#include "DiabloUI/dialogs.h" #include "devilution.h" #include "dx.h" #include "DiabloUI/diabloui.h" #include "DiabloUI/button.h" #include "DiabloUI/fonts.h" namespace dvl { extern HANDLE diabdat_mpq; extern SDL_Surface *pal_surface; namespace { Art dialogArt; Art progressArt; char dialogText[256]; char dialogCaption[1024]; bool fontWasLoaded; bool textInputWasActive; UiItem *dialogItems; std::size_t dialogItemsSize; enum class State { DEFAULT = 0, OK, CANCEL, }; State state; void DialogActionOK() { state = State::OK; } void DialogActionCancel() { state = State::CANCEL; } constexpr auto DIALOG_ART_S = UiImage(&dialogArt, { 180, 168, 280, 144 }); constexpr auto DIALOG_ART_L = UiImage(&dialogArt, { 127, 100, 385, 280 }); UiItem OKCANCEL_DIALOG[] = { DIALOG_ART_S, UiText(dialogText, { 200, 211, 240, 80 }, UIS_CENTER), MakeSmlButton("OK", &DialogActionOK, 200, 265), MakeSmlButton("Cancel", &DialogActionCancel, 330, 265), }; UiItem OK_DIALOG[] = { DIALOG_ART_S, UiText(dialogText, { 200, 211, 240, 80 }, UIS_CENTER), MakeSmlButton("OK", &DialogActionOK, 265, 265), }; UiItem OK_DIALOG_WITH_CAPTION[] = { DIALOG_ART_L, UiText(dialogText, SDL_Color{ 255, 255, 0, 0 }, { 147, 110, 345, 20 }, UIS_CENTER), UiText(dialogCaption, { 147, 141, 345, 190 }, UIS_CENTER), MakeSmlButton("OK", &DialogActionOK, 264, 335), }; UiItem PROGRESS_DIALOG[] = { DIALOG_ART_S, UiText(dialogText, { 180, 177, 280, 43 }, UIS_CENTER), UiImage(&progressArt, { 205, 220, 228, 38 }), MakeSmlButton("Cancel", &DialogActionCancel, 330, 265), }; UiListItem SELOK_DIALOG_ITEMS[] = { { "OK", 0 } }; UiItem SELOK_DIALOG[] = { UiText(dialogText, { 140, 210, 400, 168 }, UIS_CENTER), UiList(SELOK_DIALOG_ITEMS, 230, 390, 180, 35, UIS_CENTER), }; UiItem SPAWNERR_DIALOG[] = { UiText("The Rogue and Sorcerer are only available in the full retail version of Diablo. For ordering information call (800) 953-SNOW.", { 140, 199, 400, 177 }), UiArtTextButton("OK", &DialogActionOK, { 230, 407, 180, 43 }), }; const std::uint_fast8_t DEFAULT_BG_DIALOG_IDX = 4; const std::uint_fast8_t DEFAULT_BG_BUTTON_IDX = 5; void LoadFallbackPalette() { PALETTEENTRY fallback_palette[256] = { 0 }; fallback_palette[1] = { 255, 255, 255, 0 }; fallback_palette[2] = { 255, 255, 0, 0 }; fallback_palette[3] = { 243, 243, 243, 0 }; fallback_palette[DEFAULT_BG_DIALOG_IDX] = { 100, 20, 20, 0 }; fallback_palette[DEFAULT_BG_BUTTON_IDX] = { 130, 110, 80, 0 }; LoadPalInMem(fallback_palette); ApplyGamma(logical_palette, orig_palette, 256); } void StubArt(Art *art, int w, int h, std::uint_fast8_t color_idx) { art->surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h * art->frames, 8, 0, 0, 0, 0); SDL_FillRect(art->surface, nullptr, color_idx); art->frame_height = h; } void Init(const char *text, const char *caption, bool error) { strcpy(dialogText, text); if (caption == nullptr) { LoadMaskedArt(error ? "ui_art\\srpopup.pcx" : "ui_art\\spopup.pcx", &dialogArt); dialogItems = OK_DIALOG; dialogItemsSize = size(OK_DIALOG); } else { LoadMaskedArt(error ? "ui_art\\lrpopup.pcx" : "ui_art\\lpopup.pcx", &dialogArt); strcpy(dialogCaption, caption); dialogItems = OK_DIALOG_WITH_CAPTION; dialogItemsSize = size(OK_DIALOG_WITH_CAPTION); } LoadSmlButtonArt(); if (diabdat_mpq == nullptr) { ShowCursor(true); LoadFallbackPalette(); const auto dlg_rect = (caption == nullptr ? DIALOG_ART_S.rect : DIALOG_ART_L.rect); StubArt(&dialogArt, dlg_rect.w, dlg_rect.h, DEFAULT_BG_DIALOG_IDX); const auto &btn = dialogItems[dialogItemsSize - 1].button; StubArt(btn.art, btn.rect.w, btn.rect.h, DEFAULT_BG_BUTTON_IDX); } fontWasLoaded = font != nullptr; if (!fontWasLoaded) LoadTtfFont(); textInputWasActive = SDL_IsTextInputActive(); SDL_StopTextInput(); } void Deinit() { dialogArt.Unload(); UnloadSmlButtonArt(); if (!fontWasLoaded) UnloadTtfFont(); if (textInputWasActive) SDL_StartTextInput(); for (std::size_t i = 0; i < dialogItemsSize; ++i) { dialogItems[i].FreeCache(); } } void DialogLoop(UiItem *items, std::size_t num_items, UiItem *render_behind, std::size_t render_behind_size) { SDL_Event event; state = State::DEFAULT; if (render_behind_size == 0) SDL_FillRect(pal_surface, nullptr, 0); do { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_ESCAPE: case SDLK_RETURN: case SDLK_KP_ENTER: case SDLK_SPACE: state = State::OK; break; default: break; } break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: UiItemMouseEvents(&event, items, num_items); break; case SDL_QUIT: exit(0); } } UiRenderItems(render_behind, render_behind_size); DrawLogo(); UiRenderItems(items, num_items); DrawMouse(); UiFadeIn(); } while (state == State::DEFAULT); } } // namespace void UiOkDialog(const char *text, const char *caption, bool error, UiItem *render_behind, std::size_t render_behind_size) { Init(text, caption, error); DialogLoop(dialogItems, dialogItemsSize, render_behind, render_behind_size); Deinit(); } void UiErrorOkDialog(const char *text, const char *caption, UiItem *render_behind, std::size_t render_behind_size) { UiOkDialog(text, caption, /*error=*/true, render_behind, render_behind_size); } void UiErrorOkDialog(const char *text, UiItem *render_behind, std::size_t render_behind_size) { UiErrorOkDialog(text, nullptr, render_behind, render_behind_size); } } // namespace dvl