From 5f383da62c7a80526634b68c28d7ba9d9e693e75 Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Wed, 7 May 2025 00:08:29 -0400 Subject: Create html shell wrapper for game --- .gitignore | 10 +++++ CMakeLists.txt | 35 ++++++++++++++++ starless/main.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vcpkg.json | 17 ++++++++ wrapper.html | 91 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 276 insertions(+) create mode 100644 .gitignore create mode 100644 starless/main.cpp create mode 100644 vcpkg.json create mode 100644 wrapper.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5de5580 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +assets/ +build/ +.cache/ + +*.exe +*.out +*.d +*.o + +*.swp diff --git a/CMakeLists.txt b/CMakeLists.txt index e69de29..a460e57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.19...4.0) + +option(BUILD_NATIVE "Compile for host toolchain instead of web" OFF) +if (NOT BUILD_NATIVE) + message("Compiling with emscripten...") + set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "$ENV{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake") + set(VCPKG_TARGET_TRIPLET "wasm32-emscripten") +endif() + +set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/vendor/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain") + +project(starless VERSION 0.1 LANGUAGES C CXX) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") + +file( + GLOB_RECURSE SOURCE_FILES + CONFIGURE_DEPENDS + ${PROJECT_SOURCE_DIR}/starless/*.cpp +) + +add_executable(${PROJECT_NAME} ${SOURCE_FILES}) +target_include_directories(${PROJECT_NAME} PRIVATE .) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) + +if (NOT BUILD_NATIVE) + target_link_options(${PROJECT_NAME} PRIVATE --preload-file "${CMAKE_CURRENT_SOURCE_DIR}/data@data" --shell-file "${CMAKE_CURRENT_SOURCE_DIR}/wrapper.html") + set_target_properties(${PROJECT_NAME} PROPERTIES SUFFIX ".html") +endif() + +find_package(SDL3 CONFIG REQUIRED) +find_package(Lua CONFIG REQUIRED) +find_package(libtcod CONFIG REQUIRED) +target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3 libtcod::libtcod ${LUA_LIBRARIES}) diff --git a/starless/main.cpp b/starless/main.cpp new file mode 100644 index 0000000..458b521 --- /dev/null +++ b/starless/main.cpp @@ -0,0 +1,123 @@ +#define SDL_MAIN_USE_CALLBACKS +#include +#include + +#include +#include +#include +#include + +/// Return the data directory. +auto get_data_dir() -> std::filesystem::path { + static auto root_directory = std::filesystem::path{"."}; // Begin at the working directory. + while (!std::filesystem::exists(root_directory / "data")) { + // If the current working directory is missing the data dir then it will assume it exists in any parent directory. + root_directory /= ".."; + if (!std::filesystem::exists(root_directory)) { + throw std::runtime_error("Could not find the data directory."); + } + } + return root_directory / "data"; +}; + +static constexpr auto WHITE = tcod::ColorRGB{255, 255, 255}; + +static tcod::Console g_console; // The global console object. +static tcod::Context g_context; // The global libtcod context. + +static int player_x{}; +static int player_y{}; + +// Called every frame +SDL_AppResult SDL_AppIterate(void*) { + g_console.clear(); + if (g_console.in_bounds({player_x, player_y})) { + g_console.at({player_x, player_y}).ch = '@'; + } + g_context.present(g_console); + return SDL_APP_CONTINUE; +} +// Handle events +SDL_AppResult SDL_AppEvent(void*, SDL_Event* event) { + switch (event->type) { + case SDL_EVENT_KEY_DOWN: + switch (event->key.key) { + case SDLK_LEFT: // Arrow key + case SDLK_H: // Vi key + case SDLK_KP_4: // Keypad + player_x -= 1; + break; + case SDLK_RIGHT: + case SDLK_L: + case SDLK_KP_6: + player_x += 1; + break; + case SDLK_UP: + case SDLK_K: + case SDLK_KP_8: + player_y -= 1; + break; + case SDLK_DOWN: + case SDLK_J: + case SDLK_KP_2: + player_y += 1; + break; + case SDLK_HOME: + case SDLK_Y: + case SDLK_KP_7: + player_x -= 1; + player_y -= 1; + break; + case SDLK_PAGEUP: + case SDLK_U: + case SDLK_KP_9: + player_x += 1; + player_y -= 1; + break; + case SDLK_END: + case SDLK_B: + case SDLK_KP_1: + player_x -= 1; + player_y += 1; + break; + case SDLK_PAGEDOWN: + case SDLK_N: + case SDLK_KP_3: + player_x += 1; + player_y += 1; + break; + case SDLK_PERIOD: + case SDLK_CLEAR: + case SDLK_KP_5: + break; + } + break; + case SDL_EVENT_QUIT: + return SDL_APP_SUCCESS; + } + return SDL_APP_CONTINUE; +} +// Main entry point +SDL_AppResult SDL_AppInit(void**, int argc, char** argv) { + auto params = TCOD_ContextParams{}; + params.argc = argc; + params.argv = argv; + params.renderer_type = TCOD_RENDERER_SDL2; + params.vsync = 1; + params.sdl_window_flags = SDL_WINDOW_RESIZABLE; + params.window_title = "This Starless Sky - Paterissa"; + + auto tileset = tcod::load_tilesheet(get_data_dir() / "assets/dejavu16x16_gs_tc.png", {32, 8}, tcod::CHARMAP_TCOD); + params.tileset = tileset.get(); + + g_console = tcod::Console{80, 40}; + player_x = g_console.get_width() / 2; + player_y = g_console.get_height() / 2; + params.console = g_console.get(); + + g_context = tcod::Context(params); + + return SDL_APP_CONTINUE; +} +// Called before existing +void SDL_AppQuit(void*, SDL_AppResult) {} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..a5b8de9 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", + "dependencies": [ + { + "name": "libtcod", + "default-features": true, + "features": [ + "png", + "sdl", + "unicode", + "zlib" + ] + }, + "sdl3", + "lua" + ] +} diff --git a/wrapper.html b/wrapper.html new file mode 100644 index 0000000..0bd537b --- /dev/null +++ b/wrapper.html @@ -0,0 +1,91 @@ + + + + + + + + +
+

This Starless Sky

+

we are deserving of no gifts. +

+
+
+
+ +
+ + {{{ SCRIPT }}} + + + -- cgit v1.2.3