Merge branch 'dev'
This commit is contained in:
commit
c23927c4fa
|
@ -7,7 +7,7 @@ project(breakhack C)
|
|||
set(breakhack_GAME_TITLE "BreakHack")
|
||||
set(breakhack_MAJOR_VERSION 0)
|
||||
set(breakhack_MINOR_VERSION 2)
|
||||
set(breakhack_PATCH_VERSION 1)
|
||||
set(breakhack_PATCH_VERSION 0)
|
||||
set(breakhack_RELEASE_TYPE "(beta)")
|
||||
|
||||
include(FindLua)
|
||||
|
@ -100,6 +100,7 @@ include_directories(
|
|||
${SDL2_IMAGE_INCLUDE_DIR}
|
||||
${SDL2_TTF_INCLUDE_DIR}
|
||||
${SDL2_MIXER_INCLUDE_DIR}
|
||||
sqlite3
|
||||
)
|
||||
|
||||
if (CMOCKA_FOUND)
|
||||
|
@ -167,7 +168,7 @@ add_executable(breakhack
|
|||
src/projectile
|
||||
src/vector2d
|
||||
src/map_room_modifiers
|
||||
src/sqlite3
|
||||
sqlite3/sqlite3
|
||||
src/db
|
||||
src/settings
|
||||
src/actiontextbuilder
|
||||
|
@ -177,10 +178,12 @@ add_executable(breakhack
|
|||
src/screen
|
||||
src/hiscore
|
||||
src/object
|
||||
src/gui_util
|
||||
src/tooltip
|
||||
)
|
||||
|
||||
# Sqlite has some warnings that I we don't need to see
|
||||
set_source_files_properties(src/sqlite3.c COMPILE_FLAGS -w)
|
||||
set_source_files_properties(sqlite3/sqlite3.c COMPILE_FLAGS -w)
|
||||
|
||||
target_link_libraries(breakhack
|
||||
${CMAKE_DL_LIBS} # Sqlite needs DL libs
|
||||
|
@ -241,7 +244,7 @@ ENDIF ()
|
|||
# LINT:
|
||||
if (CPPCHECK_FOUND)
|
||||
add_custom_target(lint
|
||||
COMMAND ${CPPCHECK_EXECUTABLE} --force --language=c --template=gcc --error-exitcode=1 --quiet --enable=warning,style,performance,portability,information,missingInclude --suppress=*:src/sqlite3.? -isrc/sqlite3.c src/
|
||||
COMMAND ${CPPCHECK_EXECUTABLE} --force --language=c --template=gcc --error-exitcode=1 --quiet --enable=warning,style,performance,portability,information,missingInclude src/
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Run cppcheck"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
f5a88fc Introduces texture blending
|
||||
52913af Completes #42 Add boss 2 & 3
|
||||
449cc36 Fixes some minor buggs
|
||||
f67aab0 Completes #43 Add win state
|
||||
8c261fd Added the undead monsters for level > 10
|
||||
6326a64 Begins #42 Add boss 2 & 3
|
||||
f1b0045 Introduces the "orc levels"
|
||||
ffe1736 Minor buggfixes and typos
|
||||
8bf9329 Version bump and badges
|
||||
8c25693 Moves sqlite3 files to separate dir
|
||||
bec9eb4 Fixed a typo in skill tooltip
|
||||
43f021a Created an FPS counter for debug mode
|
||||
dbc36aa Fixes #41, Minimap
|
||||
c390c02 Fixes #40, Prevent adjecant traps before lvl 4
|
||||
9ef97c0 Fixes #38, Artifact inventory
|
||||
358c0c7 Fixes #37 and #39 Adds tooltips to everything
|
||||
5f754d5 Merge branch 'master' into dev
|
||||
30058ea Creates gui_util and moves some code out from gui.c
|
||||
854f2c0 Prevent levels > 10 from crashing the game.
|
||||
549f47a Minor code fixes and a slight tweak to the blue color
|
|
@ -45,7 +45,9 @@ local behaviour = {
|
|||
guerilla = 3,
|
||||
coward = 4,
|
||||
sentinel = 5,
|
||||
fire_demon = 6
|
||||
fire_demon = 6,
|
||||
sorcerer = 7,
|
||||
assassin = 8
|
||||
}
|
||||
|
||||
local stats = {
|
||||
|
@ -84,19 +86,26 @@ local stats = {
|
|||
def = 0,
|
||||
speed = 1
|
||||
},
|
||||
orc = {
|
||||
hp = 20,
|
||||
dmg = 2,
|
||||
atk = 0,
|
||||
def = 0,
|
||||
speed = 1
|
||||
},
|
||||
boss = {
|
||||
hp = 60,
|
||||
dmg = 4,
|
||||
dmg = 3,
|
||||
atk = 1,
|
||||
def = 0,
|
||||
speed = 1
|
||||
},
|
||||
platino = {
|
||||
hp = 60,
|
||||
dmg = 60,
|
||||
atk = 60,
|
||||
def = 60,
|
||||
speed = 3
|
||||
hp = 90,
|
||||
dmg = 1,
|
||||
atk = 0,
|
||||
def = 0,
|
||||
speed = 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,6 +143,16 @@ for i=1,#pests do
|
|||
pests[i] = concat({ texturePaths.pest0, texturePaths.pest1 }, pests[i])
|
||||
end
|
||||
|
||||
local avian = {
|
||||
{ stats.default, 0, 11*16, "A Small Brown Bat", behaviour.pacifist },
|
||||
{ stats.default, 16, 11*16, "A Big Brown Bat", behaviour.normal },
|
||||
{ stats.default, 32, 11*16, "A Vampire Bat", behaviour.guerilla },
|
||||
{ stats.default, 48, 11*16, "A Rabid Bat", behaviour.hostile },
|
||||
}
|
||||
for i=1,#avian do
|
||||
avian[i] = concat({ texturePaths.avian0, texturePaths.avian1 }, avian[i])
|
||||
end
|
||||
|
||||
local misc = {
|
||||
{ stats.misc, 0, 0, "A Giant Black Rat", behaviour.sentinel },
|
||||
{ stats.misc, 16, 0, "A Giant White Rat", behaviour.sentinel },
|
||||
|
@ -143,13 +162,33 @@ for i=1,#misc do
|
|||
misc[i] = concat({ texturePaths.misc0, texturePaths.misc1 }, misc[i])
|
||||
end
|
||||
|
||||
local undead = {
|
||||
-- UNDEAD
|
||||
local reanimated = {
|
||||
{ stats.undead, 0, 32, "A Skeleton", behaviour.normal },
|
||||
{ stats.undead, 48, 32, "A Black Skeleton", behaviour.normal },
|
||||
{ stats.undead, 64, 32, "A Zombie", behaviour.normal },
|
||||
{ stats.undead, 80, 32, "A Zombie", behaviour.normal }
|
||||
}
|
||||
for i=1,#reanimated do
|
||||
reanimated[i] = concat({ texturePaths.undead0, texturePaths.undead1 }, reanimated[i])
|
||||
end
|
||||
|
||||
local undead = {
|
||||
{ stats.undead, 5*16, 16, "A Mummy", behaviour.normal },
|
||||
{ stats.undead, 6*16, 16, "A Two Headed Mummy", behaviour.sentinel },
|
||||
{ stats.undead, 0*16, 32, "A Skeleton", behaviour.normal },
|
||||
{ stats.misc, 1*16, 32, "A Burning Skeleton", behaviour.fire_demon },
|
||||
{ stats.misc, 2*16, 32, "An Eldritch Skeleton", behaviour.sorcerer },
|
||||
{ stats.misc, 3*16, 32, "A Black Skeleton", behaviour.guerilla },
|
||||
{ stats.misc, 4*16, 32, "A Zombie", behaviour.coward },
|
||||
{ stats.misc, 5*16, 32, "A Pale Zombie", behaviour.coward },
|
||||
{ stats.misc, 7*16, 32, "A Scorched Zombie", behaviour.fire_demon },
|
||||
{ stats.undead, 0*16, 4*16, "A Whight", behaviour.coward },
|
||||
{ stats.undead, 1*16, 4*16, "A Ghast", behaviour.sentinel },
|
||||
{ stats.misc, 1*16, 4*16, "A Ghost", behaviour.guerilla },
|
||||
{ stats.misc, 0*16, 5*16, "A Spectre", behaviour.sentinel },
|
||||
{ stats.undead, 1*16, 5*16, "An Eldritch Spectre", behaviour.sorcerer },
|
||||
{ stats.undead, 2*16, 5*16, "A Scorched Spectre", behaviour.fire_demon },
|
||||
}
|
||||
for i=1,#undead do
|
||||
undead[i] = concat({ texturePaths.undead0, texturePaths.undead1 }, undead[i])
|
||||
end
|
||||
|
@ -188,10 +227,36 @@ for i=1,#demon do
|
|||
demon[i] = concat({ texturePaths.demon0, texturePaths.demon1 }, demon[i])
|
||||
end
|
||||
|
||||
local orcs = {
|
||||
{ stats.orc, 0, 4*16, "An Orc Guard", behaviour.normal },
|
||||
{ stats.orc, 16, 4*16, "An Orc Seargeant", behaviour.coward },
|
||||
{ stats.orc, 32, 4*16, "An Orc Militia", behaviour.hostile },
|
||||
{ stats.orc, 48, 4*16, "An Orc Sentry", behaviour.sentinel },
|
||||
{ stats.orc, 64, 4*16, "An Orc Brute", behaviour.guerilla },
|
||||
{ stats.orc, 80, 4*16, "An Orc Captain", behaviour.hostile },
|
||||
{ stats.orc, 96, 4*16, "An Orc Pyro", behaviour.fire_demon },
|
||||
}
|
||||
for i=1,#orcs do
|
||||
orcs[i] = concat({ texturePaths.humanoid0, texturePaths.humanoid1 }, orcs[i])
|
||||
end
|
||||
|
||||
local assassins = {
|
||||
{ stats.misc, 1*16, 6*16, "A Reaper", behaviour.assassin },
|
||||
{ stats.misc, 0*16, 7*16, "An Assassin", behaviour.assassin },
|
||||
{ stats.misc, 1*16, 7*16, "A Royal Assassin", behaviour.assassin },
|
||||
}
|
||||
for i=1,#assassins do
|
||||
assassins[i] = concat({ texturePaths.undead0, texturePaths.undead1 }, assassins[i])
|
||||
end
|
||||
|
||||
local bosses = {
|
||||
{ stats.boss, 16, 5*16, "The Hell Hound", behaviour.fire_demon, true }
|
||||
{ stats.boss, 16, 5*16, "The Hell Hound", behaviour.fire_demon, true },
|
||||
{ stats.boss, 16, 23*16, "The Cleric", behaviour.sorcerer, true },
|
||||
{ stats.boss, 16, 8*16, "The Shadow", behaviour.assassin, true },
|
||||
}
|
||||
bosses[1] = concat({ texturePaths.dog0, texturePaths.dog1 }, bosses[1])
|
||||
bosses[2] = concat({ texturePaths.humanoid0, texturePaths.humanoid1 }, bosses[2])
|
||||
bosses[3] = concat({ texturePaths.undead0, texturePaths.undead1 }, bosses[3])
|
||||
|
||||
local platino = {
|
||||
{
|
||||
|
@ -201,7 +266,8 @@ local platino = {
|
|||
48,
|
||||
12*16,
|
||||
"Platino",
|
||||
behaviour.sentinel
|
||||
behaviour.sentinel,
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,29 +290,24 @@ if(CURRENT_LEVEL > 0) then
|
|||
if (CURRENT_LEVEL == 1) then
|
||||
enemies = concat(enemies, pests)
|
||||
enemies = concat(enemies, misc)
|
||||
enemies = concat(enemies, dogs)
|
||||
elseif (CURRENT_LEVEL > 15) then
|
||||
enemies = {}
|
||||
enemies = concat(enemies, undead)
|
||||
enemies = concat(enemies, orcs)
|
||||
enemies = concat(enemies, assassins)
|
||||
elseif (CURRENT_LEVEL > 10) then
|
||||
enemies = {}
|
||||
enemies = concat(enemies, undead)
|
||||
enemies = concat(enemies, avian)
|
||||
elseif (CURRENT_LEVEL > 5) then
|
||||
enemies = {}
|
||||
enemies = concat(enemies, demon)
|
||||
enemies = concat(enemies, undead)
|
||||
enemies = concat(enemies, reptile)
|
||||
enemies = concat(enemies, misc)
|
||||
elseif (CURRENT_LEVEL > 3) then
|
||||
enemies = {}
|
||||
enemies = concat(enemies, undead)
|
||||
enemies = concat(enemies, reptile)
|
||||
enemies = concat(enemies, misc)
|
||||
enemies = concat(enemies, dogs)
|
||||
elseif (CURRENT_LEVEL > 2) then
|
||||
enemies = {}
|
||||
enemies = concat(enemies, undead)
|
||||
enemies = concat(enemies, reptile)
|
||||
enemies = concat(enemies, misc)
|
||||
enemies = concat(enemies, dogs)
|
||||
enemies = concat(enemies, orcs)
|
||||
enemies = concat(enemies, avian)
|
||||
elseif (CURRENT_LEVEL > 1) then
|
||||
enemies = {}
|
||||
enemies = concat(enemies, undead)
|
||||
enemies = concat(enemies, reanimated)
|
||||
enemies = concat(enemies, reptile)
|
||||
enemies = concat(enemies, avian)
|
||||
enemies = concat(enemies, misc)
|
||||
enemies = concat(enemies, dogs)
|
||||
end
|
||||
|
@ -279,7 +340,7 @@ function module.add_monsters_to_room(room, roomx, roomy)
|
|||
end
|
||||
|
||||
function module.add_boss_to_room(room, roomx, roomy)
|
||||
local boss = bosses[1]
|
||||
local boss = bosses[CURRENT_LEVEL / 5]
|
||||
local success = false
|
||||
while not success do
|
||||
local rx = random(13) + 1
|
||||
|
@ -309,3 +370,4 @@ function module.load_monsters(map, monsters)
|
|||
end
|
||||
|
||||
return module
|
||||
|
||||
|
|
|
@ -35,9 +35,25 @@ function module.add_traps_to_room(room)
|
|||
while i < count do
|
||||
local rx = random(13) + 1
|
||||
local ry = random(9) + 1
|
||||
if room_builder.is_tile_avilable(room, rx, ry) then
|
||||
room.traps[rx][ry] = traps[random(#traps)]
|
||||
i = i + 1
|
||||
if CURRENT_LEVEL < 4 then
|
||||
if room_builder.is_tile_avilable(room, rx, ry)
|
||||
and not room.traps[rx+1][ry]
|
||||
and not room.traps[rx-1][ry]
|
||||
and not room.traps[rx][ry+1]
|
||||
and not room.traps[rx][ry-1]
|
||||
and not room.traps[rx+1][ry+1]
|
||||
and not room.traps[rx+1][ry-1]
|
||||
and not room.traps[rx-1][ry+1]
|
||||
and not room.traps[rx-1][ry-1]
|
||||
then
|
||||
room.traps[rx][ry] = traps[random(#traps)]
|
||||
i = i + 1
|
||||
end
|
||||
else
|
||||
if room_builder.is_tile_avilable(room, rx, ry) then
|
||||
room.traps[rx][ry] = traps[random(#traps)]
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -45,6 +45,9 @@ typedef struct Artifact {
|
|||
int level;
|
||||
} Artifact;
|
||||
|
||||
Sprite *
|
||||
artifact_sprite_for(MagicalEffect);
|
||||
|
||||
Artifact *
|
||||
artifact_create_random(Player*, Uint8 level);
|
||||
|
||||
|
|
|
@ -33,20 +33,21 @@
|
|||
#define SPRITE_DIMENSION 16
|
||||
|
||||
/* Display stuff */
|
||||
#define GAME_VIEW_WIDTH (MAP_ROOM_WIDTH * TILE_DIMENSION)
|
||||
#define GAME_VIEW_HEIGHT (MAP_ROOM_HEIGHT * TILE_DIMENSION)
|
||||
#define GAME_VIEW_WIDTH (MAP_ROOM_WIDTH * TILE_DIMENSION) // 16 * 32
|
||||
#define GAME_VIEW_HEIGHT (MAP_ROOM_HEIGHT * TILE_DIMENSION) // 12 * 32
|
||||
|
||||
#define SKILL_BAR_WIDTH GAME_VIEW_WIDTH
|
||||
#define SKILL_BAR_HEIGHT 32
|
||||
|
||||
#define RIGHT_GUI_WIDTH (10 * SPRITE_DIMENSION)
|
||||
#define RIGHT_GUI_HEIGHT (GAME_VIEW_HEIGHT + SKILL_BAR_HEIGHT)
|
||||
#define RIGHT_GUI_WIDTH (10 * SPRITE_DIMENSION) // 10 * 16
|
||||
#define MINIMAP_GUI_HEIGHT 128
|
||||
#define STATS_GUI_HEIGHT (GAME_VIEW_HEIGHT + SKILL_BAR_HEIGHT - MINIMAP_GUI_HEIGHT)
|
||||
|
||||
#define BOTTOM_GUI_HEIGHT (10 * SPRITE_DIMENSION)
|
||||
#define BOTTOM_GUI_WIDTH (GAME_VIEW_WIDTH + RIGHT_GUI_WIDTH)
|
||||
|
||||
#define SCREEN_WIDTH (GAME_VIEW_WIDTH + RIGHT_GUI_WIDTH)
|
||||
#define SCREEN_HEIGHT (RIGHT_GUI_HEIGHT + BOTTOM_GUI_HEIGHT)
|
||||
#define SCREEN_HEIGHT (GAME_VIEW_HEIGHT + SKILL_BAR_HEIGHT + BOTTOM_GUI_HEIGHT)
|
||||
|
||||
/* Quality of life stuff */
|
||||
#define DEFAULT_DIMENSION (Dimension) { 16, 16 }
|
||||
|
@ -65,7 +66,7 @@
|
|||
#define C_WHITE (SDL_Color) { 255, 255, 255, 255 }
|
||||
#define C_RED (SDL_Color) { 255, 0, 0, 255 }
|
||||
#define C_GREEN (SDL_Color) { 0, 255, 0, 255 }
|
||||
#define C_BLUE (SDL_Color) { 0, 0, 255, 255 }
|
||||
#define C_BLUE (SDL_Color) { 60, 134, 252, 255 }
|
||||
#define C_YELLOW (SDL_Color) { 255, 255, 0, 255 }
|
||||
#define C_BLACK (SDL_Color) { 0, 0, 0, 255 }
|
||||
#define C_PURPLE (SDL_Color) { 137, 16, 229, 255 }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -26,6 +26,7 @@ typedef enum GameState_t {
|
|||
PLAYING,
|
||||
IN_GAME_MENU,
|
||||
GAME_OVER,
|
||||
COMPLETED,
|
||||
QUIT
|
||||
} GameState;
|
||||
|
||||
|
|
158
src/gui.c
158
src/gui.c
|
@ -26,6 +26,8 @@
|
|||
#include "util.h"
|
||||
#include "map.h"
|
||||
#include "texturecache.h"
|
||||
#include "gui_util.h"
|
||||
#include "tooltip.h"
|
||||
|
||||
#define DEFAULT_LOG { NULL, LOG_LINES_COUNT, 0, 200 }
|
||||
#define DEFAULT_EVENT_MESSAGES { NULL, 5, 0, 200 }
|
||||
|
@ -33,16 +35,6 @@
|
|||
#define POS_Y_COLLECTABLES 64
|
||||
#define POS_Y_XPBAR 128
|
||||
|
||||
static SDL_Rect frame_top_left = { 16, 160, 16, 16 };
|
||||
static SDL_Rect frame_top_right = { 48, 160, 16, 16 };
|
||||
static SDL_Rect frame_bottom_left = { 16, 192, 16, 16 };
|
||||
static SDL_Rect frame_bottom_right = { 48, 192, 16, 16 };
|
||||
static SDL_Rect frame_top = { 32, 160, 16, 16 };
|
||||
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 };
|
||||
|
||||
static struct LogData_t {
|
||||
char **log;
|
||||
unsigned int len;
|
||||
|
@ -50,16 +42,13 @@ static struct LogData_t {
|
|||
unsigned int strlen;
|
||||
} log_data = DEFAULT_LOG;
|
||||
|
||||
static struct GuiEventMsgData_t {
|
||||
static struct GuiEventMsgs {
|
||||
char **messages;
|
||||
unsigned int len;
|
||||
unsigned int count;
|
||||
unsigned int strlen;
|
||||
} event_messages = DEFAULT_EVENT_MESSAGES;
|
||||
|
||||
static Sprite*
|
||||
gui_create_frame(unsigned int width, unsigned int height, Camera *cam);
|
||||
|
||||
static void
|
||||
gui_malloc_log(void)
|
||||
{
|
||||
|
@ -174,12 +163,16 @@ init_sprites(Gui *gui, Camera *cam)
|
|||
s->pos = (Position) { 16, POS_Y_COLLECTABLES + 32 };
|
||||
linkedlist_append(&gui->sprites, s);
|
||||
|
||||
gui->rightFrame = gui_create_frame(RIGHT_GUI_WIDTH/16,
|
||||
RIGHT_GUI_HEIGHT/16,
|
||||
cam);
|
||||
gui->bottomFrame = gui_create_frame(BOTTOM_GUI_WIDTH/16,
|
||||
BOTTOM_GUI_HEIGHT/16,
|
||||
cam);
|
||||
gui->statsFrame = gui_util_create_frame_sprite(RIGHT_GUI_WIDTH/16,
|
||||
STATS_GUI_HEIGHT/16,
|
||||
cam);
|
||||
gui->bottomFrame = gui_util_create_frame_sprite(BOTTOM_GUI_WIDTH/16,
|
||||
BOTTOM_GUI_HEIGHT/16,
|
||||
cam);
|
||||
|
||||
gui->miniMapFrame = gui_util_create_frame_sprite(RIGHT_GUI_WIDTH/16,
|
||||
MINIMAP_GUI_HEIGHT/16,
|
||||
cam);
|
||||
}
|
||||
|
||||
Gui*
|
||||
|
@ -192,6 +185,7 @@ gui_create(Camera *cam)
|
|||
gui->sprites = linkedlist_create();
|
||||
gui->health = linkedlist_create();
|
||||
gui->xp_bar = linkedlist_create();
|
||||
gui->activeTooltip = NULL;
|
||||
|
||||
for (i = 0; i < LOG_LINES_COUNT; ++i) {
|
||||
t = texture_create();
|
||||
|
@ -400,91 +394,10 @@ gui_update_player_stats(Gui *gui, Player *player, Map *map, SDL_Renderer *render
|
|||
}
|
||||
}
|
||||
|
||||
static Sprite*
|
||||
gui_create_frame(unsigned int width, unsigned int height, Camera *cam)
|
||||
{
|
||||
Sprite *frame = sprite_create();
|
||||
Texture *texture = texture_create();
|
||||
texture->dim = (Dimension) {
|
||||
width * 16,
|
||||
height * 16
|
||||
};
|
||||
frame->textures[0] = texture;
|
||||
frame->destroyTextures = true;
|
||||
frame->pos = (Position) { 0, 0 };
|
||||
frame->dim = (Dimension) { width*16, height*16 };
|
||||
frame->fixed = true;
|
||||
texture_create_blank(texture,
|
||||
SDL_TEXTUREACCESS_TARGET,
|
||||
cam->renderer);
|
||||
Texture *source = texturecache_get("GUI/GUI0.png");
|
||||
|
||||
SDL_SetRenderTarget(cam->renderer, texture->texture);
|
||||
SDL_RenderClear(cam->renderer);
|
||||
|
||||
SDL_Rect box = { 0, 0, 16, 16 };
|
||||
unsigned int i, j;
|
||||
for (i = 0; i < width; ++i) {
|
||||
for (j = 0; j < height; ++j) {
|
||||
box.x = i * 16;
|
||||
box.y = j * 16;
|
||||
|
||||
if (i == 0 && j == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_top_left,
|
||||
cam);
|
||||
} else if (i == (width - 1) && j == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_top_right,
|
||||
cam);
|
||||
} else if (i == 0 && j == (height - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_bottom_left,
|
||||
cam);
|
||||
} else if (i == (width - 1) && j == (height - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_bottom_right,
|
||||
cam);
|
||||
} else if (i == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_left,
|
||||
cam);
|
||||
} else if (i == (width - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_right,
|
||||
cam);
|
||||
} else if (j == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_top,
|
||||
cam);
|
||||
} else if (j == (height - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_bottom,
|
||||
cam);
|
||||
} else {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_center,
|
||||
cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_SetRenderTarget(cam->renderer, NULL);
|
||||
return frame;
|
||||
}
|
||||
|
||||
void
|
||||
gui_render_panel(Gui *gui, Camera *cam)
|
||||
{
|
||||
sprite_render(gui->rightFrame, cam);
|
||||
sprite_render(gui->statsFrame, cam);
|
||||
LinkedList *item = gui->health;
|
||||
while (item != NULL) {
|
||||
Sprite *s = item->data;
|
||||
|
@ -508,6 +421,30 @@ gui_render_panel(Gui *gui, Camera *cam)
|
|||
sprite_render(gui->labels[i], cam);
|
||||
}
|
||||
|
||||
void
|
||||
gui_render_minimap(Gui *gui, Map *map, Camera *cam)
|
||||
{
|
||||
sprite_render(gui->miniMapFrame, cam);
|
||||
|
||||
SDL_Rect box = { 0, 0, 12, 8 };
|
||||
for (Uint8 i = 0; i < MAP_H_ROOM_COUNT; ++i) {
|
||||
for (Uint8 j = 0; j < MAP_V_ROOM_COUNT; ++j) {
|
||||
Room *room = map->rooms[i][j];
|
||||
box.x = i*14 + 10;
|
||||
box.y = j*10 + 14;
|
||||
if (room && room->visited) {
|
||||
if (map->currentRoom.x == i && map->currentRoom.y == j)
|
||||
SDL_SetRenderDrawColor(cam->renderer, 0, 255, 255, 255);
|
||||
else
|
||||
SDL_SetRenderDrawColor(cam->renderer, 255, 255, 255, 255);
|
||||
SDL_RenderFillRect(cam->renderer, &box);
|
||||
SDL_SetRenderDrawColor(cam->renderer, 60, 134, 252, 255);
|
||||
SDL_RenderDrawRect(cam->renderer, &box);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gui_log(const char *fmt, ...)
|
||||
{
|
||||
|
@ -557,6 +494,14 @@ gui_event_message(const char *fmt, ...)
|
|||
event_messages.count++;
|
||||
}
|
||||
|
||||
void
|
||||
gui_render_tooltip(Gui *gui, Camera *cam)
|
||||
{
|
||||
if (gui->activeTooltip) {
|
||||
sprite_render(gui->activeTooltip, cam);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gui_render_log(Gui *gui, Camera *cam)
|
||||
{
|
||||
|
@ -613,8 +558,9 @@ gui_render_event_message(Gui *gui, Camera *cam)
|
|||
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]);
|
||||
}
|
||||
event_messages.count = 0;
|
||||
|
||||
for (size_t i = 0; i < log_data.count; ++i)
|
||||
|
@ -642,8 +588,9 @@ destroy_event_messages(void)
|
|||
if (event_messages.messages == NULL)
|
||||
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);
|
||||
event_messages.messages = NULL;
|
||||
|
@ -659,7 +606,8 @@ gui_destroy(Gui *gui)
|
|||
texture_destroy(gui->event_message);
|
||||
|
||||
sprite_destroy(gui->bottomFrame);
|
||||
sprite_destroy(gui->rightFrame);
|
||||
sprite_destroy(gui->statsFrame);
|
||||
sprite_destroy(gui->miniMapFrame);
|
||||
|
||||
while (gui->sprites != NULL)
|
||||
sprite_destroy(linkedlist_pop(&gui->sprites));
|
||||
|
|
12
src/gui.h
12
src/gui.h
|
@ -42,13 +42,15 @@ typedef enum Label_e {
|
|||
LABEL_COUNT
|
||||
} LabelIndex;
|
||||
|
||||
typedef struct {
|
||||
typedef struct Gui {
|
||||
LinkedList *sprites;
|
||||
LinkedList *health;
|
||||
LinkedList *xp_bar;
|
||||
Sprite *bottomFrame;
|
||||
Sprite *rightFrame;
|
||||
Sprite *statsFrame;
|
||||
Sprite *miniMapFrame;
|
||||
Sprite *labels[LABEL_COUNT];
|
||||
Sprite *activeTooltip;
|
||||
Texture *log_lines[LOG_LINES_COUNT];
|
||||
Texture *event_message;
|
||||
Timer *event_message_timer;
|
||||
|
@ -63,12 +65,18 @@ gui_update_player_stats(Gui*, Player*, Map*, SDL_Renderer*);
|
|||
void
|
||||
gui_render_panel(Gui*, Camera*);
|
||||
|
||||
void
|
||||
gui_render_minimap(Gui*, Map*, Camera*);
|
||||
|
||||
void
|
||||
gui_render_log(Gui*, Camera*);
|
||||
|
||||
void
|
||||
gui_render_event_message(Gui*, Camera*);
|
||||
|
||||
void
|
||||
gui_render_tooltip(Gui*, Camera*);
|
||||
|
||||
void
|
||||
gui_log(const char *fmt, ...);
|
||||
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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 "texturecache.h"
|
||||
#include "gui_util.h"
|
||||
|
||||
static Sprite *
|
||||
render_frame_on_texture(Uint32 width,
|
||||
Uint32 height,
|
||||
Position offset,
|
||||
Camera *cam)
|
||||
{
|
||||
Sprite *frame = sprite_create();
|
||||
Texture *texture = texture_create();
|
||||
texture->dim = (Dimension) {
|
||||
width * 16,
|
||||
height * 16
|
||||
};
|
||||
frame->textures[0] = texture;
|
||||
frame->destroyTextures = true;
|
||||
frame->pos = (Position) { 0, 0 };
|
||||
frame->dim = (Dimension) { width*16, height*16 };
|
||||
frame->fixed = true;
|
||||
texture_create_blank(texture,
|
||||
SDL_TEXTUREACCESS_TARGET,
|
||||
cam->renderer);
|
||||
|
||||
SDL_SetRenderTarget(cam->renderer, texture->texture);
|
||||
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 };
|
||||
unsigned int i, j;
|
||||
for (i = 0; i < width; ++i) {
|
||||
for (j = 0; j < height; ++j) {
|
||||
box.x = i * 16;
|
||||
box.y = j * 16;
|
||||
|
||||
if (i == 0 && j == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_top_left,
|
||||
cam);
|
||||
} else if (i == (width - 1) && j == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_top_right,
|
||||
cam);
|
||||
} else if (i == 0 && j == (height - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_bottom_left,
|
||||
cam);
|
||||
} else if (i == (width - 1) && j == (height - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_bottom_right,
|
||||
cam);
|
||||
} else if (i == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_left,
|
||||
cam);
|
||||
} else if (i == (width - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_right,
|
||||
cam);
|
||||
} else if (j == 0) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_top,
|
||||
cam);
|
||||
} else if (j == (height - 1)) {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_bottom,
|
||||
cam);
|
||||
} else {
|
||||
texture_render_clip(source,
|
||||
&box,
|
||||
&frame_center,
|
||||
cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetRenderTarget(cam->renderer, NULL);
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 "sprite.h"
|
||||
#include "camera.h"
|
||||
|
||||
Sprite *
|
||||
gui_util_create_frame_sprite(Uint32 width,
|
||||
Uint32 height,
|
||||
Camera*);
|
||||
|
||||
Sprite *
|
||||
gui_util_create_tooltip_frame_sprite(Uint32 width,
|
||||
Uint32 height,
|
||||
Camera*);
|
15
src/input.c
15
src/input.c
|
@ -107,6 +107,21 @@ get_event_modkey(SDL_Event *event)
|
|||
key = KEY_CTRL_S; break;
|
||||
case SDLK_m:
|
||||
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:
|
||||
key = 0; break;
|
||||
}
|
||||
|
|
10
src/input.h
10
src/input.h
|
@ -39,8 +39,14 @@
|
|||
#define KEY_ESC 16384
|
||||
#define KEY_ENTER 32768
|
||||
|
||||
#define KEY_CTRL_M 1
|
||||
#define KEY_CTRL_S 2
|
||||
#define KEY_CTRL_M 0x1
|
||||
#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_MIDDLE 2
|
||||
|
|
415
src/main.c
415
src/main.c
|
@ -52,38 +52,116 @@
|
|||
#include "screen.h"
|
||||
#include "hiscore.h"
|
||||
#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!",
|
||||
"",
|
||||
" You have aquired a new level and a new skill!",
|
||||
"",
|
||||
" Skills are listed in the bar below the game screen.",
|
||||
"",
|
||||
"",
|
||||
" SKILL INFO: SHIFT + <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 {
|
||||
PLAYER,
|
||||
MONSTER
|
||||
} Turn;
|
||||
|
||||
static SDL_Window *gWindow = NULL;
|
||||
static SDL_Renderer *gRenderer = NULL;
|
||||
static Player *gPlayer = NULL;
|
||||
static Map *gMap = NULL;
|
||||
static RoomMatrix *gRoomMatrix = NULL;
|
||||
static Gui *gGui = NULL;
|
||||
static SkillBar *gSkillBar = NULL;
|
||||
static Pointer *gPointer = NULL;
|
||||
static Menu *mainMenu = NULL;
|
||||
static Menu *inGameMenu = NULL;
|
||||
static Timer *menuTimer = NULL;
|
||||
static Camera *gCamera = NULL;
|
||||
static Screen *creditsScreen = NULL;
|
||||
static Screen *scoreScreen = NULL;
|
||||
static unsigned int cLevel = 1;
|
||||
static float deltaTime = 1.0;
|
||||
static double renderScale = 1.0;
|
||||
static SDL_Window *gWindow = NULL;
|
||||
static SDL_Renderer *gRenderer = NULL;
|
||||
static Player *gPlayer = NULL;
|
||||
static Map *gMap = NULL;
|
||||
static RoomMatrix *gRoomMatrix = NULL;
|
||||
static Gui *gGui = NULL;
|
||||
static SkillBar *gSkillBar = NULL;
|
||||
static Menu *mainMenu = NULL;
|
||||
static Menu *inGameMenu = NULL;
|
||||
static Timer *menuTimer = NULL;
|
||||
static Camera *gCamera = NULL;
|
||||
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;
|
||||
static Turn currentTurn = PLAYER;
|
||||
static GameState gGameState;
|
||||
static SDL_Rect gameViewport;
|
||||
static SDL_Rect skillBarViewport;
|
||||
static SDL_Rect bottomGuiViewport;
|
||||
static SDL_Rect rightGuiViewport;
|
||||
static SDL_Rect statsGuiViewport;
|
||||
static SDL_Rect minimapViewport;
|
||||
static SDL_Rect menuViewport;
|
||||
static Turn currentTurn = PLAYER;
|
||||
static Input input;
|
||||
|
||||
#ifdef DEBUG
|
||||
static Sprite *fpsSprite = NULL;
|
||||
static Pointer *gPointer = NULL;
|
||||
#endif // DEBUG
|
||||
|
||||
static SDL_Color C_MENU_DEFAULT = { 255, 255, 0, 255 };
|
||||
static SDL_Color C_MENU_OUTLINE_DEFAULT = { 0, 0, 0, 255 };
|
||||
static SDL_Color C_MENU_HOVER = { 255, 0, 0, 255 };
|
||||
|
@ -180,8 +258,11 @@ initViewports(void)
|
|||
bottomGuiViewport = (SDL_Rect) { 0, GAME_VIEW_HEIGHT + SKILL_BAR_HEIGHT,
|
||||
BOTTOM_GUI_WIDTH, BOTTOM_GUI_WIDTH };
|
||||
|
||||
rightGuiViewport = (SDL_Rect) { GAME_VIEW_WIDTH, 0,
|
||||
RIGHT_GUI_WIDTH, RIGHT_GUI_HEIGHT };
|
||||
statsGuiViewport = (SDL_Rect) { GAME_VIEW_WIDTH, 0,
|
||||
RIGHT_GUI_WIDTH, STATS_GUI_HEIGHT };
|
||||
|
||||
minimapViewport = (SDL_Rect) { GAME_VIEW_WIDTH, STATS_GUI_HEIGHT,
|
||||
RIGHT_GUI_WIDTH, MINIMAP_GUI_HEIGHT };
|
||||
|
||||
menuViewport = (SDL_Rect) {
|
||||
(SCREEN_WIDTH - GAME_VIEW_WIDTH)/2,
|
||||
|
@ -200,13 +281,22 @@ 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);
|
||||
#ifdef DEBUG
|
||||
gPointer = pointer_create(gRenderer);
|
||||
#endif // DEBUG
|
||||
particle_engine_init();
|
||||
menuTimer = timer_create();
|
||||
actiontextbuilder_init(gRenderer);
|
||||
|
||||
#ifdef DEBUG
|
||||
fpsSprite = sprite_create();
|
||||
sprite_load_text_texture(fpsSprite, "GUI/SDS_8x8.ttf", 0, 14, 1);
|
||||
fpsSprite->pos = POS(16, 16);
|
||||
fpsSprite->fixed = true;
|
||||
#endif // DEBUG
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -218,20 +308,18 @@ startGame(void *unused)
|
|||
gGameState = PLAYING;
|
||||
if (gPlayer)
|
||||
player_destroy(gPlayer);
|
||||
gPlayer = player_create(WARRIOR, gRenderer);
|
||||
gPlayer = player_create(WARRIOR, gCamera);
|
||||
mixer_play_music(GAME_MUSIC0 + get_random(2));
|
||||
#ifdef DEBUG
|
||||
// This block is for testing
|
||||
cLevel = 1;
|
||||
if (cLevel % 5 == 0)
|
||||
mixer_play_music(BOSS_MUSIC0);
|
||||
for (size_t i = 1; i < cLevel; ++i)
|
||||
player_levelup(gPlayer);
|
||||
#endif // DEBUG
|
||||
resetGame();
|
||||
skillbar_reset(gSkillBar);
|
||||
gui_clear_message_log();
|
||||
gui_log("The Dungeon Crawl begins!");
|
||||
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
|
||||
|
@ -245,10 +333,14 @@ static void
|
|||
toggleInGameMenu(void *unused)
|
||||
{
|
||||
UNUSED(unused);
|
||||
if (gGameState == PLAYING || gGameState == GAME_OVER)
|
||||
if (gGameState == PLAYING ||
|
||||
gGameState == GAME_OVER ||
|
||||
gGameState == COMPLETED)
|
||||
gGameState = IN_GAME_MENU;
|
||||
else if (is_player_dead())
|
||||
gGameState = GAME_OVER;
|
||||
else if (cLevel >= 20)
|
||||
gGameState = COMPLETED;
|
||||
else
|
||||
gGameState = PLAYING;
|
||||
}
|
||||
|
@ -257,6 +349,7 @@ static void
|
|||
goToMainMenu(void *unused)
|
||||
{
|
||||
UNUSED(unused);
|
||||
gui_clear_message_log();
|
||||
gGameState = MENU;
|
||||
menu_destroy(inGameMenu);
|
||||
inGameMenu = NULL;
|
||||
|
@ -299,16 +392,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
|
||||
initInGameMenu(void)
|
||||
{
|
||||
struct MENU_ITEM menu_items[] = {
|
||||
{ "RESUME", toggleInGameMenu },
|
||||
{ "HOW TO PLAY", showHowToTooltip },
|
||||
{ "MAIN MENU", goToMainMenu },
|
||||
{ "QUIT", exitGame },
|
||||
};
|
||||
|
||||
createMenu(&inGameMenu, menu_items, 3);
|
||||
createMenu(&inGameMenu, menu_items, 4);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -388,8 +490,10 @@ resetGame(void)
|
|||
screen_destroy(scoreScreen);
|
||||
scoreScreen = NULL;
|
||||
|
||||
if (!inGameMenu)
|
||||
initInGameMenu();
|
||||
if (inGameMenu)
|
||||
menu_destroy(inGameMenu);
|
||||
inGameMenu = NULL;
|
||||
initInGameMenu();
|
||||
|
||||
if (gMap)
|
||||
map_destroy(gMap);
|
||||
|
@ -420,6 +524,10 @@ init(void)
|
|||
hiscore_init();
|
||||
initMainMenu();
|
||||
|
||||
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 };
|
||||
|
||||
gGameState = MENU;
|
||||
|
@ -432,9 +540,10 @@ handle_main_input(void)
|
|||
{
|
||||
if (gGameState == PLAYING
|
||||
|| gGameState == IN_GAME_MENU
|
||||
|| gGameState == GAME_OVER)
|
||||
|| gGameState == GAME_OVER
|
||||
|| gGameState == COMPLETED)
|
||||
{
|
||||
if (input_key_is_pressed(&input, KEY_ESC))
|
||||
if (!gGui->activeTooltip && input_key_is_pressed(&input, KEY_ESC))
|
||||
toggleInGameMenu(NULL);
|
||||
}
|
||||
|
||||
|
@ -444,6 +553,8 @@ handle_main_input(void)
|
|||
gGameState = MENU;
|
||||
else if (gGameState == MENU && input_key_is_pressed(&input, KEY_ESC))
|
||||
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 (mixer_toggle_music(&gGameState))
|
||||
|
@ -458,6 +569,15 @@ handle_main_input(void)
|
|||
else
|
||||
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
|
||||
|
@ -491,15 +611,33 @@ handle_events(void)
|
|||
static bool
|
||||
is_player_dead(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
gPlayer->stats.hp = gPlayer->stats.hp > 0 ? gPlayer->stats.hp : 1;
|
||||
#endif // DEBUG
|
||||
if (gPlayer->stats.hp <= 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_next_level(void)
|
||||
{
|
||||
if (cLevel >= 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
Room *room = gMap->rooms[gMap->currentRoom.x][gMap->currentRoom.y];
|
||||
Position pos = position_to_matrix_coords(&gPlayer->sprite->pos);
|
||||
|
||||
|
@ -511,11 +649,18 @@ check_next_level(void)
|
|||
if (tile->levelExit) {
|
||||
mixer_play_effect(NEXT_LEVEL);
|
||||
++cLevel;
|
||||
if (cLevel % 5 == 0)
|
||||
if (cLevel > 19) {
|
||||
mixer_play_music(BOSS_MUSIC0);
|
||||
else
|
||||
} else if (cLevel % 5 == 0) {
|
||||
gui_log("You sense something powerful in the vicinity");
|
||||
mixer_play_music(BOSS_MUSIC0);
|
||||
} else {
|
||||
mixer_play_music(GAME_MUSIC0 + get_random(2));
|
||||
resetGame();
|
||||
}
|
||||
|
||||
if (cLevel < 20) {
|
||||
resetGame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,7 +671,9 @@ populateUpdateData(UpdateData *data, float deltatime)
|
|||
data->map = gMap;
|
||||
data->matrix = gRoomMatrix;
|
||||
data->input = &input;
|
||||
data->gui = gGui;
|
||||
data->deltatime = deltatime;
|
||||
data->cam = gCamera;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -534,17 +681,28 @@ 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);
|
||||
|
||||
populateUpdateData(&updateData, deltaTime);
|
||||
bool skillActivated = false;
|
||||
if (playerLevel != gPlayer->stats.lvl) {
|
||||
playerLevel = gPlayer->stats.lvl;
|
||||
skillbar_check_skill_activation(gSkillBar, gPlayer);
|
||||
skillActivated = skillbar_check_skill_activation(gSkillBar,
|
||||
gPlayer);
|
||||
}
|
||||
|
||||
Settings *settings = settings_get();
|
||||
if (skillActivated && settings->tooltips_enabled && playerLevel < 5) {
|
||||
gGui->activeTooltip = new_skill_tooltip;
|
||||
}
|
||||
if (!artifactTooltipShown && gPlayer->equipment.hasArtifacts && settings->tooltips_enabled) {
|
||||
artifactTooltipShown = true;
|
||||
gGui->activeTooltip = new_artifact_tooltip;
|
||||
}
|
||||
|
||||
map_clear_expired_entities(gMap, gPlayer);
|
||||
if (gGameState == PLAYING && currentTurn == PLAYER)
|
||||
player_update(&updateData);
|
||||
|
||||
|
@ -558,19 +716,85 @@ run_game_update(void)
|
|||
map_set_current_room(gMap, &gPlayer->sprite->pos);
|
||||
map_update(&updateData);
|
||||
|
||||
bool turnSwitch = false;
|
||||
if (currentTurn == PLAYER) {
|
||||
if (player_turn_over(gPlayer)) {
|
||||
currentTurn = MONSTER;
|
||||
player_reset_steps(gPlayer);
|
||||
map_on_new_turn(gMap);
|
||||
repopulate_roommatrix();
|
||||
turnSwitch = true;
|
||||
}
|
||||
} else if (currentTurn == MONSTER) {
|
||||
if (map_move_monsters(gMap, gRoomMatrix)) {
|
||||
currentTurn = PLAYER;
|
||||
repopulate_roommatrix();
|
||||
turnSwitch = true;
|
||||
}
|
||||
}
|
||||
|
||||
map_clear_expired_entities(gMap, gPlayer);
|
||||
if (turnSwitch)
|
||||
repopulate_roommatrix();
|
||||
}
|
||||
|
||||
static void
|
||||
render_gui(void)
|
||||
{
|
||||
SDL_RenderSetViewport(gRenderer, &statsGuiViewport);
|
||||
gui_render_panel(gGui, gCamera);
|
||||
SDL_RenderSetViewport(gRenderer, &minimapViewport);
|
||||
gui_render_minimap(gGui, gMap, gCamera);
|
||||
SDL_RenderSetViewport(gRenderer, &skillBarViewport);
|
||||
skillbar_render(gSkillBar, gPlayer, gCamera);
|
||||
SDL_RenderSetViewport(gRenderer, &bottomGuiViewport);
|
||||
gui_render_log(gGui, gCamera);
|
||||
SDL_RenderSetViewport(gRenderer, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
render_game_completed(void)
|
||||
{
|
||||
SDL_RenderSetViewport(gRenderer, &gameViewport);
|
||||
if (!is_player_dead()) {
|
||||
player_render(gPlayer, gCamera);
|
||||
player_render_toplayer(gPlayer, gCamera);
|
||||
}
|
||||
actiontextbuilder_render(gCamera);
|
||||
gui_render_event_message(gGui, gCamera);
|
||||
|
||||
if (gGameState == IN_GAME_MENU) {
|
||||
SDL_Rect dimmer = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
|
||||
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 150);
|
||||
SDL_RenderFillRect(gRenderer, &dimmer);
|
||||
menu_render(inGameMenu, gCamera);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
sprite_render(fpsSprite, gCamera);
|
||||
pointer_render(gPointer, gCamera);
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
static void
|
||||
render_game(void)
|
||||
{
|
||||
SDL_RenderSetViewport(gRenderer, &gameViewport);
|
||||
map_render(gMap, gCamera);
|
||||
particle_engine_render_game(gCamera);
|
||||
|
||||
map_render_mid_layer(gMap, gCamera);
|
||||
|
||||
if (!is_player_dead()) {
|
||||
player_render(gPlayer, gCamera);
|
||||
player_render_toplayer(gPlayer, gCamera);
|
||||
}
|
||||
|
||||
map_render_top_layer(gMap, gRoomMatrix, gCamera);
|
||||
|
||||
if (gPlayer->class == MAGE || gPlayer->class == PALADIN)
|
||||
roommatrix_render_mouse_square(gRoomMatrix, gCamera);
|
||||
|
||||
roommatrix_render_lightmap(gRoomMatrix, gCamera);
|
||||
actiontextbuilder_render(gCamera);
|
||||
gui_render_event_message(gGui, gCamera);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -579,36 +803,11 @@ run_game_render(void)
|
|||
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0);
|
||||
SDL_RenderClear(gRenderer);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, &gameViewport);
|
||||
map_render(gMap, gCamera);
|
||||
particle_engine_render_game(gCamera);
|
||||
map_render_mid_layer(gMap, gCamera);
|
||||
render_game();
|
||||
render_gui();
|
||||
|
||||
if (!is_player_dead()) {
|
||||
player_render(gPlayer, gCamera);
|
||||
player_render_toplayer(gPlayer, gCamera);
|
||||
}
|
||||
|
||||
map_render_top_layer(gMap, gCamera);
|
||||
|
||||
if (gPlayer->class == MAGE || gPlayer->class == PALADIN)
|
||||
roommatrix_render_mouse_square(gRoomMatrix, gCamera);
|
||||
|
||||
roommatrix_render_lightmap(gRoomMatrix, gCamera);
|
||||
actiontextbuilder_render(gCamera);
|
||||
gui_render_event_message(gGui, gCamera);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, &rightGuiViewport);
|
||||
gui_render_panel(gGui, gCamera);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, &skillBarViewport);
|
||||
skillbar_render(gSkillBar, gPlayer, gCamera);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, &bottomGuiViewport);
|
||||
gui_render_log(gGui, gCamera);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, NULL);
|
||||
particle_engine_render_global(gCamera);
|
||||
gui_render_tooltip(gGui, gCamera);
|
||||
|
||||
if (gGameState == IN_GAME_MENU) {
|
||||
SDL_Rect dimmer = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
|
||||
|
@ -616,7 +815,10 @@ run_game_render(void)
|
|||
SDL_RenderFillRect(gRenderer, &dimmer);
|
||||
menu_render(inGameMenu, gCamera);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
sprite_render(fpsSprite, gCamera);
|
||||
pointer_render(gPointer, gCamera);
|
||||
#endif // DEBUG
|
||||
|
||||
SDL_RenderPresent(gRenderer);
|
||||
}
|
||||
|
@ -626,19 +828,21 @@ run_game(void)
|
|||
{
|
||||
run_game_update();
|
||||
|
||||
run_game_render();
|
||||
if (cLevel >= 20) {
|
||||
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(gRenderer);
|
||||
render_game_completed();
|
||||
render_gui();
|
||||
SDL_RenderPresent(gRenderer);
|
||||
} else {
|
||||
run_game_render();
|
||||
}
|
||||
|
||||
if (gGameState == PLAYING && is_player_dead()) {
|
||||
camera_shake(VECTOR2D_RIGHT, 800);
|
||||
gui_log("The dungeon consumed you");
|
||||
gui_log("You earned %.2f gold", gPlayer->gold);
|
||||
gui_event_message("You died!");
|
||||
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");
|
||||
}
|
||||
gui_event_message("Press ESC to open menu");
|
||||
end_game_details();
|
||||
mixer_play_effect(SPLAT);
|
||||
gGameState = GAME_OVER;
|
||||
createInGameGameOverMenu();
|
||||
|
@ -647,6 +851,15 @@ run_game(void)
|
|||
} else {
|
||||
check_next_level();
|
||||
}
|
||||
|
||||
if (gGameState == PLAYING && cLevel >= 20) {
|
||||
gGameState = COMPLETED;
|
||||
createInGameGameOverMenu();
|
||||
gui_event_message("Your break is over!");
|
||||
gui_log("Your break is over!");
|
||||
gui_event_message("Well done!");
|
||||
end_game_details();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -672,7 +885,7 @@ run_menu(void)
|
|||
SDL_RenderSetViewport(gRenderer, &menuViewport);
|
||||
map_render(gMap, gCamera);
|
||||
map_render_mid_layer(gMap, gCamera);
|
||||
map_render_top_layer(gMap, gCamera);
|
||||
map_render_top_layer(gMap, gRoomMatrix, gCamera);
|
||||
roommatrix_render_lightmap(gRoomMatrix, gCamera);
|
||||
|
||||
SDL_RenderSetViewport(gRenderer, NULL);
|
||||
|
@ -684,19 +897,31 @@ run_menu(void)
|
|||
else if (gGameState == SCORE_SCREEN)
|
||||
screen_render(scoreScreen, gCamera);
|
||||
|
||||
#ifdef DEBUG
|
||||
sprite_render(fpsSprite, gCamera);
|
||||
pointer_render(gPointer, gCamera);
|
||||
#endif // DEBUG
|
||||
|
||||
SDL_RenderPresent(gRenderer);
|
||||
}
|
||||
|
||||
static
|
||||
void run(void)
|
||||
static void
|
||||
run(void)
|
||||
{
|
||||
static int oldTime = 0;
|
||||
static int currentTime = 0;
|
||||
|
||||
bool quit = false;
|
||||
Timer* fpsTimer = timer_create();
|
||||
|
||||
#ifdef DEBUG
|
||||
Uint32 frame = 0;
|
||||
Timer *fpsTime = timer_create();
|
||||
Timer *updateTimer = timer_create();
|
||||
timer_start(fpsTime);
|
||||
timer_start(updateTimer);
|
||||
#endif // DEBUG
|
||||
|
||||
Timer *fpsTimer = timer_create();
|
||||
|
||||
while (!quit)
|
||||
{
|
||||
|
@ -704,12 +929,15 @@ void run(void)
|
|||
|
||||
quit = handle_events();
|
||||
handle_main_input();
|
||||
#ifdef DEBUG
|
||||
pointer_handle_input(gPointer, &input);
|
||||
#endif // DEBUG
|
||||
|
||||
switch (gGameState) {
|
||||
case PLAYING:
|
||||
case IN_GAME_MENU:
|
||||
case GAME_OVER:
|
||||
case COMPLETED:
|
||||
run_game();
|
||||
break;
|
||||
case MENU:
|
||||
|
@ -736,9 +964,23 @@ void run(void)
|
|||
currentTime = SDL_GetTicks();
|
||||
deltaTime = (float) ((currentTime - oldTime) / 1000.0);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
frame++;
|
||||
if (timer_get_ticks(updateTimer) > 1000) {
|
||||
char buffer[20];
|
||||
m_sprintf(buffer, 20, "FPS: %u", frame / (timer_get_ticks(fpsTime) / 1000));
|
||||
texture_load_from_text(fpsSprite->textures[0], buffer, C_RED, C_WHITE, gRenderer);
|
||||
fpsSprite->dim = fpsSprite->textures[0]->dim;
|
||||
timer_start(updateTimer);
|
||||
}
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
timer_destroy(fpsTimer);
|
||||
#ifdef DEBUG
|
||||
timer_destroy(fpsTime);
|
||||
timer_destroy(updateTimer);
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
static
|
||||
|
@ -758,11 +1000,16 @@ void close(void)
|
|||
if (inGameMenu)
|
||||
menu_destroy(inGameMenu);
|
||||
|
||||
sprite_destroy(howto_tooltip);
|
||||
sprite_destroy(new_skill_tooltip);
|
||||
camera_destroy(gCamera);
|
||||
roommatrix_destroy(gRoomMatrix);
|
||||
gui_destroy(gGui);
|
||||
skillbar_destroy(gSkillBar);
|
||||
#ifdef DEBUG
|
||||
pointer_destroy(gPointer);
|
||||
sprite_destroy(fpsSprite);
|
||||
#endif // DEBUG
|
||||
actiontextbuilder_close();
|
||||
item_builder_close();
|
||||
particle_engine_close();
|
||||
|
|
19
src/map.c
19
src/map.c
|
@ -27,8 +27,8 @@
|
|||
#include "update_data.h"
|
||||
#include "trap.h"
|
||||
|
||||
static
|
||||
Room* create_room(void)
|
||||
static Room*
|
||||
create_room(void)
|
||||
{
|
||||
int i, j;
|
||||
Room *room;
|
||||
|
@ -40,6 +40,7 @@ Room* create_room(void)
|
|||
room->tiles[i][j] = NULL;
|
||||
room->decorations[i][j] = NULL;
|
||||
room->traps[i][j] = NULL;
|
||||
room->visited = false;
|
||||
}
|
||||
}
|
||||
return room;
|
||||
|
@ -205,14 +206,18 @@ map_move_monsters(Map *map, RoomMatrix *rm)
|
|||
if (monster->state.current == PASSIVE
|
||||
&& position_proximity(1, &rm->playerRoomPos, &pos))
|
||||
continue;
|
||||
if (monster->steps >= monster->stats.speed)
|
||||
continue;
|
||||
|
||||
allDone = allDone && monster_move(monster, rm, map);
|
||||
}
|
||||
|
||||
if (allDone)
|
||||
if (allDone) {
|
||||
timer_stop(map->monsterMoveTimer);
|
||||
else
|
||||
linkedlist_each(&map->monsters, (void (*)(void*)) monster_reset_steps);
|
||||
} else {
|
||||
timer_start(map->monsterMoveTimer);
|
||||
}
|
||||
|
||||
return allDone;
|
||||
}
|
||||
|
@ -353,13 +358,13 @@ map_render_mid_layer(Map *map, Camera *cam)
|
|||
}
|
||||
|
||||
void
|
||||
map_render_top_layer(Map *map, Camera *cam)
|
||||
map_render_top_layer(Map *map, RoomMatrix *rm, Camera *cam)
|
||||
{
|
||||
LinkedList *monsterItem = map->monsters;
|
||||
while (monsterItem != NULL) {
|
||||
Monster *monster = monsterItem->data;
|
||||
monsterItem = monsterItem->next;
|
||||
monster_render_top_layer(monster, cam);
|
||||
monster_render_top_layer(monster, rm, cam);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,6 +393,8 @@ void map_set_current_room(Map *map, Position *pos)
|
|||
map->currentRoom.x = MAP_H_ROOM_COUNT - 1;
|
||||
if (map->currentRoom.y >= MAP_V_ROOM_COUNT)
|
||||
map->currentRoom.y = MAP_V_ROOM_COUNT - 1;
|
||||
|
||||
map->rooms[map->currentRoom.x][map->currentRoom.y]->visited = true;
|
||||
}
|
||||
|
||||
static
|
||||
|
|
|
@ -51,6 +51,7 @@ typedef struct Room_t {
|
|||
MapTile* decorations[MAP_ROOM_WIDTH][MAP_ROOM_HEIGHT];
|
||||
Trap* traps[MAP_ROOM_WIDTH][MAP_ROOM_HEIGHT];
|
||||
RoomModifierData modifier;
|
||||
bool visited;
|
||||
} Room;
|
||||
|
||||
typedef struct Map_t {
|
||||
|
@ -106,7 +107,7 @@ void
|
|||
map_render_mid_layer(Map*, Camera*);
|
||||
|
||||
void
|
||||
map_render_top_layer(Map*, Camera*);
|
||||
map_render_top_layer(Map*, RoomMatrix*, Camera*);
|
||||
|
||||
void
|
||||
map_set_current_room(Map*, Position*);
|
||||
|
|
120
src/monster.c
120
src/monster.c
|
@ -106,6 +106,8 @@ monster_behaviour_check_post_hit(Monster *m)
|
|||
monster_state_change(m, SCARED);
|
||||
break;
|
||||
case GUERILLA:
|
||||
case ASSASSIN:
|
||||
case SORCERER:
|
||||
case FIRE_DEMON:
|
||||
break;
|
||||
default:
|
||||
|
@ -114,14 +116,61 @@ monster_behaviour_check_post_hit(Monster *m)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
damage_surroundings(Monster *m, RoomMatrix *rm)
|
||||
{
|
||||
Position roomPos = position_to_matrix_coords(&m->sprite->pos);
|
||||
for (Sint32 i = -1; i <= 1; ++i) {
|
||||
for (Sint32 j = -1; j <= 1; ++j) {
|
||||
if (i == 0 && j == 0)
|
||||
continue;
|
||||
RoomSpace *r = &rm->spaces[roomPos.x + i][roomPos.y + j];
|
||||
if (r->monster) {
|
||||
int dmg = stats_fight(&m->stats, &r->monster->stats);
|
||||
monster_hit(r->monster, dmg);
|
||||
gui_log("%s takes %d damage from the explosion", r->monster->label, dmg);
|
||||
} else if (r->player) {
|
||||
int dmg = stats_fight(&m->stats, &r->player->stats);
|
||||
player_hit(r->player, dmg);
|
||||
gui_log("You take %d damage from the explosion", dmg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sorcerer_blast(Monster *m, RoomMatrix *rm)
|
||||
{
|
||||
gui_log("%s creates a magical explosion", m->label);
|
||||
particle_engine_eldritch_explosion(m->sprite->pos, DIM(TILE_DIMENSION, TILE_DIMENSION));
|
||||
|
||||
damage_surroundings(m, rm);
|
||||
}
|
||||
|
||||
static void
|
||||
assassin_cloak_effect(Monster *m, bool cloak)
|
||||
{
|
||||
if (cloak)
|
||||
gui_log("%s dissappears from sight", m->label);
|
||||
else
|
||||
gui_log("%s reappears, filled with rage", m->label);
|
||||
particle_engine_fire_explosion(m->sprite->pos, DIM(TILE_DIMENSION, TILE_DIMENSION));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
monster_behaviour_check_post_attack(Monster *m)
|
||||
{
|
||||
switch (m->behaviour) {
|
||||
case GUERILLA:
|
||||
case SORCERER:
|
||||
case FIRE_DEMON:
|
||||
monster_state_change(m, SCARED);
|
||||
break;
|
||||
case ASSASSIN:
|
||||
assassin_cloak_effect(m, true);
|
||||
monster_state_change(m, SCARED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -154,12 +203,20 @@ monster_behaviour_check(Monster *m, RoomMatrix *rm)
|
|||
{
|
||||
switch (m->behaviour) {
|
||||
case GUERILLA:
|
||||
case SORCERER:
|
||||
case FIRE_DEMON:
|
||||
if (m->state.stepsSinceChange > 8
|
||||
if (m->state.stepsSinceChange > 5
|
||||
&& m->state.current == SCARED) {
|
||||
monster_state_change(m, AGRESSIVE);
|
||||
}
|
||||
break;
|
||||
case ASSASSIN:
|
||||
if (m->state.stepsSinceChange > 5
|
||||
&& m->state.current == SCARED) {
|
||||
assassin_cloak_effect(m, false);
|
||||
monster_state_change(m, AGRESSIVE);
|
||||
}
|
||||
break;
|
||||
case SENTINEL:
|
||||
handle_sentinel_behaviour(m, rm);
|
||||
break;
|
||||
|
@ -395,10 +452,18 @@ monster_move(Monster *m, RoomMatrix *rm, Map *map)
|
|||
}
|
||||
|
||||
monster_behaviour_check(m, rm);
|
||||
|
||||
Position origPos = m->sprite->pos;
|
||||
Position originalMPos =
|
||||
position_to_matrix_coords(&m->sprite->pos);
|
||||
|
||||
if (m->state.current == AGRESSIVE && m->behaviour == SORCERER) {
|
||||
if (position_proximity(1, &originalMPos, &rm->playerRoomPos)) {
|
||||
sorcerer_blast(m, rm);
|
||||
monster_behaviour_check_post_attack(m);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
rm->spaces[originalMPos.x][originalMPos.y].occupied = false;
|
||||
rm->spaces[originalMPos.x][originalMPos.y].monster = NULL;
|
||||
|
||||
|
@ -436,18 +501,28 @@ monster_move(Monster *m, RoomMatrix *rm, Map *map)
|
|||
|
||||
RoomSpace *space = &rm->spaces[newPos.x][newPos.y];
|
||||
if (space->light < 100 && withinHearingDist) {
|
||||
actiontextbuilder_create_text("!", C_WHITE, &m->sprite->pos);
|
||||
Position alertPos = m->sprite->pos;
|
||||
alertPos.x += TILE_DIMENSION >> 1;
|
||||
alertPos.y += TILE_DIMENSION >> 1;
|
||||
actiontextbuilder_create_text("!", C_WHITE, &alertPos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!position_equals(&origPos, &m->sprite->pos)
|
||||
&& (rm->modifier->type == RMOD_TYPE_FIRE || m->behaviour == FIRE_DEMON)) {
|
||||
Object *o = object_create_fire();
|
||||
o->sprite->pos = origPos;
|
||||
o->damage *= m->stats.lvl;
|
||||
linkedlist_push(&map->objects, o);
|
||||
if (!position_equals(&origPos, &m->sprite->pos)) {
|
||||
if (rm->modifier->type == RMOD_TYPE_FIRE || m->behaviour == FIRE_DEMON) {
|
||||
Object *o = object_create_fire();
|
||||
o->sprite->pos = origPos;
|
||||
o->damage *= m->stats.lvl;
|
||||
linkedlist_push(&map->objects, o);
|
||||
}
|
||||
if (m->behaviour == SORCERER) {
|
||||
Object *o = object_create_green_gas();
|
||||
o->sprite->pos = origPos;
|
||||
o->damage *= m->stats.lvl;
|
||||
linkedlist_push(&map->objects, o);
|
||||
}
|
||||
}
|
||||
|
||||
m->steps++;
|
||||
|
@ -455,13 +530,18 @@ monster_move(Monster *m, RoomMatrix *rm, Map *map)
|
|||
if (m->stateIndicator.displayCount > 0)
|
||||
m->stateIndicator.displayCount -= 1;
|
||||
m->state.stepsSinceChange += 1;
|
||||
m->steps = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
monster_reset_steps(Monster *m)
|
||||
{
|
||||
m->steps = 0;
|
||||
}
|
||||
|
||||
void
|
||||
monster_update(Monster *m, UpdateData *data)
|
||||
{
|
||||
|
@ -542,7 +622,7 @@ monster_drop_loot(Monster *monster, Map *map, Player *player)
|
|||
linkedlist_append(&map->items, treasure);
|
||||
}
|
||||
|
||||
if (monster->stats.lvl > 2 && get_random(19) == 0) {
|
||||
if (monster->stats.lvl > 2 && get_random(29) == 0) {
|
||||
Artifact *a = artifact_create_random(player, 1);
|
||||
a->sprite->pos = monster->sprite->pos;
|
||||
linkedlist_append(&map->artifacts, a);
|
||||
|
@ -593,17 +673,31 @@ monster_render(Monster *m, Camera *cam)
|
|||
if (m->stats.hp <= 0)
|
||||
return;
|
||||
|
||||
if (m->behaviour == ASSASSIN && m->state.current != AGRESSIVE)
|
||||
return;
|
||||
|
||||
sprite_render(m->sprite, cam);
|
||||
}
|
||||
|
||||
void
|
||||
monster_render_top_layer(Monster *m, Camera *cam)
|
||||
monster_render_top_layer(Monster *m, RoomMatrix *rm, Camera *cam)
|
||||
{
|
||||
if (m->stats.hp <= 0)
|
||||
return;
|
||||
|
||||
if (m->behaviour == ASSASSIN && m->state.current != AGRESSIVE)
|
||||
return;
|
||||
|
||||
Position mPos = position_to_matrix_coords(&m->sprite->pos);
|
||||
mPos.y -= 1;
|
||||
if (rm->spaces[mPos.x][mPos.y].player) {
|
||||
sprite_set_alpha(m->stateIndicator.sprite, 110);
|
||||
}
|
||||
if (m->stateIndicator.displayCount != 0)
|
||||
sprite_render(m->stateIndicator.sprite, cam);
|
||||
if (rm->spaces[mPos.x][mPos.y].player) {
|
||||
sprite_set_alpha(m->stateIndicator.sprite, 255);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -613,6 +707,8 @@ monster_set_behaviour(Monster *m, MonsterBehaviour behaviour)
|
|||
switch (behaviour) {
|
||||
case HOSTILE:
|
||||
case GUERILLA:
|
||||
case ASSASSIN:
|
||||
case SORCERER:
|
||||
case COWARD:
|
||||
case FIRE_DEMON:
|
||||
m->state.current = AGRESSIVE;
|
||||
|
|
|
@ -35,7 +35,9 @@ typedef enum {
|
|||
GUERILLA,
|
||||
COWARD,
|
||||
SENTINEL,
|
||||
FIRE_DEMON
|
||||
FIRE_DEMON,
|
||||
SORCERER,
|
||||
ASSASSIN
|
||||
} MonsterBehaviour;
|
||||
|
||||
typedef enum {
|
||||
|
@ -85,7 +87,7 @@ void
|
|||
monster_render(Monster*, Camera*);
|
||||
|
||||
void
|
||||
monster_render_top_layer(Monster*, Camera*);
|
||||
monster_render_top_layer(Monster*, RoomMatrix*, Camera*);
|
||||
|
||||
void
|
||||
monster_hit(Monster*, unsigned int dmg);
|
||||
|
@ -108,6 +110,9 @@ monster_set_state(Monster *m, StateType state, Uint8 forceCount);
|
|||
void
|
||||
monster_push(Monster *, RoomMatrix*, Vector2d dir);
|
||||
|
||||
void
|
||||
monster_reset_steps(Monster *m);
|
||||
|
||||
void
|
||||
monster_destroy(Monster*);
|
||||
|
||||
|
|
15
src/object.c
15
src/object.c
|
@ -49,6 +49,21 @@ object_create_fire()
|
|||
return o;
|
||||
}
|
||||
|
||||
Object *
|
||||
object_create_green_gas()
|
||||
{
|
||||
Object *o = object_create();
|
||||
Texture *t0 = texturecache_add("Objects/Effect0.png");
|
||||
Texture *t1 = texturecache_add("Objects/Effect1.png");
|
||||
sprite_set_texture(o->sprite, t0, 0);
|
||||
sprite_set_texture(o->sprite, t1, 1);
|
||||
o->sprite->dim = GAME_DIMENSION;
|
||||
o->sprite->clip = CLIP16(32, 24*16);
|
||||
o->damage = 3;
|
||||
o->timeout = 3;
|
||||
return o;
|
||||
}
|
||||
|
||||
void
|
||||
object_render(Object *o, Camera *cam)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,9 @@ object_create(void);
|
|||
Object *
|
||||
object_create_fire(void);
|
||||
|
||||
Object *
|
||||
object_create_green_gas(void);
|
||||
|
||||
void
|
||||
object_render(Object*, Camera*);
|
||||
|
||||
|
|
|
@ -156,10 +156,10 @@ create_explosion(Position pos, Dimension dim, unsigned int c_count, ...)
|
|||
x = get_random(dim.width) + pos.x;
|
||||
y = get_random(dim.height) + pos.y;
|
||||
|
||||
xv = get_random(600) - 300;
|
||||
yv = get_random(600) - 300;
|
||||
xv = get_random(500) - 300;
|
||||
yv = get_random(500) - 300;
|
||||
|
||||
lt = get_random(10);
|
||||
lt = get_random(20);
|
||||
|
||||
p = create_rect_particle();
|
||||
p->particle.rect.pos = (Position) { x, y };
|
||||
|
@ -167,6 +167,7 @@ create_explosion(Position pos, Dimension dim, unsigned int c_count, ...)
|
|||
p->velocity = (Vector2d) { (float) xv, (float) yv };
|
||||
p->movetime = lt;
|
||||
p->lifetime = lt;
|
||||
p->blend_mode = SDL_BLENDMODE_BLEND;
|
||||
p->color = colors[get_random((unsigned int) c_count-1)];
|
||||
linkedlist_append(&engine->game_particles, p);
|
||||
}
|
||||
|
@ -318,7 +319,7 @@ particle_engine_heat()
|
|||
h = get_random(2) + 2;
|
||||
|
||||
yvel = get_random(50) - 200;
|
||||
xvel = get_random(100) * -get_random(1);
|
||||
xvel = get_random(100) * -((int) get_random(1));
|
||||
|
||||
lt = get_random(500);
|
||||
|
||||
|
|
21
src/player.c
21
src/player.c
|
@ -428,7 +428,7 @@ build_sword_animation(Player *p, SDL_Renderer *renderer)
|
|||
}
|
||||
|
||||
Player*
|
||||
player_create(class_t class, SDL_Renderer *renderer)
|
||||
player_create(class_t class, Camera *cam)
|
||||
{
|
||||
Player *player = malloc(sizeof(Player));
|
||||
player->sprite = sprite_create();
|
||||
|
@ -450,8 +450,9 @@ player_create(class_t class, SDL_Renderer *renderer)
|
|||
player->projectiles = linkedlist_create();
|
||||
player->animationTimer = timer_create();
|
||||
player->swordAnimation = animation_create(5);
|
||||
player->equipment.hasArtifacts = false;
|
||||
|
||||
build_sword_animation(player, renderer);
|
||||
build_sword_animation(player, cam->renderer);
|
||||
|
||||
memset(&player->skills,
|
||||
0, PLAYER_SKILL_COUNT * sizeof(Skill*));
|
||||
|
@ -480,16 +481,16 @@ player_create(class_t class, SDL_Renderer *renderer)
|
|||
case WARRIOR:
|
||||
m_strcpy(asset, 100, "Commissions/Warrior.png");
|
||||
player->stats = (Stats) WARRIOR_STATS;
|
||||
player->skills[0] = skill_create(FLURRY);
|
||||
player->skills[1] = skill_create(BASH);
|
||||
player->skills[2] = skill_create(CHARGE);
|
||||
player->skills[3] = skill_create(DAGGER_THROW);
|
||||
player->skills[0] = skill_create(FLURRY, cam);
|
||||
player->skills[1] = skill_create(BASH, cam);
|
||||
player->skills[2] = skill_create(CHARGE, cam);
|
||||
player->skills[3] = skill_create(DAGGER_THROW, cam);
|
||||
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->dim = GAME_DIMENSION;
|
||||
player->sprite->clip = (SDL_Rect) { 0, 0, 16, 16 };
|
||||
|
@ -530,7 +531,7 @@ player_hit(Player *p, unsigned int dmg)
|
|||
Position pos = p->sprite->pos;
|
||||
pos.x += 8;
|
||||
pos.y += 8;
|
||||
particle_engine_bloodspray(pos, (Dimension) { 8, 8 }, dmg);
|
||||
particle_engine_bloodspray(pos, DIM(8, 8), dmg);
|
||||
mixer_play_effect(PLAYER_HIT0 + get_random(2));
|
||||
char msg[5];
|
||||
m_sprintf(msg, 5, "-%d", dmg);
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ typedef struct ArtifactData {
|
|||
|
||||
typedef struct PlayerEquipment {
|
||||
ArtifactData artifacts[LAST_ARTIFACT_EFFECT];
|
||||
bool hasArtifacts;
|
||||
} PlayerEquipment;
|
||||
|
||||
typedef struct Player {
|
||||
|
@ -79,7 +80,7 @@ typedef struct Player {
|
|||
} Player;
|
||||
|
||||
Player*
|
||||
player_create(class_t, SDL_Renderer*);
|
||||
player_create(class_t, Camera*);
|
||||
|
||||
ExperienceData
|
||||
player_get_xp_data(Player*);
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define POS(x, y) (Position) { x, y }
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
|
|
|
@ -295,6 +295,8 @@ void roommatrix_destroy(RoomMatrix *m)
|
|||
linkedlist_pop(&space->items);
|
||||
while (space->artifacts)
|
||||
linkedlist_pop(&space->artifacts);
|
||||
while (space->objects)
|
||||
linkedlist_pop(&space->objects);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,10 @@
|
|||
static sqlite3 *db = NULL;
|
||||
static Settings settings;
|
||||
|
||||
static const char *KEY_MUSIC_ENABLED = "music_enabled";
|
||||
static const char *KEY_SOUND_ENABLED = "sound_enabled";
|
||||
static const char *KEY_MUSIC_ENABLED = "music_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
|
||||
DbQuery MIGRATE_COMMANDS[] = {
|
||||
|
@ -49,6 +51,8 @@ set_default_settings(void)
|
|||
{
|
||||
settings.music_enabled = true;
|
||||
settings.sound_enabled = true;
|
||||
settings.tooltips_enabled = true;
|
||||
settings.howto_tooltip_shown = false;
|
||||
}
|
||||
|
||||
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]);
|
||||
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;
|
||||
}
|
||||
|
@ -127,6 +139,8 @@ settings_save(void)
|
|||
{
|
||||
save_setting_int(KEY_SOUND_ENABLED, settings.sound_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 *
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
typedef struct Settings {
|
||||
bool music_enabled;
|
||||
bool sound_enabled;
|
||||
bool tooltips_enabled;
|
||||
bool howto_tooltip_shown;
|
||||
} Settings;
|
||||
|
||||
void
|
||||
|
|
110
src/skill.c
110
src/skill.c
|
@ -35,6 +35,106 @@
|
|||
#include "animation.h"
|
||||
#include "artifact.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 *
|
||||
create_default(const char *s_label, Sprite *s)
|
||||
|
@ -50,6 +150,7 @@ create_default(const char *s_label, Sprite *s)
|
|||
skill->available = NULL;
|
||||
skill->use = NULL;
|
||||
skill->levelcap = 1;
|
||||
skill->tooltip = NULL;
|
||||
return skill;
|
||||
}
|
||||
|
||||
|
@ -410,24 +511,29 @@ create_charge(void)
|
|||
}
|
||||
|
||||
Skill*
|
||||
skill_create(enum SkillType t)
|
||||
skill_create(enum SkillType t, Camera *cam)
|
||||
{
|
||||
Skill *skill;
|
||||
switch (t) {
|
||||
case FLURRY:
|
||||
skill = create_flurry();
|
||||
skill->tooltip = tooltip_create(flurry_tooltip, cam);
|
||||
break;
|
||||
case SIP_HEALTH:
|
||||
skill = create_sip_health();
|
||||
skill->tooltip = tooltip_create(health_tooltip, cam);
|
||||
break;
|
||||
case CHARGE:
|
||||
skill = create_charge();
|
||||
skill->tooltip = tooltip_create(charge_tooltip, cam);
|
||||
break;
|
||||
case DAGGER_THROW:
|
||||
skill = create_throw_dagger();
|
||||
skill->tooltip = tooltip_create(dagger_tooltip, cam);
|
||||
break;
|
||||
case BASH:
|
||||
skill = create_bash();
|
||||
skill->tooltip = tooltip_create(bash_tooltip, cam);
|
||||
break;
|
||||
default:
|
||||
fatal("Unknown SkillType %u", (unsigned int) t);
|
||||
|
@ -444,5 +550,7 @@ void
|
|||
skill_destroy(Skill *skill)
|
||||
{
|
||||
sprite_destroy(skill->icon);
|
||||
if (skill->tooltip)
|
||||
sprite_destroy(skill->tooltip);
|
||||
free(skill);
|
||||
}
|
||||
|
|
|
@ -52,10 +52,11 @@ typedef struct Skill_t {
|
|||
bool active;
|
||||
bool (*available)(Player*);
|
||||
bool (*use)(struct Skill_t*, SkillData*);
|
||||
Sprite *tooltip;
|
||||
} Skill;
|
||||
|
||||
Skill*
|
||||
skill_create(enum SkillType);
|
||||
skill_create(enum SkillType, Camera *cam);
|
||||
|
||||
void
|
||||
skill_destroy(Skill*);
|
||||
|
|
207
src/skillbar.c
207
src/skillbar.c
|
@ -26,6 +26,7 @@
|
|||
#include "texturecache.h"
|
||||
#include "particle_engine.h"
|
||||
#include "update_data.h"
|
||||
#include "gui.h"
|
||||
|
||||
static void
|
||||
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.height = 16;
|
||||
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
char buffer[4];
|
||||
Sprite *s = sprite_create();
|
||||
s->pos = (Position) { i * 32 + 20, 20 };
|
||||
|
@ -52,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 };
|
||||
|
@ -60,45 +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;
|
||||
}
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -111,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
|
||||
|
@ -177,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)
|
||||
{
|
||||
|
@ -242,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);
|
||||
|
@ -256,8 +348,17 @@ skillbar_update(SkillBar *bar, UpdateData *data)
|
|||
{
|
||||
Input *input = data->input;
|
||||
|
||||
unsigned int key = 0;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int i = 0; i < 5; ++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))
|
||||
continue;
|
||||
key = i;
|
||||
|
@ -268,6 +369,35 @@ 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;
|
||||
|
||||
Uint32 origLevel = bar->artifacts[i].lvl;
|
||||
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_PURPLE, C_WHITE, data->cam->renderer);
|
||||
|
||||
// Only update position if this is the first pickup
|
||||
if (origLevel == 0) {
|
||||
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
|
||||
|
@ -275,9 +405,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);
|
||||
|
|
|
@ -28,18 +28,27 @@
|
|||
|
||||
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*);
|
||||
|
||||
void
|
||||
bool
|
||||
skillbar_check_skill_activation(SkillBar*, Player*);
|
||||
|
||||
void
|
||||
|
@ -48,6 +57,9 @@ skillbar_render(SkillBar*, Player*, Camera*);
|
|||
void
|
||||
skillbar_update(SkillBar*, struct UpdateData*);
|
||||
|
||||
void
|
||||
skillbar_reset(SkillBar*);
|
||||
|
||||
void
|
||||
skillbar_destroy(SkillBar*);
|
||||
|
||||
|
|
18
src/sprite.c
18
src/sprite.c
|
@ -94,6 +94,24 @@ sprite_set_texture(Sprite *s, Texture *t, int index)
|
|||
s->textures[index] = t;
|
||||
}
|
||||
|
||||
void
|
||||
sprite_set_blend_mode(Sprite *s, SDL_BlendMode mode)
|
||||
{
|
||||
if (s->textures[0])
|
||||
texture_set_blend_mode(s->textures[0], mode);
|
||||
if (s->textures[1])
|
||||
texture_set_blend_mode(s->textures[1], mode);
|
||||
}
|
||||
|
||||
void
|
||||
sprite_set_alpha(Sprite *s, Uint8 alpha)
|
||||
{
|
||||
if (s->textures[0])
|
||||
texture_set_alpha(s->textures[0], alpha);
|
||||
if (s->textures[1])
|
||||
texture_set_alpha(s->textures[1], alpha);
|
||||
}
|
||||
|
||||
void
|
||||
sprite_render(Sprite *s, Camera *cam)
|
||||
{
|
||||
|
|
|
@ -59,6 +59,12 @@ sprite_set_texture(Sprite *, Texture *, int index);
|
|||
void
|
||||
sprite_render(Sprite*, Camera*);
|
||||
|
||||
void
|
||||
sprite_set_blend_mode(Sprite*, SDL_BlendMode);
|
||||
|
||||
void
|
||||
sprite_set_alpha(Sprite*, Uint8);
|
||||
|
||||
void
|
||||
sprite_destroy(Sprite *);
|
||||
|
||||
|
|
|
@ -67,16 +67,17 @@ stats_fight(Stats *attacker, Stats *defender)
|
|||
bool critical = false;
|
||||
|
||||
int atkRoll = get_attack_roll(attacker);
|
||||
if (atkRoll - attacker->atk == 20)
|
||||
critical = true;
|
||||
int defRoll = get_defence_roll(defender);
|
||||
|
||||
if (atkRoll - attacker->atk == 20)
|
||||
critical = get_attack_roll(attacker) > defRoll;
|
||||
|
||||
int dmgRoll = 0;
|
||||
if (atkRoll >= defRoll) {
|
||||
if (attacker->dmg > 0)
|
||||
dmgRoll = get_random(attacker->dmg) + 1;
|
||||
else
|
||||
dmgRoll = get_random(attacker->dmg - 1) + 1;
|
||||
else
|
||||
dmgRoll = 1;
|
||||
|
||||
if (critical) {
|
||||
dmgRoll = dmgRoll * 2;
|
||||
|
|
|
@ -223,6 +223,20 @@ texture_load_from_text_blended(Texture *t, const char * text, SDL_Color fg, SDL_
|
|||
load_from_surface(t, surface, renderer);
|
||||
}
|
||||
|
||||
void
|
||||
texture_set_blend_mode(Texture *t, SDL_BlendMode mode)
|
||||
{
|
||||
assert(t->texture);
|
||||
SDL_SetTextureBlendMode(t->texture, mode);
|
||||
}
|
||||
|
||||
void
|
||||
texture_set_alpha(Texture *t, Uint8 alpha)
|
||||
{
|
||||
assert(t->texture);
|
||||
SDL_SetTextureAlphaMod(t->texture, alpha);
|
||||
}
|
||||
|
||||
void
|
||||
texture_render(Texture *texture, SDL_Rect *box, Camera *cam)
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "position.h"
|
||||
#include "camera.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct Texture {
|
||||
SDL_Texture *texture;
|
||||
TTF_Font *font;
|
||||
TTF_Font *outlineFont;
|
||||
|
@ -76,6 +76,12 @@ texture_load_from_text_blended(Texture*,
|
|||
SDL_Color,
|
||||
SDL_Renderer*);
|
||||
|
||||
void
|
||||
texture_set_blend_mode(Texture*, SDL_BlendMode);
|
||||
|
||||
void
|
||||
texture_set_alpha(Texture*, Uint8);
|
||||
|
||||
void
|
||||
texture_render(Texture*, SDL_Rect*, Camera*);
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 <string.h>
|
||||
#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;
|
||||
}
|
|
@ -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*);
|
|
@ -22,11 +22,15 @@
|
|||
#include "player.h"
|
||||
#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;
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
#define debug(...) do {} while(0)
|
||||
#define info(...) do {} while(0)
|
||||
#endif // DEBUG
|
||||
#define error(...) log_print(stderr, "ERROR", __FNAME__, __LINE__, __func__, __VA_ARGS__)
|
||||
|
||||
#define error(...) log_print(stderr, "ERROR", __FNAME__, __LINE__, __func__, __VA_ARGS__)
|
||||
#ifdef DEBUG
|
||||
#define fatal(...) \
|
||||
{ \
|
||||
|
@ -44,7 +44,7 @@
|
|||
getchar(); \
|
||||
exit(-1); \
|
||||
}
|
||||
#else
|
||||
#else // DEBUG
|
||||
#define fatal(...) \
|
||||
{ \
|
||||
log_print(stderr, "FATAL", __FNAME__, __LINE__, __func__, __VA_ARGS__); \
|
||||
|
|
Loading…
Reference in New Issue