#pragma once // Client application: window, renderer, screens (title, join, character // creator, play) and the glue between NetClient, World and the HD-2D UI. #include "Common.h" #include "NetClient.h" #include "World.h" #include "hd2d/Camera.h" #include "hd2d/DebugUI.h" #include "hd2d/Renderer.h" #include "hd2d/Screenshot.h" #include "hd2d/UI.h" #include "hd2d/Window.h" #include #include #include #include namespace bs { struct Options { std::string screenshot; // capture to this PNG, then exit (hidden window) int frames = 120; // frames before the capture int width = 1600, height = 900; bool show = false; // visible window even when capturing std::string connect; // host[:port] to join right away bool host = false; // start a local server and join it uint16_t port = kDefaultPort; bool autoCreate = false; // skip the creator with a default look bool autoDialogue = false; // captures: advance dialogue automatically std::string screen; // "title" | "creator" capture start screen std::string profile; // identity file suffix (several clients on one machine) std::string name; // character name for --auto-create glm::vec2 move{0.0f}; // held movement for captures bool run = false; float yaw = 0.0f, dist = 0.0f; bool hasYaw = false; float hour = -1.0f; // title backdrop hour std::string weather; // title backdrop weather std::vector keys; // scripted key presses: ":" (space, e, f, tab) std::string look; // --look body,skin,hair,hat,top,bottom,shoes (creator capture) }; class App { public: explicit App(Options opt) : opt_(std::move(opt)) {} int run(); private: enum class Screen { Title, Join, Connecting, Creator, Play }; struct DialogueScript { std::vector> lines; // speaker, text }; bool init(); void shutdown(); void frame(float dt); void handleNet(); void updateCamera(float dt); // screens void drawTitle(ImVec2 vp); void drawJoin(ImVec2 vp); void drawConnecting(ImVec2 vp); void drawCreator(ImVec2 vp); void drawPlay(ImVec2 vp, float dt); void drawHud(ImVec2 vp); void drawLabels(ImVec2 vp); void drawCollection(ImVec2 vp); void drawChat(ImVec2 vp); void drawPause(ImVec2 vp); void playInput(float dt); void startDialogue(const std::string& script); void beginConnect(const std::string& host, uint16_t port); bool startLocalServer(); void stopLocalServer(); void returnToTitle(const std::string& message = {}); UiTexture* creatureIcon(uint16_t species); void refreshPreview(); bool pressed(int key) const; // game key (ignored while ImGui has the keyboard) bool scripted(const char* key) const; Options opt_; hd2d::Window window_; hd2d::Renderer renderer_; hd2d::DebugUI debugUi_; hd2d::OffscreenTarget offscreen_; bool capture_ = false; hd2d::Camera cam_; World world_; NetClient net_; Screen screen_ = Screen::Title; float time_ = 0.0f; int frame_ = 0; bool showDebug_ = false; float uiScale_ = 1.0f; // identity std::string token_, lastHost_ = "127.0.0.1", savedName_; uint16_t lastPort_ = kDefaultPort; void loadIdentity(); void saveIdentity(); // title / join int titleSel_ = 0; std::string message_; net::Scanner scanner_; std::vector found_; float scanTimer_ = 0.0f; char addressBuf_[128] = "127.0.0.1"; int serverPid_ = -1; float connectTimer_ = 0.0f; // creator Appearance look_; char nameBuf_[24] = ""; UiTexture preview_; int previewDir_ = 0; bool creating_ = false; // play hd2d::ui::DialogueBox dialogue_; std::string dialogueScript_; hd2d::ui::Toasts toasts_; std::map scripts_; UiTexture henryPortrait_; std::map> icons_; bool collectionOpen_ = false, pauseOpen_ = false, chatOpen_ = false; int collectionSel_ = 0, pauseSel_ = 0; char chatBuf_[128] = ""; bool chatFocus_ = false; float camYawTarget_ = 0.0f; glm::vec2 heldMove_{0.0f}; }; } // namespace bs