diff --git a/.appveyor.yml b/.appveyor.yml index d9675c9..8f67fe4 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -91,24 +91,24 @@ build_script: - |- mingw32-make ctest -V - mingw32-make package +# mingw32-make package -artifacts: - - path: package/breakhack-*.zip - name: breakhack_zip +# artifacts: +# - path: package/breakhack-*.zip +# name: breakhack_zip - - path: package/breakhack-*.exe - name: breakhack_exe +# - path: package/breakhack-*.exe +# name: breakhack_exe -deploy: - provider: GitHub - description: 'Alpha pre-release' - auth_token: - secure: IlMEyGp0AuDI8/MkFAY2KpRr70c3p8eVEMdcqC1EcgyCCbvoMOppBQ0gY44ao0gq - draft: false - prerelease: true - on: - branch: master - appveyor_repo_tag: true +# deploy: +# provider: GitHub +# description: 'Alpha pre-release' +# auth_token: +# secure: IlMEyGp0AuDI8/MkFAY2KpRr70c3p8eVEMdcqC1EcgyCCbvoMOppBQ0gY44ao0gq +# draft: false +# prerelease: true +# on: +# branch: master +# appveyor_repo_tag: true diff --git a/.clang_complete b/.clang_complete index 17b71c1..e1282ec 100644 --- a/.clang_complete +++ b/.clang_complete @@ -1,4 +1,6 @@ -DDEBUG +-I./steamworks_c_api/src/ +-I./src/steam/ -I./build/config.h -I/usr/include/SDL2/ -I/usr/include/lua5.2/ diff --git a/.gitignore b/.gitignore index b63594d..f64b1a7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,8 @@ /data.pack /.vs/ /.data.db +/steamworks_c_wrapper/_build +/steamworks_c_wrapper/sdk *.swp *~ +/steam_appid.txt diff --git a/.travis.yml b/.travis.yml index 0377e20..5f2d39b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,19 +52,18 @@ addons: build_command: "make" branch_pattern: coverity_scan -before_deploy: - - make package +# before_deploy: +# - make package -deploy: - provider: releases - api_key: - secure: "KeT/BC2ck2eqs1q4keoLe/Y9KIk+AR5shiAnA2oMQzbLWoZmxUx3Kol7rLPJ0Hfgb+aCpSpTM1njX6Kw7Nl8j4NrOkgadb3ZmfqRthFazzb93reRt+0dZZcurilHpWtMeteaZLWGWaG0j09xnI3CPPjmth6BB+/roGRsQyo1QKk0pZYsQD6ZKfGAUR1576dFyRzvsIrnfLd7rZVSNZ8HtPwN2rmSLD/cGxMCf+IafcBInPyv9p6bCoVLIDFnDdCr+kwBuSlGudT15EtDx3d9Abab3ZIS3NUpnXr2s0BmknCpyb59YsG9V0YXIQsIkwioEWiJskcAznXT/yB4XqDCq693b+0sxldsUVPw2JkMU+40V5ay2itH3SeP/LyXVFUARdWB+nn6avaFRVaZ1nHYP95CrBXC8JGB1bd7ejeEm9+cOvBOgvsZp71uRJ2OdEXN5Z3i373cyvWXPFHVbQRJS5l1dRBJR0sozYcPe8BMQ4Pv+xahFWIeyDAErUwJSiOf1Uv/x6PNxJaZTTZKCYGSRo6Ywb15bw4YnlOzDXllBxNg3IsJjJes1qFBJGR1eRMq/U9Ne+eHLk7cn2r7Fa77DtFsbONTDHftXDFHk46LDLF+HlL2wHIoTJVzLl/tXyBm3MJuaghGEvvZSwalWS3UnvMTQOBlDG0qC/ww6mlkv+Y=" - skip_cleanup: true - file_glob: true - file: - - "package/breakhack*.tar.gz" - - "package/breakhack*.tar.Z" - on: - tags: true - condition: $CC = gcc - condition: $BUILD_TYPE = Release +# deploy: +# provider: releases +# api_key: +# secure: "KeT/BC2ck2eqs1q4keoLe/Y9KIk+AR5shiAnA2oMQzbLWoZmxUx3Kol7rLPJ0Hfgb+aCpSpTM1njX6Kw7Nl8j4NrOkgadb3ZmfqRthFazzb93reRt+0dZZcurilHpWtMeteaZLWGWaG0j09xnI3CPPjmth6BB+/roGRsQyo1QKk0pZYsQD6ZKfGAUR1576dFyRzvsIrnfLd7rZVSNZ8HtPwN2rmSLD/cGxMCf+IafcBInPyv9p6bCoVLIDFnDdCr+kwBuSlGudT15EtDx3d9Abab3ZIS3NUpnXr2s0BmknCpyb59YsG9V0YXIQsIkwioEWiJskcAznXT/yB4XqDCq693b+0sxldsUVPw2JkMU+40V5ay2itH3SeP/LyXVFUARdWB+nn6avaFRVaZ1nHYP95CrBXC8JGB1bd7ejeEm9+cOvBOgvsZp71uRJ2OdEXN5Z3i373cyvWXPFHVbQRJS5l1dRBJR0sozYcPe8BMQ4Pv+xahFWIeyDAErUwJSiOf1Uv/x6PNxJaZTTZKCYGSRo6Ywb15bw4YnlOzDXllBxNg3IsJjJes1qFBJGR1eRMq/U9Ne+eHLk7cn2r7Fa77DtFsbONTDHftXDFHk46LDLF+HlL2wHIoTJVzLl/tXyBm3MJuaghGEvvZSwalWS3UnvMTQOBlDG0qC/ww6mlkv+Y=" +# skip_cleanup: true +# file_glob: true +# file: +# - "package/breakhack*.tar.gz" +# on: +# tags: true +# condition: $CC = gcc +# condition: $BUILD_TYPE = Release diff --git a/.vimrc b/.vimrc index 579fddc..4647378 100644 --- a/.vimrc +++ b/.vimrc @@ -5,4 +5,4 @@ nnoremap :ter ++close ./_build/breakhack packadd termdebug let g:termdebug_wide = 1 -let g:syntastic_c_include_dirs = [ '_build', '/usr/include/SDL2' ] +let g:syntastic_c_include_dirs = [ '_build', '/usr/include/SDL2', 'steamworks_c_wrapper/src', 'steamworks_c_wrapper/sdk/public/steam' ] diff --git a/CMakeLists.txt b/CMakeLists.txt index 3515bce..ca13619 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,10 @@ SET(CMAKE_COLOR_MAKEFILE ON) project(breakhack C) set(breakhack_GAME_TITLE "BreakHack") -set(breakhack_MAJOR_VERSION 0) -set(breakhack_MINOR_VERSION 2) -set(breakhack_PATCH_VERSION 0) -set(breakhack_RELEASE_TYPE "(beta)") +set(breakhack_MAJOR_VERSION 1) +set(breakhack_MINOR_VERSION 0) +set(breakhack_PATCH_VERSION 2) +set(breakhack_RELEASE_TYPE "") include(FindLua) include(FindPhysFS) @@ -25,6 +25,17 @@ configure_file( "${PROJECT_BINARY_DIR}/config.h" ) +if (EXISTS "${PROJECT_SOURCE_DIR}/steamworks_c_wrapper/sdk") + MESSAGE ( STATUS "Steam SDK located, Steam build enabled") + set(STEAM 1) +else () + MESSAGE ( STATUS "Steam SDK not found, Steam build disabled") +endif() + +if (STEAM) + add_subdirectory(steamworks_c_wrapper) +endif() + if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") set(CLANG 1) elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") @@ -54,22 +65,22 @@ IF ( MSVC ) MESSAGE ( STATUS "Setting MSVC MT switches") SET ( CMAKE_C_FLAGS_DEBUG - "${CMAKE_CXX_FLAGS_DEBUG} /MTd" + "${CMAKE_C_FLAGS_DEBUG} /MTd" CACHE STRING "MSVC MT flags " FORCE ) SET ( CMAKE_C_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} /MT" + "${CMAKE_C_FLAGS_RELEASE} /MT" CACHE STRING "MSVC MT flags " FORCE ) ELSEIF ( WIN32 ) SET ( CMAKE_C_FLAGS_DEBUG - "${CMAKE_CXX_FLAGS_DEBUG} -mconsole" + "${CMAKE_C_FLAGS_DEBUG} -mconsole" ) SET ( CMAKE_C_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} -mwindows" + "${CMAKE_C_FLAGS_RELEASE} -mwindows" ) ENDIF () IF ( GCC OR CLANG ) @@ -93,6 +104,13 @@ else () ) endif () +if (STEAM) + include_directories( + ${STEAMWORKS_INCLUDE_DIR} + steamworks_c_wrapper/src + ) +endif () + include_directories( ${PROJECT_BINARY_DIR} ${LUA_INCLUDE_DIR} @@ -123,12 +141,24 @@ if (NOT MSVC) endif (NOT MSVC) set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") +if (STEAM) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSTEAM_BUILD") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DSTEAM_BUILD") +endif () if (NOT MSVC) set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D__FNAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") else (NOT MSVC) set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D__FNAME__=__FILE__") endif (NOT MSVC) +if (STEAM) + set(STEAM_SOURCES + src/steam/steamworks_api_wrapper + ) +else () + set(STEAM_SOURCES "") +endif () + # PROGRAMS: add_executable(breakhack src/main @@ -180,6 +210,7 @@ add_executable(breakhack src/object src/gui_util src/tooltip + ${STEAM_SOURCES} ) # Sqlite has some warnings that I we don't need to see @@ -195,6 +226,12 @@ target_link_libraries(breakhack ${SDL2_MIXER_LIBRARY} ) +if (STEAM) + target_link_libraries(breakhack + steamworks_c_wrapper + ) +endif () + if (NOT PHYSFS_FOUND) target_link_libraries(breakhack physfs-static @@ -287,6 +324,7 @@ SET(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT "Release") SET(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ".") if (WIN32) SET(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS + ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} ${CMAKE_SOURCE_DIR}/bin/libFLAC-8.dll ${CMAKE_SOURCE_DIR}/bin/libfreetype-6.dll ${CMAKE_SOURCE_DIR}/bin/libmodplug-1.dll @@ -301,6 +339,13 @@ if (WIN32) ${CMAKE_SOURCE_DIR}/bin/SDL2_ttf.dll ${CMAKE_SOURCE_DIR}/bin/zlib1.dll ) + if (STEAM) + SET(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS + ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} + steamworks_c_wrapper/sdk/redistributable_bin/steam_api.dll + build/steam/steam_appid.txt + ) + endif () endif (WIN32) include(InstallRequiredSystemLibraries) @@ -323,11 +368,15 @@ set(CPACK_PACKAGE_VERSION_MAJOR ${breakhack_MAJOR_VERSION}) set(CPACK_PACKAGE_VERSION_MINOR ${breakhack_MINOR_VERSION}) set(CPACK_PACKAGE_VERSION_PATCH ${breakhack_PATCH_VERSION}) set(CPACK_PACKAGE_INSTALL_DIRECTORY "BreakHack") -set(CPACK_PACKAGE_FILE_NAME "breakhack-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") +if (WIN32) + set(CPACK_PACKAGE_FILE_NAME "breakhack-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}-win32") +else () + set(CPACK_PACKAGE_FILE_NAME "breakhack-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") +endif () set(CPACK_PACKAGE_CHECKSUM "MD5") if(UNIX) - set(CPACK_GENERATOR STGZ TGZ TZ) + set(CPACK_GENERATOR TGZ) set(CPACK_STRIP_FILES breakhack) set(CPACK_SOURCE_STRIP_FILES "") elseif(WIN32) diff --git a/data/trapgen.lua b/data/trapgen.lua index 8edbd1c..8e47892 100644 --- a/data/trapgen.lua +++ b/data/trapgen.lua @@ -31,6 +31,7 @@ function module.add_traps_to_room(room) end local count = random(4) + local attempts = 0; local i = 0 while i < count do local rx = random(13) + 1 @@ -55,6 +56,8 @@ function module.add_traps_to_room(room) i = i + 1 end end + attempts = attempts + 1 + if attempts > 100 then break end end end diff --git a/src/defines.h b/src/defines.h index d7db9f7..c465c0f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -84,6 +84,8 @@ typedef int16_t Sint16; typedef uint16_t Uint16; typedef int32_t Sint32; typedef uint32_t Uint32; +typedef int64_t Sint64; +typedef uint64_t Uint64; typedef enum Direction_t { UP, DOWN, LEFT, RIGHT diff --git a/src/input.c b/src/input.c index cb8182d..9625d83 100644 --- a/src/input.c +++ b/src/input.c @@ -109,6 +109,8 @@ get_event_modkey(SDL_Event *event) key = KEY_CTRL_M; break; case SDLK_d: key = KEY_CTRL_D; break; + case SDLK_f: + key = KEY_CTRL_F; break; } } else if (event->key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) { switch (event->key.keysym.sym) { @@ -122,8 +124,6 @@ get_event_modkey(SDL_Event *event) key = KEY_SHIFT_NUM4; break; case SDLK_5: key = KEY_SHIFT_NUM5; break; - default: - key = 0; break; } } return key; diff --git a/src/input.h b/src/input.h index 78e3f1b..f08b438 100644 --- a/src/input.h +++ b/src/input.h @@ -47,6 +47,7 @@ #define KEY_SHIFT_NUM3 0x20 #define KEY_SHIFT_NUM4 0x40 #define KEY_SHIFT_NUM5 0x80 +#define KEY_CTRL_F 0x100 #define MBUTTON_LEFT 1 #define MBUTTON_MIDDLE 2 diff --git a/src/main.c b/src/main.c index a6264db..c4cf3da 100644 --- a/src/main.c +++ b/src/main.c @@ -22,7 +22,6 @@ #include #include #include - #include "linkedlist.h" #include "player.h" #include "screenresolution.h" @@ -54,6 +53,10 @@ #include "io_util.h" #include "tooltip.h" +#ifdef STEAM_BUILD +#include "steam/steamworks_api_wrapper.h" +#endif // STEAM_BUILD + static char *artifacts_tooltip[] = { "CONGRATULATIONS!", "", @@ -96,19 +99,21 @@ static char *skills_tooltip[] = { static char *how_to_play_tooltip[] = { "HOW TO PLAY", "", - " NAVIGATION: Use ARROWS or WASD or HJKL to move", + " NAVIGATION: Use ARROWS or WASD or HJKL to move", "", - " ATTACK: Walk into a monster to attack it", + " ATTACK: Walk into a monster to attack it", "", - " THROW DAGGER: Press 4 then chose a direction (navigation keys)", + " THROW DAGGER: Press 4 then chose a direction (nav keys)", "", - " DRINK HEALTH: Press 5 (if you need health and have potions)", + " DRINK HEALTH: Press 5 (if you need health and have potions)", "", - " TOGGLE MUSIC: CTRL + M", + " TOGGLE MUSIC: CTRL + M", "", - " TOGGLE SOUND: CTRL + S", + " TOGGLE SOUND: CTRL + S", "", - " TOGGLE MENU: ESC", + " TOGGLE FULLSCREEN: CTRL + F", + "", + " TOGGLE MENU: ESC", "", " Your stats and inventory are listed in the right panel", "", @@ -149,6 +154,7 @@ static float deltaTime = 1.0; static double renderScale = 1.0; static Turn currentTurn = PLAYER; static GameState gGameState; +static SDL_Rect mainViewport; static SDL_Rect gameViewport; static SDL_Rect skillBarViewport; static SDL_Rect bottomGuiViewport; @@ -247,26 +253,30 @@ bool initSDL(void) } static void -initViewports(void) +initViewports(Uint32 offset) { - gameViewport = (SDL_Rect) { 0, 0, + mainViewport = (SDL_Rect) { offset, 0, + SCREEN_WIDTH, SCREEN_HEIGHT + }; + + gameViewport = (SDL_Rect) { offset, 0, GAME_VIEW_WIDTH, GAME_VIEW_HEIGHT }; - skillBarViewport = (SDL_Rect) { 0, GAME_VIEW_HEIGHT, + skillBarViewport = (SDL_Rect) { offset, GAME_VIEW_HEIGHT, SKILL_BAR_WIDTH, SKILL_BAR_HEIGHT }; - bottomGuiViewport = (SDL_Rect) { 0, GAME_VIEW_HEIGHT + SKILL_BAR_HEIGHT, + bottomGuiViewport = (SDL_Rect) { offset, GAME_VIEW_HEIGHT + SKILL_BAR_HEIGHT, BOTTOM_GUI_WIDTH, BOTTOM_GUI_WIDTH }; - statsGuiViewport = (SDL_Rect) { GAME_VIEW_WIDTH, 0, + statsGuiViewport = (SDL_Rect) { offset + GAME_VIEW_WIDTH, 0, RIGHT_GUI_WIDTH, STATS_GUI_HEIGHT }; - minimapViewport = (SDL_Rect) { GAME_VIEW_WIDTH, STATS_GUI_HEIGHT, + minimapViewport = (SDL_Rect) { offset + GAME_VIEW_WIDTH, STATS_GUI_HEIGHT, RIGHT_GUI_WIDTH, MINIMAP_GUI_HEIGHT }; menuViewport = (SDL_Rect) { - (SCREEN_WIDTH - GAME_VIEW_WIDTH)/2, - (SCREEN_HEIGHT - GAME_VIEW_HEIGHT)/2, + offset + ((SCREEN_WIDTH - GAME_VIEW_WIDTH) >> 1), + (SCREEN_HEIGHT - GAME_VIEW_HEIGHT) >> 1, GAME_VIEW_WIDTH, GAME_VIEW_HEIGHT }; @@ -275,7 +285,7 @@ initViewports(void) static bool initGame(void) { - initViewports(); + initViewports(0); input_init(&input); texturecache_init(gRenderer); gCamera = camera_create(gRenderer); @@ -520,6 +530,10 @@ init(void) return false; } +#ifdef STEAM_BUILD + steam_init(); +#endif // STEAM_BUILD + settings_init(); hiscore_init(); initMainMenu(); @@ -535,6 +549,34 @@ init(void) return true; } +static void +toggle_fullscreen(void) +{ + bool isFullscreen = SDL_GetWindowFlags(gWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP; + Settings *settings = settings_get(); + if (isFullscreen) { + initViewports(0); + SDL_SetWindowFullscreen(gWindow, 0); + settings->fullscreen_enabled = false; + } + else { + int w, h, lw, lh; + SDL_RenderGetLogicalSize(gRenderer, &lw, &lh); + SDL_GetWindowSize(gWindow, &w, &h); + + double lratio = (double) w / (double) lw; + + SDL_SetWindowFullscreen(gWindow, SDL_WINDOW_FULLSCREEN_DESKTOP); + + SDL_DisplayMode dMode; + SDL_GetWindowDisplayMode(gWindow, &dMode); + double ratio = (double) (dMode.w) / w; + double offset = ((dMode.w - w) / 2); + initViewports((Uint32)(offset/(ratio*lratio))); + settings->fullscreen_enabled = true; + } +} + static void handle_main_input(void) { @@ -578,6 +620,10 @@ handle_main_input(void) else gui_log("Tooltips disabled"); } + + if (input_modkey_is_pressed(&input, KEY_CTRL_F)) { + toggle_fullscreen(); + } } static bool @@ -611,9 +657,6 @@ 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; } @@ -625,6 +668,7 @@ end_game_details(void) { gui_log("You earned %.2f gold", gPlayer->gold); gui_event_message("You earned %.2f gold", gPlayer->gold); + if (hiscore_get_top_gold() < gPlayer->gold) { gui_event_message("NEW HIGHSCORE"); gui_log("NEW HIGHSCORE"); @@ -698,9 +742,10 @@ run_game_update(void) if (skillActivated && settings->tooltips_enabled && playerLevel < 5) { gGui->activeTooltip = new_skill_tooltip; } - if (!artifactTooltipShown && gPlayer->equipment.hasArtifacts && settings->tooltips_enabled) { + if (!artifactTooltipShown && gPlayer->equipment.hasArtifacts) { artifactTooltipShown = true; - gGui->activeTooltip = new_artifact_tooltip; + if (settings->tooltips_enabled) + gGui->activeTooltip = new_artifact_tooltip; } if (gGameState == PLAYING && currentTurn == PLAYER) @@ -747,7 +792,7 @@ render_gui(void) skillbar_render(gSkillBar, gPlayer, gCamera); SDL_RenderSetViewport(gRenderer, &bottomGuiViewport); gui_render_log(gGui, gCamera); - SDL_RenderSetViewport(gRenderer, NULL); + SDL_RenderSetViewport(gRenderer, &mainViewport); } static void @@ -806,6 +851,7 @@ run_game_render(void) render_game(); render_gui(); + SDL_RenderSetViewport(gRenderer, &mainViewport); particle_engine_render_global(gCamera); gui_render_tooltip(gGui, gCamera); @@ -847,6 +893,10 @@ run_game(void) gGameState = GAME_OVER; createInGameGameOverMenu(); hiscore_register(gPlayer, cLevel); +#ifdef STEAM_BUILD + steam_register_score((int)hiscore_get_top_gold()); + steam_register_kills((int) gPlayer->stat_data.kills); +#endif // STEAM_BUILD } else { check_next_level(); @@ -859,6 +909,9 @@ run_game(void) gui_log("Your break is over!"); gui_event_message("Well done!"); end_game_details(); +#ifdef STEAM_BUILD + steam_set_achievement(BACK_TO_WORK); +#endif // STEAM_BUILD } } @@ -888,7 +941,7 @@ run_menu(void) map_render_top_layer(gMap, gRoomMatrix, gCamera); roommatrix_render_lightmap(gRoomMatrix, gCamera); - SDL_RenderSetViewport(gRenderer, NULL); + SDL_RenderSetViewport(gRenderer, &mainViewport); if (gGameState == MENU) menu_render(mainMenu, gCamera); @@ -933,6 +986,10 @@ run(void) pointer_handle_input(gPointer, &input); #endif // DEBUG +#ifdef STEAM_BUILD + steam_run_callbacks(); +#endif // STEAM_BUILD + switch (gGameState) { case PLAYING: case IN_GAME_MENU: @@ -1019,6 +1076,10 @@ void close(void) settings_close(); hiscore_close(); +#ifdef STEAM_BUILD + steam_shutdown(); +#endif // STEAM_BUILD + SDL_DestroyRenderer(gRenderer); SDL_DestroyWindow(gWindow); gWindow = NULL; @@ -1043,6 +1104,11 @@ int main(int argc, char *argv[]) if (!init()) return 1; + if (settings_get()->fullscreen_enabled) { + // Game starts in windowed mode so this will + // change to fullscreen + toggle_fullscreen(); + } run(); close(); PHYSFS_deinit(); diff --git a/src/player.c b/src/player.c index 1e9f6e3..9be7a7b 100644 --- a/src/player.c +++ b/src/player.c @@ -36,6 +36,10 @@ #include "animation.h" #include "trap.h" +#ifdef STEAM_BUILD +#include "steam/steamworks_api_wrapper.h" +#endif // STEAM_BUILD + #define ENGINEER_STATS { 12, 12, 5, 7, 2, 2, 1, false, false } #define MAGE_STATS { 12, 12, 5, 7, 1, 2, 1, false, false } #define PALADIN_STATS { 12, 12, 8, 9, 3, 1, 1, false, false } @@ -141,7 +145,8 @@ on_monster_collision(Player *player, if (get_random(10) < player_has_artifact(player, FEAR_INDUCING)) { gui_log("%s shivers with fear at the sight of you", monster->label); - monster_set_state(monster, SCARED, 3); + if (monster->state.current != STUNNED) + monster_set_state(monster, SCARED, 3); } } @@ -203,8 +208,7 @@ has_collided(Player *player, RoomMatrix *matrix, Vector2d direction) } if (space->lethal && !collided) { - mixer_play_effect(FALL0 + get_random(2) - 1); - player->state = FALLING; + player_set_falling(player); } if (space->trap && !collided) { @@ -514,6 +518,17 @@ player_monster_kill_check(Player *player, Monster *monster) if (!monster) return; +#ifdef STEAM_BUILD + if (strcmp("The Shadow", monster->label) == 0) + steam_set_achievement(LIGHTS_ON); + else if (strcmp("The Hell Hound", monster->label) == 0) + steam_set_achievement(BAD_DOG); + else if (strcmp("Platino", monster->label) == 0) + steam_set_achievement(DRAGON_SLAYER); + else if (strcmp("The Cleric", monster->label) == 0) + steam_set_achievement(THE_DOCTOR_IS_OUT); +#endif // STEAM_BUILD + if (monster->stats.hp <= 0) { unsigned int gained_xp = 5 * monster->stats.lvl; player->stat_data.kills += 1; @@ -681,3 +696,10 @@ player_add_artifact(Player *p, Artifact *a) gui_log("%s (%u)", ad->desc, ad->level); p->equipment.hasArtifacts = true; } + +void +player_set_falling(Player *player) +{ + mixer_play_effect(FALL0 + get_random(2) - 1); + player->state = FALLING; +} diff --git a/src/player.h b/src/player.h index 07d970d..d3a9765 100644 --- a/src/player.h +++ b/src/player.h @@ -123,3 +123,6 @@ player_has_artifact(Player *, MagicalEffect); void player_add_artifact(Player*, Artifact*); + +void +player_set_falling(Player*); diff --git a/src/screen.c b/src/screen.c index 4781535..7ebdb31 100644 --- a/src/screen.c +++ b/src/screen.c @@ -95,6 +95,7 @@ screen_create_credits(SDL_Renderer *renderer) linkedlist_push(&screen->sprites, credit_txt("ArtisticDuded", C_WHITE, x + columnOffset, y, renderer)); y += 20; linkedlist_push(&screen->sprites, credit_txt("opengameart.org/users/artisticdude", C_WHITE, x + columnOffset, y, renderer)); + linkedlist_push(&screen->sprites, score_txt("Press ESC to go back", C_RED, 15, SCREEN_HEIGHT - 25, renderer)); return screen; } @@ -164,6 +165,7 @@ screen_create_hiscore(SDL_Renderer *renderer) renderer)); hiscore_destroy(score); } + linkedlist_push(&screen->sprites, score_txt("Press ESC to go back", C_RED, 15, SCREEN_HEIGHT - 25, renderer)); return screen; } diff --git a/src/settings.c b/src/settings.c index 489e1b1..1c4f13f 100644 --- a/src/settings.c +++ b/src/settings.c @@ -31,6 +31,7 @@ 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 const char *KEY_FULLSCREEN_ENABLED = "fullscreen_enabled"; static DbQuery MIGRATE_COMMANDS[] = { @@ -53,6 +54,7 @@ set_default_settings(void) settings.sound_enabled = true; settings.tooltips_enabled = true; settings.howto_tooltip_shown = false; + settings.fullscreen_enabled = false; } static void @@ -90,6 +92,10 @@ load_settings_cb(void *unused, int count, char **values, char **colNames) settings.howto_tooltip_shown = (bool)atoi(values[i + 1]); i += 2; } + else if (!strcmp(KEY_FULLSCREEN_ENABLED, values[i])) { + settings.fullscreen_enabled = (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; @@ -141,6 +147,7 @@ settings_save(void) 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); + save_setting_int(KEY_FULLSCREEN_ENABLED, settings.fullscreen_enabled); } Settings * diff --git a/src/settings.h b/src/settings.h index 91d5a25..14f197e 100644 --- a/src/settings.h +++ b/src/settings.h @@ -26,6 +26,7 @@ typedef struct Settings { bool sound_enabled; bool tooltips_enabled; bool howto_tooltip_shown; + bool fullscreen_enabled; } Settings; void diff --git a/src/skill.c b/src/skill.c index b512d0b..cd77d7d 100644 --- a/src/skill.c +++ b/src/skill.c @@ -393,7 +393,7 @@ skill_charge_check_path(SkillData *data, Monster *monster = matrix->spaces[itPos.x][itPos.y].monster; Stats tmpStats = player->stats; tmpStats.dmg *= steps > 0 ? steps : 1; - mixer_play_effect(SWING0 + get_random(3) - 1); + mixer_play_effect(SWING0 + get_random(2)); unsigned int dmg = stats_fight(&tmpStats, &monster->stats); if (dmg > 0) { gui_log("You charged %s for %u damage", monster->lclabel, dmg); @@ -492,6 +492,13 @@ skill_charge(Skill *skill, SkillData *data) skill_charge_check_path(data, playerStartPos, destination); + Position lastTilePos = position_to_matrix_coords(&playerDestinationPos); + RoomSpace *destSpace = &matrix->spaces[lastTilePos.x][lastTilePos.y]; + if (destSpace->lethal) + player_set_falling(player); + else if (destSpace->trap) + trap_activate(destSpace->trap, player); + return true; } diff --git a/src/steam/steamworks_api_wrapper.c b/src/steam/steamworks_api_wrapper.c new file mode 100644 index 0000000..716cdde --- /dev/null +++ b/src/steam/steamworks_api_wrapper.c @@ -0,0 +1,126 @@ +#include +#include +#include "steamworks_api_wrapper.h" +#include "steamworks_c_wrapper.h" +#include "../util.h" +#include "../defines.h" +#include "../gui.h" +#include "../timer.h" + +static const char *LB_HIGHSCORE = "Highscore"; +static const char *LB_KILLS = "Most Kills"; + +static Achievement g_Achievements[] = { + _ACH_ID(BAD_DOG, "Bad Dog"), + _ACH_ID(THE_DOCTOR_IS_OUT, "The Doctor is Out"), + _ACH_ID(LIGHTS_ON, "Omnidirectional light"), + _ACH_ID(BACK_TO_WORK, "Back to work"), + _ACH_ID(DRAGON_SLAYER, "Platinum dragon slayer") +}; +static Uint8 numAchievements = 5; + +static bool m_Initiated = false; +static bool m_bStatsReceived = false; +static Sint64 m_AppID = 0; +static Sint64 m_hHighscoreLeaderboard = 0; +static Sint64 m_hKillsLeaderboard = 0; + +static Timer *requestDataTimer = NULL; + +static bool +steam_request_stats(void) +{ + if (m_Initiated) + return c_SteamUserStats_RequestCurrentStats(); + return false; +} + +static void +stats_received(void) +{ + debug("Steam stats received"); + m_bStatsReceived = true; +} + +static void +stats_stored(void) +{ + debug("Steam stats stored"); +} + +static void +leaderboard_received(Sint64 hLeaderboard, const char *name) +{ + debug("Leaderboard received: %s", name); + if (strcmp(LB_HIGHSCORE, name) == 0) + m_hHighscoreLeaderboard = hLeaderboard; + else if (strcmp(LB_KILLS, name) == 0) + m_hKillsLeaderboard = hLeaderboard; +} + +void +steam_init() +{ + m_AppID = c_SteamAPI_Init(); + m_Initiated = m_AppID != 0; + if (m_Initiated) + c_SteamAPI_SetCallbacks(stats_received, stats_stored, leaderboard_received); + requestDataTimer = timer_create(); +} + +void steam_shutdown(void) +{ + c_SteamAPI_Shutdown(); + timer_destroy(requestDataTimer); +} + +static void +request_data_queue_run(void) +{ + if (!timer_started(requestDataTimer)) + timer_start(requestDataTimer); + + if (timer_get_ticks(requestDataTimer) > 1000) { + if (!m_bStatsReceived) + steam_request_stats(); + else if (!m_hHighscoreLeaderboard) + c_SteamUserStats_FindLeaderboard(LB_HIGHSCORE); + else if (!m_hKillsLeaderboard) + c_SteamUserStats_FindLeaderboard(LB_KILLS); + + timer_start(requestDataTimer); + } +} + +void steam_run_callbacks(void) +{ + if (m_Initiated) { + c_SteamAPI_RunCallbacks(); + request_data_queue_run(); + } +} + +void steam_set_achievement(EAchievement eAch) +{ + for (Uint8 i = 0; i < numAchievements; ++i) { + Achievement *a = &g_Achievements[i]; + if (a->m_eAchievementID == eAch && !a->m_bAchieved) { + c_SteamUserStats_SetAchievement(g_Achievements[i].m_pchAchievementID); + gui_log("You just earned the \"%s\" achievement", a->m_rgchName); + } + } +} + +void steam_register_score(Sint32 nScore) +{ + if (!m_hHighscoreLeaderboard) + return; + c_SteamUserStats_UploadLeaderboardScore(m_hHighscoreLeaderboard, nScore); +} + +void steam_register_kills(Sint32 nKills) +{ + if (!m_hKillsLeaderboard) + return; + c_SteamUserStats_UploadLeaderboardScore(m_hKillsLeaderboard, nKills); +} diff --git a/src/steam/steamworks_api_wrapper.h b/src/steam/steamworks_api_wrapper.h new file mode 100644 index 0000000..52ec293 --- /dev/null +++ b/src/steam/steamworks_api_wrapper.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include "../defines.h" + +typedef enum EAchievement +{ + BAD_DOG = 0, + THE_DOCTOR_IS_OUT = 1, + LIGHTS_ON = 2, + BACK_TO_WORK = 5, + DRAGON_SLAYER = 6 +} EAchievement; + + +#define _ACH_ID( id, name ) { id, #id, name, "", 0, 0 } +typedef struct Achievement { + EAchievement m_eAchievementID; + const char *m_pchAchievementID; + char m_rgchName[128]; + char m_rgchDescription[256]; + bool m_bAchieved; + int m_iIconImage; +} Achievement; + +void steam_init(void); + +void steam_shutdown(void); + +void steam_run_callbacks(void); + +void steam_set_achievement(EAchievement eAch); + +void steam_register_score(Sint32 nScore); + +void steam_register_kills(Sint32 nKills); diff --git a/steamworks_c_wrapper/CMakeLists.txt b/steamworks_c_wrapper/CMakeLists.txt new file mode 100644 index 0000000..f948ab6 --- /dev/null +++ b/steamworks_c_wrapper/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.1) +project(steamworks_c_wrapper) + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +include(cmake/FindSTEAMWORKS.cmake) + +if (BIT_32) + MESSAGE("COMPILING 32 BIT") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -m32") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_DEBUG} -m32") +endif() + +set (Windows 0) +set (Apple 0) +if (WIN32) + set(Windows 1) +elseif (APPLE) + set(Apple 1) +else() + #Linux +endif () + +include_directories(${STEAMWORKS_INCLUDE_DIR}) + +if (WIN32) + add_library(steamworks_c_wrapper + src/steamworks_c_wrapper + src/CallbackHandler + ) +else () + add_library(steamworks_c_wrapper + SHARED + src/steamworks_c_wrapper + src/CallbackHandler + ) +endif() + +target_link_libraries(steamworks_c_wrapper ${STEAMWORKS_LIBRARY}) + +IF ( MSVC ) + MESSAGE ( STATUS "Setting MSVC MT switches") + SET ( + CMAKE_CXX_FLAGS_DEBUG + "${CMAKE_CXX_FLAGS_DEBUG} /MTd" + CACHE STRING "MSVC MT flags " FORCE + ) + SET ( + CMAKE_CXX_FLAGS_RELEASE + "${CMAKE_CXX_FLAGS_RELEASE} /MT" + CACHE STRING "MSVC MT flags " FORCE + ) +endif () diff --git a/steamworks_c_wrapper/cmake/FindSTEAMWORKS.cmake b/steamworks_c_wrapper/cmake/FindSTEAMWORKS.cmake new file mode 100644 index 0000000..87b6fd3 --- /dev/null +++ b/steamworks_c_wrapper/cmake/FindSTEAMWORKS.cmake @@ -0,0 +1,32 @@ +# - Try to find the steamworks library +# +# Once done, this will define: +# +# STEAMWORKS_INCLUDE_DIR - the Steamworks include directory +# STEAMWORKS_LIBRARIES - The libraries needed to use Steamworks + +find_path(STEAMWORKS_INCLUDE_DIR + NAMES + steam_api.h + PATHS + ${PROJECT_SOURCE_DIR}/sdk/public/steam/ +) + +if (WIN32) + find_library(STEAMWORKS_LIBRARY + NAMES + steam_api + PATHS + ${PROJECT_SOURCE_DIR}/sdk/redistributable_bin/ + ) +else() + find_library(STEAMWORKS_LIBRARY + NAMES + steam_api + PATHS + ${PROJECT_SOURCE_DIR}/sdk/redistributable_bin/linux64/ + ) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(STEAMWORKS DEFAULT_MSG STEAMWORKS_INCLUDE_DIR STEAMWORKS_LIBRARY) diff --git a/steamworks_c_wrapper/src/CallbackHandler.cpp b/steamworks_c_wrapper/src/CallbackHandler.cpp new file mode 100644 index 0000000..2750955 --- /dev/null +++ b/steamworks_c_wrapper/src/CallbackHandler.cpp @@ -0,0 +1,44 @@ +#include "CallbackHandler.h" + +CallbackHandler::CallbackHandler(int64 appId) : + m_CallbackUserStatsReceived(this, &CallbackHandler::OnUserStatsReceived), + m_CallbackUserStatsStored(this, &CallbackHandler::OnUserStatsStored), + m_AppId(appId) +{ + // Nothing +} + +void +CallbackHandler::OnUserStatsReceived(UserStatsReceived_t *pCallback) +{ + if (m_AppId != pCallback->m_nGameID) + return; + + m_bStatsCallbackReceived = true; + if (statsReceivedCb && k_EResultOK == pCallback->m_eResult) + statsReceivedCb(); +} + +void +CallbackHandler::OnUserStatsStored(UserStatsStored_t *pCallback) +{ + if (m_AppId != pCallback->m_nGameID) + return; + + if (statsStoredCb && k_EResultOK == pCallback->m_eResult) + statsStoredCb(); +} + +bool CallbackHandler::CallbackReceived() const +{ + return m_bStatsCallbackReceived; +} + +void CallbackHandler::OnFindLeaderboard(LeaderboardFindResult_t * pCallback, bool bIOFailiure) +{ + if (bIOFailiure || !pCallback->m_bLeaderboardFound) + return; + + if (leaderboardReceivedCb) + leaderboardReceivedCb(pCallback->m_hSteamLeaderboard, SteamUserStats()->GetLeaderboardName(pCallback->m_hSteamLeaderboard)); +} \ No newline at end of file diff --git a/steamworks_c_wrapper/src/CallbackHandler.h b/steamworks_c_wrapper/src/CallbackHandler.h new file mode 100644 index 0000000..1cb8ebc --- /dev/null +++ b/steamworks_c_wrapper/src/CallbackHandler.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +class CallbackHandler +{ +private: + int64 m_AppId = 0; + bool m_bStatsCallbackReceived = false; + +public: + CallbackHandler(int64 appId); + STEAM_CALLBACK(CallbackHandler, OnUserStatsReceived, UserStatsReceived_t, m_CallbackUserStatsReceived); + STEAM_CALLBACK(CallbackHandler, OnUserStatsStored, UserStatsStored_t, m_CallbackUserStatsStored); + CCallResult m_FindLeaderboardCallResult; + + void(*statsReceivedCb)() = nullptr; + void(*statsStoredCb)() = nullptr; + void(*leaderboardReceivedCb)(int64_t, const char*) = nullptr; + + bool CallbackReceived() const; + + void OnFindLeaderboard(LeaderboardFindResult_t *pCallback, bool bIOFailiure); +}; diff --git a/steamworks_c_wrapper/src/steamworks_c_wrapper.cpp b/steamworks_c_wrapper/src/steamworks_c_wrapper.cpp new file mode 100644 index 0000000..3123c4f --- /dev/null +++ b/steamworks_c_wrapper/src/steamworks_c_wrapper.cpp @@ -0,0 +1,108 @@ +#include + +extern "C" { +#include "steamworks_c_wrapper.h" +} +#include "CallbackHandler.h" + +static bool m_Initiated = false; +static int64 m_AppId = 0; +static CallbackHandler *m_CallbackHandler = NULL; + +extern "C" int64_t +c_SteamAPI_Init() +{ + m_CallbackHandler = new CallbackHandler(m_AppId); + if (SteamAPI_Init()) { + m_AppId = SteamUtils()->GetAppID(); + m_Initiated = true; + return m_AppId; + } + return 0; +} + +extern "C" int64_t +c_SteamAPI_GetAppID() +{ + if (!m_Initiated) + return 0; + m_AppId = SteamUtils()->GetAppID(); + return m_AppId; +} + +void +c_SteamAPI_RunCallbacks(void) +{ + if (m_Initiated) + SteamAPI_RunCallbacks(); +} + +extern "C" void c_SteamAPI_SetCallbacks(void(*recvCB)(void), void(*storCB)(void), void(*recvLB)(int64_t, const char *)) +{ + m_CallbackHandler->statsReceivedCb = recvCB; + m_CallbackHandler->statsStoredCb = storCB; + m_CallbackHandler->leaderboardReceivedCb = recvLB; +} + +extern "C" void +c_SteamAPI_Shutdown() +{ + delete m_CallbackHandler; + SteamAPI_Shutdown(); +} + +extern "C" bool +c_SteamUserStats_RequestCurrentStats() +{ + if (NULL == SteamUserStats() || NULL == SteamUser()) + return false; + if (!SteamUser()->BLoggedOn()) + return false; + + return SteamUserStats()->RequestCurrentStats(); +} + +extern "C" bool +c_SteamUserStats_SetAchievement(const char *pchName) +{ + if (m_CallbackHandler && !m_CallbackHandler->CallbackReceived()) + return false; + + bool result = SteamUserStats()->SetAchievement(pchName); + if (result) + SteamUserStats()->StoreStats(); + return result; +} + +extern "C" void +c_SteamUserStats_GetAchievement(const char *achId, bool *achieved) +{ + if (!m_Initiated) + return; + + SteamUserStats()->GetAchievement(achId, achieved); +} + +extern "C" const char* +c_SteamUserStats_GetAchievementDisplayAttribute(const char *achId, const char *attrName) +{ + return SteamUserStats()->GetAchievementDisplayAttribute(achId, attrName); +} + +extern "C" void +c_SteamUserStats_FindLeaderboard(const char * name) +{ + if (!m_Initiated || !m_CallbackHandler) + return; + + SteamAPICall_t hSteamAPICall = SteamUserStats()->FindLeaderboard(name); + m_CallbackHandler->m_FindLeaderboardCallResult.Set(hSteamAPICall, m_CallbackHandler, &CallbackHandler::OnFindLeaderboard); +} + +extern "C" void c_SteamUserStats_UploadLeaderboardScore(int64_t hLeaderboard, int32_t nScore) +{ + if (!hLeaderboard || !m_Initiated) + return; + + SteamUserStats()->UploadLeaderboardScore(hLeaderboard, k_ELeaderboardUploadScoreMethodKeepBest, nScore, nullptr, 0); +} diff --git a/steamworks_c_wrapper/src/steamworks_c_wrapper.h b/steamworks_c_wrapper/src/steamworks_c_wrapper.h new file mode 100644 index 0000000..54b2a7c --- /dev/null +++ b/steamworks_c_wrapper/src/steamworks_c_wrapper.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +int64_t +c_SteamAPI_Init(void); + +int64_t +c_SteamAPI_GetAppID(void); + +void +c_SteamAPI_RunCallbacks(void); + +void +c_SteamAPI_SetCallbacks(void(*recvCB)(void), void(*storCB)(void), void(*recvLB)(int64_t, const char *)); + +bool +c_SteamUserStats_RequestCurrentStats(void); + +bool +c_SteamUserStats_SetAchievement(const char *id); + +void +c_SteamUserStats_GetAchievement(const char *achId, bool *achieved); + +const char * +c_SteamUserStats_GetAchievementDisplayAttribute(const char *achId, const char *attrName); + +void +c_SteamUserStats_FindLeaderboard(const char *name); + +void +c_SteamUserStats_UploadLeaderboardScore(int64_t hLeaderboard, int32_t nScore); + +void +c_SteamAPI_Shutdown(void); \ No newline at end of file