// // Created by rov on 12/27/25. // #include "gui.h" #include #include #include "dcimgui.h" #include "dcimgui_impl_sdl3.h" #include "dcimgui_impl_sdlrenderer3.h" #include "window.h" #include "config.h" #define BASE_BODY_SPRITE_ID 155 #define BASE_HEAD_SPRITE_ID 176 #define BASE_LEGS_SPRITE_ID 158 #define BASE_SHOES_SPRITE_ID 161 static SDL_Texture *cachedCharPreview = NULL; Character_t character = {}; void Gui_Init(Gui_t *gui) { ImGui_CreateContext(NULL); ImGuiIO *io = ImGui_GetIO(); io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; ImGui_StyleColorsLight(NULL); SDL_Window *window = Window_GetWindow(); SDL_Renderer *renderer = Window_GetRenderer(); cImGui_ImplSDL3_InitForSDLRenderer(window, renderer); cImGui_ImplSDLRenderer3_Init(renderer); gui->isPreferencesDialogOpen = false; gui->isNewGameDialogOpen = false; gui->isJourneyOnwardDialogOpen = false; Gui_UpdateStatusBar(gui, "Welcome to Tibia!"); } void Gui_ProcessEvent(const SDL_Event *event) { cImGui_ImplSDL3_ProcessEvent(event); } void Gui_StartRender() { cImGui_ImplSDLRenderer3_NewFrame(); cImGui_ImplSDL3_NewFrame(); ImGui_NewFrame(); } void Gui_Render(Gui_t *gui, const Objects_t *objects, Network_t *network, ConfigParams_t *configParams) { Gui_RenderMainMenu(gui); Gui_RenderStatusBar(gui); Gui_RenderPreferences_Dialog(gui, configParams); Gui_RenderNewGame_Dialog(gui, objects, configParams, network); Gui_RenderJourneyOnward_Dialog(gui, configParams, network); } void Gui_FinishRender() { SDL_Renderer *renderer = Window_GetRenderer(); ImGui_Render(); cImGui_ImplSDLRenderer3_RenderDrawData(ImGui_GetDrawData(), renderer); } void Gui_Shutdown() { cImGui_ImplSDLRenderer3_Shutdown(); cImGui_ImplSDL3_Shutdown(); ImGui_DestroyContext(NULL); SDL_DestroyTexture(cachedCharPreview); } void Gui_RenderMainMenu(Gui_t *gui) { if (!ImGui_BeginMainMenuBar()) { return; } if (ImGui_BeginMenu("File")) { if (ImGui_MenuItem("Preferences")) { gui->isPreferencesDialogOpen = true; } ImGui_Separator(); if (ImGui_MenuItem("Bye Bye")) { } ImGui_EndMenu(); } if (ImGui_BeginMenu("Game")) { if (ImGui_MenuItem("New Game")) { gui->isNewGameDialogOpen = true; } if (ImGui_MenuItem("Journey Onward")) { gui->isJourneyOnwardDialogOpen = true; } if (ImGui_MenuItem("End Game")) { } ImGui_EndMenu(); } if (ImGui_BeginMenu("Info")) { if (ImGui_MenuItem("Change Data")) { } if (ImGui_MenuItem("Userlist")) { } if (ImGui_MenuItem("Comments")) { } ImGui_EndMenu(); } const char *label = "Help"; // 1. Calculate text size const float textWidth = ImGui_CalcTextSize(label).x; // 2. Add the internal padding ImGui adds to menus (Style.FramePadding.x * 2) const float menuWidth = textWidth + ImGui_GetStyle()->FramePadding.x * 2.0f + 2; // 3. Set Cursor (Window Width - Menu Width) ImGui_SetCursorPosX(ImGui_GetWindowWidth() - menuWidth); // 4. Draw the menu if (ImGui_BeginMenu(label)) { if (ImGui_MenuItem("Version")) { } ImGui_EndMenu(); } ImGui_EndMainMenuBar(); } void Gui_RenderStatusBar(const Gui_t *gui) { const ImGuiViewport *viewport = ImGui_GetMainViewport(); const float height = ImGui_GetFrameHeight(); const ImVec2 position = {viewport->Pos.x, viewport->Pos.y + viewport->Size.y - height}; const ImVec2 size = {viewport->Size.x, height}; ImGui_SetNextWindowPosEx(position, ImGuiCond_Always, (ImVec2){0.0f, 0.0f}); ImGui_SetNextWindowSize(size, ImGuiCond_Always); // Remove rounding, borders and reduce padding ImGui_PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui_PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui_PushStyleVarImVec2(ImGuiStyleVar_WindowPadding, (ImVec2){8.0f, 2.0f}); // Set background and text colors ImGui_PushStyleColorImVec4(ImGuiCol_WindowBg, (ImVec4){0.85f, 0.85f, 0.85f, 1.0f}); ImGui_PushStyleColorImVec4(ImGuiCol_Text, (ImVec4){0.0f, 0.0f, 0.0f, 1.0f}); const ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNav; if (ImGui_Begin("StatusBar", NULL, windowFlags)) { ImGui_Text(gui->statusBarText); } ImGui_End(); ImGui_PopStyleColorEx(2); ImGui_PopStyleVarEx(3); } void Gui_RenderPreferences_Dialog(Gui_t *gui, ConfigParams_t *configParams) { if (!gui->isPreferencesDialogOpen) { return; } // Set the dialog position to the center of the screen, and let it grow as necessary const ImGuiViewport *viewport = ImGui_GetMainViewport(); const ImVec2 viewportCenter = { viewport->Pos.x + viewport->Size.x * 0.5f, viewport->Pos.y + viewport->Size.y * 0.5f }; ImGui_SetNextWindowPosEx(viewportCenter, ImGuiCond_Appearing, (ImVec2){0.5f, 0.5f}); ImGui_SetNextWindowSize((ImVec2){450, 0}, ImGuiCond_Always); if (!ImGui_Begin("Preferences", &gui->isPreferencesDialogOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) { ImGui_End(); SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Gui_RenderPreferences_Dialog: couldn't render."); } ImGui_Text("Server Data:"); if (ImGui_BeginTable("ServerTable", 2, ImGuiTableFlags_SizingFixedFit)) { ImGui_TableSetupColumnEx("Label", ImGuiTableColumnFlags_WidthFixed, 180.0f, 0); ImGui_TableSetupColumn("Input", ImGuiTableColumnFlags_WidthStretch); // Server Address ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Tibia-Server Address:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##Address", configParams->serverAddress, IM_ARRAYSIZE(configParams->serverAddress), 0); // Server Port ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Tibia-Server Portnumber:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputScalar("##Port", ImGuiDataType_U16, &configParams->serverPort); ImGui_EndTable(); } ImGui_Spacing(); ImGui_Separator(); ImGui_Spacing(); if (ImGui_BeginTable("BottomSplit", 2, ImGuiTableFlags_BordersInnerV)) { ImGui_TableSetupColumn("PlayerData", ImGuiTableColumnFlags_WidthStretch); ImGui_TableSetupColumnEx("Actions", ImGuiTableColumnFlags_WidthFixed, 100.0f, 0); ImGui_TableNextRow(); // Player Data ImGui_TableSetColumnIndex(0); ImGui_Text("Player Data:"); if (ImGui_BeginTable("PlayerDataTable", 2, ImGuiTableFlags_SizingFixedFit)) { ImGui_TableSetupColumnEx("Label", ImGuiTableColumnFlags_WidthFixed, 120.0f, 0); ImGui_TableSetupColumn("Input", ImGuiTableColumnFlags_WidthStretch); // Player Name ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Player Name:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##PName", configParams->lastAccount, IM_ARRAYSIZE(configParams->lastAccount), 0); // Player Password ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Player Password:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##PPass", configParams->lastPassword, IM_ARRAYSIZE(configParams->lastPassword), ImGuiInputTextFlags_Password); ImGui_EndTable(); } // Buttons ImGui_TableSetColumnIndex(1); ImGui_Dummy((ImVec2){0.0f, 2.25f}); if (ImGui_ButtonEx("Cancel", (ImVec2){-FLT_MIN, 0})) { gui->isPreferencesDialogOpen = false; } ImGui_Dummy((ImVec2){0.0f, 10.0f}); if (ImGui_ButtonEx("Save", (ImVec2){-FLT_MIN, 0})) { Config_Save_Settings(configParams); gui->isPreferencesDialogOpen = false; } ImGui_EndTable(); } ImGui_End(); } void Gui_RenderCustomizerRow(const char *label, uint8_t *value) { if (ImGui_BeginTable(label, 3, ImGuiTableFlags_SizingFixedFit)) { ImGui_TableSetupColumnEx("Left", ImGuiTableColumnFlags_WidthFixed, 20.0f, 0); ImGui_TableSetupColumnEx("Text", ImGuiTableColumnFlags_WidthFixed, 45.0f, 0); ImGui_TableSetupColumnEx("Right", ImGuiTableColumnFlags_WidthFixed, 20.0f, 0); ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); if (ImGui_ButtonEx("<", (ImVec2){20, 20})) { (*value)--; SDL_DestroyTexture(cachedCharPreview); cachedCharPreview = NULL; } ImGui_TableSetColumnIndex(1); const float currentX = ImGui_GetCursorPosX(); const float textWidth = ImGui_CalcTextSize(label).x; ImGui_SetCursorPosX(currentX + (45.0f - textWidth) * 0.5f); ImGui_Text("%s", label); ImGui_TableSetColumnIndex(2); if (ImGui_ButtonEx(">", (ImVec2){20, 20})) { (*value)++; SDL_DestroyTexture(cachedCharPreview); cachedCharPreview = NULL; } ImGui_EndTable(); } } SDL_Texture *Gui_CombineCharacterTextures(SDL_Texture *bodyTexture, SDL_Texture *headTexture, SDL_Texture *legsTexture, SDL_Texture *shoesTexture) { SDL_Renderer *renderer = Window_GetRenderer(); SDL_Texture *target = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SPRITE_SIZE, SPRITE_SIZE); SDL_SetTextureBlendMode(target, SDL_BLENDMODE_BLEND); SDL_SetTextureScaleMode(target, SDL_SCALEMODE_NEAREST); SDL_SetRenderTarget(renderer, target); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); // Draw layers in order SDL_RenderTexture(renderer, shoesTexture, NULL, NULL); SDL_RenderTexture(renderer, legsTexture, NULL, NULL); SDL_RenderTexture(renderer, bodyTexture, NULL, NULL); // The head texture needs to be offset // This is hardcoded in the original client SDL_RenderTexture(renderer, headTexture, NULL, &(SDL_FRect){1.0f, -14.0f, SPRITE_SIZE, SPRITE_SIZE}); SDL_SetRenderTarget(renderer, NULL); return target; } void Gui_RenderCharacterCustomizer(const Objects_t *objects) { if (ImGui_BeginTable("CharCustomizerMain", 2, ImGuiTableFlags_SizingFixedFit)) { ImGui_TableSetupColumnEx("Preview", ImGuiTableColumnFlags_WidthFixed, SPRITE_SIZE * 2, 0); ImGui_TableSetupColumn("Controls", ImGuiTableColumnFlags_WidthStretch); ImGui_TableNextRow(); // Character Preview ImGui_TableSetColumnIndex(0); const float frameHeight = ImGui_GetFrameHeight(); const float spacing = ImGui_GetStyle()->ItemSpacing.y; const float controlsTotalHeight = frameHeight * 4.0f + spacing * 3.0f; const float offset = (controlsTotalHeight - SPRITE_SIZE * 2) * 0.5f; if (offset > 0.0f) { ImGui_SetCursorPosY(ImGui_GetCursorPosY() + offset); } if (cachedCharPreview == NULL) { SDL_Texture *bodyTexture = Objects_GetSpriteTexture(objects, 155 + character.body); SDL_Texture *headTexture = Objects_GetSpriteTexture(objects, 176 + character.head); SDL_Texture *legsTexture = Objects_GetSpriteTexture(objects, 158 + character.legs); SDL_Texture *shoesTexture = Objects_GetSpriteTexture(objects, 161 + character.shoes); cachedCharPreview = Gui_CombineCharacterTextures(bodyTexture, headTexture, legsTexture, shoesTexture); } ImGui_Image((ImTextureRef){NULL, (ImTextureID) cachedCharPreview}, (ImVec2){SPRITE_SIZE * 2, SPRITE_SIZE * 2}); ImGui_TableSetColumnIndex(1); ImGui_SetCursorPosX(ImGui_GetCursorPosX() + 10.0f); ImGui_BeginGroup(); ImGui_PushID("Head"); Gui_RenderCustomizerRow("Head", &character.head); ImGui_PopID(); ImGui_PushID("Body"); Gui_RenderCustomizerRow("Body", &character.body); ImGui_PopID(); ImGui_PushID("Legs"); Gui_RenderCustomizerRow("Legs", &character.legs); ImGui_PopID(); ImGui_PushID("Shoes"); Gui_RenderCustomizerRow("Shoes", &character.shoes); ImGui_PopID(); ImGui_EndGroup(); ImGui_EndTable(); } } uint16_t Gui_PackCharacter() { // Ensure indices are within 4-bit range character.head &= 0x0F; character.body &= 0x0F; character.legs &= 0x0F; character.shoes &= 0x0F; uint16_t packed = 0; packed |= character.head << 12; packed |= character.body << 8; packed |= character.legs << 4; packed |= character.shoes; return packed; } void Gui_RenderNewGame_Dialog(Gui_t *gui, const Objects_t *objects, const ConfigParams_t *configParams, Network_t *network) { if (!gui->isNewGameDialogOpen) { return; } static int sex = 1; static char realName[50] = ""; static char email[50] = ""; static char location[50] = ""; const ImGuiViewport *viewport = ImGui_GetMainViewport(); const ImVec2 viewportCenter = { viewport->Pos.x + viewport->Size.x * 0.5f, viewport->Pos.y + viewport->Size.y * 0.5f }; ImGui_SetNextWindowPosEx(viewportCenter, ImGuiCond_Appearing, (ImVec2){0.5f, 0.5f}); ImGui_SetNextWindowSize((ImVec2){550, 0}, ImGuiCond_Always); if (ImGui_Begin("New Game", &gui->isNewGameDialogOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) { if (ImGui_BeginTable("TopLayout", 2, ImGuiTableFlags_BordersInnerV)) { ImGui_TableSetupColumnEx("TopInputs", ImGuiTableColumnFlags_WidthStretch, 0.0f, 0); ImGui_TableSetupColumnEx("TopButtons", ImGuiTableColumnFlags_WidthFixed, 140.0f, 0); ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); if (ImGui_BeginTable("TopForm", 2, ImGuiTableFlags_SizingFixedFit)) { ImGui_TableSetupColumnEx("Label", ImGuiTableColumnFlags_WidthFixed, 90.0f, 0); ImGui_TableSetupColumn("Input", ImGuiTableColumnFlags_WidthStretch); // Real Name ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Real Name:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##RealName", realName, sizeof(realName), 0); // Location ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Location:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##Location", location, sizeof(location), 0); // E-Mail ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("E-Mail:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##Email", email, sizeof(email), 0); ImGui_EndTable(); } ImGui_TableSetColumnIndex(1); // "Create Character" if (ImGui_ButtonEx("Create Character", (ImVec2){-FLT_MIN, 0})) { // TODO: verify is both passwords match uint8_t buffer[30 + 30 + 1 + 2 + 1 + 50 + 50 + 50] = {0}; strncpy((char *) buffer, configParams->lastAccount, 30); strncpy((char *) buffer + 30, configParams->lastPassword, 30); buffer[30 + 30] = (uint8_t) sex; const uint16_t packedCharacter = Gui_PackCharacter(); memcpy(buffer + 30 + 30 + 1, &packedCharacter, 2); strncpy((char *) buffer + 30 + 30 + 1 + 2 + 1, realName, 50); strncpy((char *) buffer + 30 + 30 + 1 + 2 + 1 + 50, location, 50); strncpy((char *) buffer + 30 + 30 + 1 + 2 + 1 + 50 + 50, email, 50); Network_ConnectAndReportStatus(network, configParams, gui); Network_SendPacket(network, HANDLER_LOGIN_OR_CREATE_CHAR, 0x00, buffer, 30 + 30 + 1 + 2 + 1 + 50 + 50 + 50); gui->isNewGameDialogOpen = false; } ImGui_Dummy((ImVec2){0.0f, 10.0f}); // Spacing between buttons // "Oops, Cancel" if (ImGui_ButtonEx("Oops, Cancel", (ImVec2){-FLT_MIN, 0})) { gui->isNewGameDialogOpen = false; } ImGui_EndTable(); } ImGui_Spacing(); ImGui_Separator(); ImGui_Spacing(); if (ImGui_BeginTable("BottomLayout", 2, ImGuiTableFlags_BordersInnerV)) { ImGui_TableSetupColumnEx("BotInputs", ImGuiTableColumnFlags_WidthStretch, 0.0f, 0); ImGui_TableSetupColumnEx("BotVisuals", ImGuiTableColumnFlags_WidthFixed, 180.0f, 0); ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); if (ImGui_BeginTable("BotForm", 2, ImGuiTableFlags_SizingFixedFit)) { ImGui_TableSetupColumnEx("Label", ImGuiTableColumnFlags_WidthFixed, 130.0f, 0); ImGui_TableSetupColumn("Input", ImGuiTableColumnFlags_WidthStretch); // Your Name ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Your Name:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); static char charName[64] = ""; ImGui_InputText("##CharName", charName, sizeof(charName), 0); // Your Sex (Radio Buttons) ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Your Sex:"); ImGui_TableSetColumnIndex(1); ImGui_RadioButtonIntPtr("male", &sex, 1); ImGui_SameLine(); ImGui_RadioButtonIntPtr("female", &sex, 0); // Enter Password ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Enter Password:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); static char pass1[64] = ""; ImGui_InputText("##Pass1", pass1, sizeof(pass1), ImGuiInputTextFlags_Password); // Retype Password ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Retype Password:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); static char pass2[64] = ""; ImGui_InputText("##Pass2", pass2, sizeof(pass2), ImGuiInputTextFlags_Password); ImGui_EndTable(); } ImGui_TableSetColumnIndex(1); Gui_RenderCharacterCustomizer(objects); ImGui_EndTable(); } } ImGui_End(); } void Gui_RenderJourneyOnward_Dialog(Gui_t *gui, ConfigParams_t *configParams, Network_t *network) { if (!gui->isJourneyOnwardDialogOpen) { return; } const ImGuiViewport *viewport = ImGui_GetMainViewport(); const ImVec2 viewportCenter = { viewport->Pos.x + viewport->Size.x * 0.5f, viewport->Pos.y + viewport->Size.y * 0.5f }; ImGui_SetNextWindowPosEx(viewportCenter, ImGuiCond_Appearing, (ImVec2){0.5f, 0.5f}); ImGui_SetNextWindowSize((ImVec2){380, 0}, ImGuiCond_Always); if (ImGui_Begin("Journey Onward", &gui->isJourneyOnwardDialogOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse)) { if (ImGui_BeginTable("Split", 2, ImGuiTableFlags_BordersInnerV)) { ImGui_TableSetupColumnEx("Data", ImGuiTableColumnFlags_WidthStretch, 0.0f, 0); ImGui_TableSetupColumnEx("Actions", ImGuiTableColumnFlags_WidthFixed, 100.0f, 0); ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_Text("Player Data:"); if (ImGui_BeginTable("InputTable", 2, ImGuiTableFlags_SizingFixedFit)) { ImGui_TableSetupColumnEx("Label", ImGuiTableColumnFlags_WidthFixed, 110.0f, 0); ImGui_TableSetupColumn("Input", ImGuiTableColumnFlags_WidthStretch); // Player Name ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Player Name:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##PName", configParams->lastAccount, IM_ARRAYSIZE(configParams->lastAccount), 0); // Player Password ImGui_TableNextRow(); ImGui_TableSetColumnIndex(0); ImGui_AlignTextToFramePadding(); ImGui_Text("Player Password:"); ImGui_TableSetColumnIndex(1); ImGui_SetNextItemWidth(-FLT_MIN); ImGui_InputText("##PPass", configParams->lastPassword, IM_ARRAYSIZE(configParams->lastPassword), ImGuiInputTextFlags_Password); ImGui_EndTable(); } ImGui_TableSetColumnIndex(1); // Cancel if (ImGui_ButtonEx("Cancel", (ImVec2){-FLT_MIN, 0})) { gui->isJourneyOnwardDialogOpen = false; } ImGui_Dummy((ImVec2){0.0f, 10.0f}); // Let's Go if (ImGui_ButtonEx("Let's Go", (ImVec2){-FLT_MIN, 0})) { gui->isJourneyOnwardDialogOpen = false; uint8_t buffer[60] = {0}; strncpy((char *) buffer, configParams->lastAccount, 30); strncpy((char *) buffer + 30, configParams->lastPassword, 30); Network_ConnectAndReportStatus(network, configParams, gui); Network_SendPacket(network, HANDLER_LOGIN_OR_CREATE_CHAR, 0x01, buffer, 60); } ImGui_EndTable(); } } ImGui_End(); } void Gui_UpdateStatusBar(Gui_t *gui, const char *message) { strncpy(gui->statusBarText, message, sizeof(gui->statusBarText) - 1); gui->statusBarText[sizeof(gui->statusBarText) - 1] = '\0'; }