diff --git a/CMakeLists.txt b/CMakeLists.txt index 72c7f8b70..7e46a2de8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,6 +146,7 @@ set(STUB_SOURCES Stub/dvlnet/base.cpp Stub/dvlnet/udp_p2p.cpp + Stub/DiabloUI/dialogs.cpp Stub/DiabloUI/credits.cpp Stub/DiabloUI/diabloui.cpp Stub/DiabloUI/mainmenu.cpp diff --git a/Stub/DiabloUI/credits.cpp b/Stub/DiabloUI/credits.cpp index 61dc7c5e8..dcff77c2a 100644 --- a/Stub/DiabloUI/credits.cpp +++ b/Stub/DiabloUI/credits.cpp @@ -537,7 +537,6 @@ BOOL __stdcall UiCreditsDialog(int a1) SDL_Event event; while (!endMenu && lineCount > 0) { - CapFPS(); credts_Render(); UiFadeIn(); diff --git a/Stub/DiabloUI/diabloui.cpp b/Stub/DiabloUI/diabloui.cpp index 85c8de1b9..908b0e29c 100644 --- a/Stub/DiabloUI/diabloui.cpp +++ b/Stub/DiabloUI/diabloui.cpp @@ -1,8 +1,8 @@ #include "../../types.h" TTF_Font *font; +int SelectedItemMin = 1; int SelectedItemMax = 1; -int submenu = 0; BYTE *FontTables[4]; Art ArtFonts[4][2]; Art ArtLogos[3]; @@ -12,12 +12,14 @@ Art ArtCursor; Art ArtHero; void(__stdcall *gfnSoundFunction)(char *file); +void(__stdcall *gfnListSelect)(int value); +void(__stdcall *gfnListFocus)(int value); int SCREEN_WIDTH = 640; int SCREEN_HEIGHT = 480; int fadeValue = 0; -int SelectedItem = 1; +int SelectedItem = 0; char *errorTitle[] = { "Direct Draw Error", @@ -118,71 +120,96 @@ void __cdecl UiDestroy() font = NULL; } -void UiFocuse(int itemIndex, bool wrap) +void UiInitList(int min, int max, void(__stdcall *fnFocus)(int value), void(__stdcall *fnSelect)(int value)) { - SelectedItem = itemIndex; + SelectedItem = min; + SelectedItemMin = min; + SelectedItemMax = max; + gfnListFocus = fnFocus; + gfnListSelect = fnSelect; + if (fnFocus) + fnFocus(min); +} + +void UiPlayMoveSound() +{ + if (gfnSoundFunction) + gfnSoundFunction("sfx\\items\\titlemov.wav"); +} +void UiPlaySelectSound() //TODO play this on menu back step +{ + if (gfnSoundFunction) + gfnSoundFunction("sfx\\items\\titlslct.wav"); +} + +void UiFocus(int itemIndex, bool wrap = false) +{ if (!wrap) { - if (SelectedItem < 1) { - SelectedItem = 1; + if (itemIndex < SelectedItemMin) { + itemIndex = SelectedItemMin; return; - } else if (SelectedItem > SelectedItemMax) { - SelectedItem = SelectedItemMax ?: 1; + } else if (itemIndex > SelectedItemMax) { + itemIndex = SelectedItemMax ?: SelectedItemMin; return; } - } else if (SelectedItem < 1) { - SelectedItem = SelectedItemMax ?: 1; - } else if (SelectedItem > SelectedItemMax) { - SelectedItem = 1; + } else if (itemIndex < SelectedItemMin) { + itemIndex = SelectedItemMax ?: SelectedItemMin; + } else if (itemIndex > SelectedItemMax) { + itemIndex = SelectedItemMin; } + if (SelectedItem == itemIndex) + return; + + SelectedItem = itemIndex; + UiPlayMoveSound(); + + if (gfnListFocus) + gfnListFocus(itemIndex); } -bool UiFocuseNavigation(SDL_Event *event, bool wrap) +bool UiFocusNavigation(SDL_Event *event, bool wrap) { + if (event->type != SDL_KEYDOWN) { + return false; + } + switch (event->key.keysym.sym) { case SDLK_UP: - UiFocuse(SelectedItem - 1, wrap); + UiFocus(SelectedItem - 1, wrap); return true; case SDLK_DOWN: - UiFocuse(SelectedItem + 1, wrap); + UiFocus(SelectedItem + 1, wrap); return true; case SDLK_TAB: if (SDL_GetModState() & KMOD_SHIFT) - UiFocuse(SelectedItem - 1, wrap); + UiFocus(SelectedItem - 1, wrap); else - UiFocuse(SelectedItem + 1, wrap); + UiFocus(SelectedItem + 1, wrap); return true; case SDLK_PAGEUP: - SelectedItem = 1; + UiFocus(SelectedItemMin); return true; case SDLK_PAGEDOWN: - SelectedItem = SelectedItemMax; + UiFocus(SelectedItemMax); return true; + case SDLK_RETURN: + case SDLK_KP_ENTER: + case SDLK_SPACE: + UiFocusNavigationSelect(); + break; } return false; } -void SetMenu(int MenuId) +void UiFocusNavigationSelect() { UiPlaySelectSound(); - - submenu = MenuId; - SelectedItem = 1; - switch (MenuId) { - case SELHERO_CLASSES: - case SELHERO_DIFFICULTY: - SelectedItemMax = 3; - break; - case SELHERO_SELECT_GAME: - SelectedItemMax = 2; - break; - default: - SelectedItemMax = 1; - break; - } + if (gfnListSelect) + gfnListSelect(SelectedItem); } bool IsInsideRect(const SDL_Event *event, const SDL_Rect *rect) @@ -356,18 +383,6 @@ BOOL __stdcall UiSoundCallback(int a1, int type, int a3) UNIMPLEMENTED(); } -void UiPlayMoveSound() -{ - if (gfnSoundFunction) - gfnSoundFunction("sfx\\items\\titlemov.wav"); -} - -void UiPlaySelectSound() -{ - if (gfnSoundFunction) - gfnSoundFunction("sfx\\items\\titlslct.wav"); -} - void __stdcall UiMessageBoxCallback(HWND hWnd, char *lpText, LPCSTR lpCaption, UINT uType) { UNIMPLEMENTED(); @@ -434,7 +449,7 @@ void DrawArt(int screenX, int screenY, Art *art, int nFrame, int drawW) } } -int GetCenterOffset(int w, int bw = 0) +int GetCenterOffset(int w, int bw) { if (bw == 0) { bw = SCREEN_WIDTH; @@ -458,30 +473,94 @@ int GetStrWidth(BYTE *str, int size) return strWidth; } -int TextAlignment(char *text, TXT_JUST align, int bw, int size) +int TextAlignment(UI_Item *item, TXT_JUST align, _artFontTables size) { if (align != JustLeft) { - int w = GetStrWidth(text, size); + int w = GetStrWidth(item->caption, size); if (align == JustCentre) { - return GetCenterOffset(w, bw); + return GetCenterOffset(w, item->rect.w); } else if (align == JustRight) { - return bw - w; + return item->rect.w - w; } } return 0; } -void DrawArtStr(int x, int y, int size, int color, BYTE *str, TXT_JUST align, int bw) +void WordWrap(UI_Item *item) { - x += TextAlignment(str, align, bw, size); + int lineStart = 0; + int len = strlen(item->caption); + for (int i = 0; i <= len; i++) { + if (item->caption[i] == '\n') { + lineStart = i + 1; + continue; + } else if (item->caption[i] != ' ' && i != len) { + continue; + } - for (int i = 0; i < strlen(str); i++) { - BYTE w = FontTables[size][str[i] + 2]; - if (!w) - w = FontTables[size][0]; - DrawArt(x, y, &ArtFonts[size][color], str[i], w); - x += w; + if (i != len) + item->caption[i] = '\0'; + if (GetStrWidth(&item->caption[lineStart], AFT_SMALL) <= item->rect.w) { + if (i != len) + item->caption[i] = ' '; + continue; + } + + int j; + for (j = i; j >= lineStart; j--) { + if (item->caption[j] == ' ') { + break; // Scan for previous space + } + } + + if (j == lineStart) { // Single word longer then width + if (i == len) + break; + j = i; + } + + if (i != len) + item->caption[i] = ' '; + item->caption[j] = '\n'; + lineStart = j + 1; + } +}; + +void DrawArtStr(UI_Item *item) +{ + _artFontTables size = AFT_SMALL; + _artFontColors color = item->flags & UIS_GOLD ? AFC_GOLD : AFC_SILVER; + TXT_JUST align = JustLeft; + + if (item->flags & UIS_MED) + size = AFT_MED; + else if (item->flags & UIS_BIG) + size = AFT_BIG; + else if (item->flags & UIS_HUGE) + size = AFT_HUGE; + + if (item->flags & UIS_CENTER) + align = JustCentre; + else if (item->flags & UIS_RIGHT) + align = JustRight; + + int x = item->rect.x + TextAlignment(item, align, size); + + int sx = x; + int sy = item->rect.y; + if (item->flags & UIS_VCENTER) + sy += (item->rect.h - ArtFonts[size][color].height) / 2; + + for (int i = 0; i < strlen(item->caption); i++) { + if (item->caption[i] == '\n') { + sx = x; + sy += ArtFonts[size][color].height; + continue; + } + BYTE w = FontTables[size][item->caption[i] + 2] ?: FontTables[size][0]; + DrawArt(sx, sy, &ArtFonts[size][color], *(BYTE *)&item->caption[i], w); + sx += w; } } @@ -512,16 +591,6 @@ int GetAnimationFrame(int frames, int fps) return frame > frames ? 0 : frame; } -int frameEnd = 0; -void CapFPS() -{ - int now = SDL_GetTicks(); - frameEnd += 1000 / 60; - if (now < frameEnd) { - SDL_Delay(frameEnd - now); - } -} - bool UiFadeIn(int steps) { if (fadeValue < 256) { @@ -536,6 +605,105 @@ bool UiFadeIn(int steps) return fadeValue == 256; } +void UiRenderItemDebug(UI_Item item) +{ + return; + item.rect.x += 64; // pal_surface is shifted? + item.rect.y += 160; + SDL_FillRect(pal_surface, &item.rect, random(0, 255)); +} + +void DrawSelector(UI_Item *item = 0) +{ + int size = FOCUS_SMALL; + if (item->rect.h >= 42) + size = FOCUS_BIG; + else if (item->rect.h >= 30) + size = FOCUS_MED; + + int frame = GetAnimationFrame(8); + int y = item->rect.y + (item->rect.h - ArtFocus[size].height) / 2; // TODO FOCUS_MED appares higher then the box + + DrawArt(item->rect.x, y, &ArtFocus[size], frame); + DrawArt(item->rect.x + item->rect.w - ArtFocus[size].width, y, &ArtFocus[size], frame); +} + +void DrawEditBox(UI_Item item) +{ + DrawSelector(&item); + item.rect.x += 43; + item.rect.y += 1; + item.rect.w -= 86; + DrawArtStr(&item); +} + +void UiRenderItems(UI_Item *items, int size) +{ + for (int i = 0; i < size; i++) { + if (items[i].flags & UIS_HIDDEN) + continue; + + UiRenderItemDebug(items[i]); + switch (items[i].type) { + case UI_EDIT: + DrawEditBox(items[i]); + break; + case UI_LIST: + if (items[i].caption == NULL) + continue; + if (SelectedItem == items[i].value) + DrawSelector(&items[i]); + case UI_BUTTON: + case UI_TEXT: + DrawArtStr(&items[i]); + break; + case UI_IMAGE: + DrawArt(items[i].rect.x, items[i].rect.y, items[i].context, items[i].value, items[i].rect.w); + break; + default: + UiRenderItemDebug(items[i]); + break; + } + } +} + +bool UiItemMouseEvents(SDL_Event *event, UI_Item *items, int size) +{ + if (event->type != SDL_MOUSEBUTTONDOWN || event->button.button != SDL_BUTTON_LEFT) { + return false; + } + + for (int i = 0; i < size; i++) { + if (!IsInsideRect(event, &items[i].rect)) { + continue; + } + + if (items[i].type != UI_BUTTON && items[i].type != UI_LIST) { + continue; + } + + if (items[i].type == UI_LIST) { + if (items[i].caption != NULL && *items[i].caption != '\0') { + if (gfnListFocus != NULL && SelectedItem != items[i].value) { + UiFocus(items[i].value); + } else if (gfnListFocus == NULL || event->button.clicks >= 2) { + SelectedItem = items[i].value; + UiFocusNavigationSelect(); + } + } + + return true; + } + + if (items[i].context) { + ((void (*)(int value))items[i].context)(items[i].value); + } + return true; + } + + return false; +} + void DrawLogo(int t, int size) { DrawArt(GetCenterOffset(ArtLogos[size].width), t, &ArtLogos[size], GetAnimationFrame(15)); @@ -557,13 +725,3 @@ void DrawMouse() DrawArt(MouseX, MouseY, &ArtCursor); } - -void DrawSelector(int x, int y, int width, int padding, int spacing, int size) -{ - width = width ? width : SCREEN_WIDTH; - y += (SelectedItem - 1) * spacing; - - int frame = GetAnimationFrame(8); - DrawArt(x + padding, y, &ArtFocus[size], frame); - DrawArt(x + width - padding - ArtFocus[size].width, y, &ArtFocus[size], frame); -} diff --git a/Stub/DiabloUI/dialogs.cpp b/Stub/DiabloUI/dialogs.cpp new file mode 100644 index 000000000..27ab59a6b --- /dev/null +++ b/Stub/DiabloUI/dialogs.cpp @@ -0,0 +1,44 @@ +#include "../../types.h" + +UI_Item ENTERIP_DIALOG[] = { + { { 305, 210, 285, 33 }, UI_TEXT, UIS_CENTER, 0, "Enter IP" }, + { { 305, 314, 285, 33 }, UI_EDIT, UIS_LIST, 128 }, // input + { { 300, 426, 140, 35 }, UI_BUTTON, 0, 0, "OK" }, + { { 450, 426, 140, 35 }, UI_BUTTON, 0, 0, "Cancel" }, +}; + +UI_Item OKCANCEL_DIALOG[] = { + { { 180, 168, 280, 144 }, UI_IMAGE, 0, 0, "ui_art\\spopup.pcx" }, + { { 200, 180, 240, 80 }, UI_TEXT, UIS_CENTER }, // message + { { 200, 265, 110, 28 }, UI_BUTTON, UIS_SML1, 0, "OK" }, + { { 330, 265, 110, 28 }, UI_BUTTON, UIS_SML2, 0, "Cancel" }, +}; + +UI_Item OK_DIALOG[] = { + { { 180, 168, 280, 144 }, UI_IMAGE, 0, 0, "ui_art\\spopup.pcx" }, + { { 200, 180, 240, 80 }, UI_TEXT, UIS_CENTER }, // message + { { 265, 265, 110, 28 }, UI_BUTTON, UIS_SML1, 0, "OK" }, +}; + +UI_Item PROGRESS_DIALOG[] = { + { { 180, 168, 280, 144 }, UI_IMAGE, 0, 0, "ui_art\\spopup.pcx" }, + { { 180, 177, 280, 43 }, UI_TEXT, UIS_CENTER }, // Message + { { 205, 220, 228, 38 }, UI_IMAGE, 0, 0, "ui_art\\prog_bg.pcx" }, + { { 265, 267, 110, 28 }, UI_BUTTON, UIS_SML1, 0, "Cancel" }, +}; + +UI_Item SELOK_DIALOG[] = { + { { 140, 210, 400, 168 } }, // Message + { { 230, 390, 180, 35 }, UI_LIST, UIS_CENTER, 0, "OK" }, +}; + +UI_Item SELYESNO_DIALOG[] = { + { { 120, 210, 400, 168 } }, // Question text + { { 230, 390, 180, 35 }, UI_LIST, UIS_CENTER, 0, "Yes" }, + { { 230, 426, 180, 35 }, UI_LIST, UIS_CENTER, 0, "No" }, +}; + +UI_Item SPAWNERR_DIALOG[] = { + { { 140, 199, 400, 177 }, UI_TEXT, 0, 0, "The Rogue and Sorcerer are only available in the full retail version of Diablo. For ordering information call (800) 953-SNOW." }, + { { 230, 407, 180, 43 }, UI_BUTTON, 0, 0, "OK" }, +}; diff --git a/Stub/DiabloUI/mainmenu.cpp b/Stub/DiabloUI/mainmenu.cpp index a777cb48a..08cb689fa 100644 --- a/Stub/DiabloUI/mainmenu.cpp +++ b/Stub/DiabloUI/mainmenu.cpp @@ -1,30 +1,21 @@ #include "../../types.h" -void mainmenu_Render(char *name) -{ - DrawArt(0, 0, &ArtBackground); - - DrawLogo(); - - int menuTop = 192; - char *MENIITEMS[5] = { "Single Player", "Multi Player", "Replay Intro", "Show Credits", "Exit Diablo" }; - - int spacing = 43; - for (int i = 0; i < 5; i++) { - int y = menuTop + i * spacing; - DrawArtStr(0, y, AFT_HUGE, AFC_GOLD, MENIITEMS[i], 1); - } - - DrawSelector(0, menuTop, 0, 65, spacing, FOCUS_BIG); +int MainMenuResult; - DrawArtStr(17, 444, AFT_SMALL, AFC_SILVER, name); +void UiMainMenuSelect(int value) +{ + MainMenuResult = value; } void mainmenu_Load() { + MainMenuResult = 0; + UiInitList(MAINMENU_SINGLE_PLAYER, MAINMENU_EXIT_DIABLO, NULL, UiMainMenuSelect); + char *pszFile = "ui_art\\mainmenu.pcx"; if (false) //DiabloUI_GetSpawned() pszFile = "ui_art\\swmmenu.pcx"; + LoadBackgroundArt(pszFile); } @@ -34,123 +25,57 @@ void mainmenu_Free() ArtBackground.data = NULL; } -BOOL __stdcall UiMainMenuDialog(char *name, int *pdwResult, void(__stdcall *fnSound)(char *file), int a4) +bool UiMainMenuEvent(SDL_Event *event) { - gfnSoundFunction = fnSound; - mainmenu_Load(); + switch (event->type) { + case SDL_KEYDOWN: + if (UiFocusNavigation(event, true)) + return true; + if (event->key.keysym.sym == SDLK_ESCAPE) { + UiMainMenuSelect(MAINMENU_EXIT_DIABLO); + return true; + } + break; + case SDL_QUIT: + exit(0); + } + + return false; +} - SelectedItem = 1; - SelectedItemMax = 5; +BOOL __stdcall UiMainMenuDialog(char *name, int *pdwResult, void(__stdcall *fnSound)(char *file), int a4) +{ SDL_Event event; - int ItemHeight = 43; - SDL_Rect SinglePlayer = { 0, 191, 515, ItemHeight }; - SinglePlayer.x = GetCenterOffset(SinglePlayer.w); - SDL_Rect MultiPlayer = SinglePlayer; - MultiPlayer.y += ItemHeight * 1; - SDL_Rect ReplayIntro = MultiPlayer; - ReplayIntro.y += ItemHeight * 2; - SDL_Rect ShowCredits = ReplayIntro; - ShowCredits.y += ItemHeight * 3; - SDL_Rect ExitDiablo = ShowCredits; - ExitDiablo.y += ItemHeight * 4; + UI_Item MAINMENU_DIALOG[] = { + { { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground }, + { { 64, 192, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_SINGLE_PLAYER, "Single Player" }, + { { 64, 235, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_MULTIPLAYER, "Multi Player" }, + { { 64, 277, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_REPLAY_INTRO, "Replay Intro" }, + { { 64, 320, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_SHOW_CREDITS, "Show Credits" }, + { { 64, 363, 510, 43 }, UI_LIST, UIS_HUGE | UIS_GOLD | UIS_CENTER, MAINMENU_EXIT_DIABLO, "Exit Diablo" }, + { { 17, 444, 605, 21 }, UI_TEXT, UIS_SMALL, 0, name }, + }; - bool endMenu = false; + gfnSoundFunction = fnSound; + mainmenu_Load(); - while (!endMenu) { - CapFPS(); - mainmenu_Render(name); + while (MainMenuResult == 0) { + UiRenderItems(MAINMENU_DIALOG, size(MAINMENU_DIALOG)); + DrawLogo(); DrawMouse(); UiFadeIn(); while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYDOWN: - if (UiFocuseNavigation(&event, true)) - break; - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - *pdwResult = MAINMENU_EXIT_DIABLO; - UiPlaySelectSound(); - Sleep(250); // Wait for soudn to play - endMenu = true; - break; - case SDLK_RETURN: - case SDLK_KP_ENTER: - case SDLK_SPACE: - switch (SelectedItem) { - case MAINMENU_SINGLE_PLAYER: - UiPlaySelectSound(); - *pdwResult = MAINMENU_SINGLE_PLAYER; - endMenu = true; - break; - case MAINMENU_MULTIPLAYER: - UiPlaySelectSound(); - *pdwResult = MAINMENU_MULTIPLAYER; - endMenu = true; - break; - case MAINMENU_REPLAY_INTRO: - UiPlaySelectSound(); - *pdwResult = MAINMENU_REPLAY_INTRO; - endMenu = true; - break; - case MAINMENU_SHOW_CREDITS: - UiPlaySelectSound(); - *pdwResult = MAINMENU_SHOW_CREDITS; - endMenu = true; - break; - case MAINMENU_EXIT_DIABLO: - UiPlaySelectSound(); - Sleep(250); // Wait for sound to play - *pdwResult = MAINMENU_EXIT_DIABLO; - endMenu = true; - break; - } - break; - } - break; - case SDL_MOUSEBUTTONDOWN: - if (event.button.button == SDL_BUTTON_LEFT) { - if (IsInsideRect(&event, &SinglePlayer)) { - UiPlaySelectSound(); - *pdwResult = MAINMENU_SINGLE_PLAYER; - endMenu = true; - break; - } else if (IsInsideRect(&event, &MultiPlayer)) { - UiPlaySelectSound(); - *pdwResult = MAINMENU_MULTIPLAYER; - endMenu = true; - break; - } else if (IsInsideRect(&event, &ReplayIntro)) { - UiPlaySelectSound(); - *pdwResult = MAINMENU_REPLAY_INTRO; - endMenu = true; - break; - } else if (IsInsideRect(&event, &ShowCredits)) { - UiPlaySelectSound(); - *pdwResult = MAINMENU_SHOW_CREDITS; - endMenu = true; - break; - } else if (IsInsideRect(&event, &ExitDiablo)) { - UiPlaySelectSound(); - Sleep(250); // Wait for soudn to play - *pdwResult = MAINMENU_EXIT_DIABLO; - endMenu = true; - break; - } - } - break; - case SDL_QUIT: - *pdwResult = MAINMENU_EXIT_DIABLO; - endMenu = true; - break; - } + if (UiMainMenuEvent(&event)) + continue; + UiItemMouseEvents(&event, MAINMENU_DIALOG, size(MAINMENU_DIALOG)); } } BlackPalette(); - mainmenu_Free(); + *pdwResult = MainMenuResult; return TRUE; } diff --git a/Stub/DiabloUI/progress.cpp b/Stub/DiabloUI/progress.cpp index f3bc906bf..25f99eb1c 100644 --- a/Stub/DiabloUI/progress.cpp +++ b/Stub/DiabloUI/progress.cpp @@ -75,7 +75,6 @@ int __stdcall UiProgressDialog(HWND window, char *msg, int enable, int(__cdecl * SDL_Event event; while (!endMenu && progress < 100) { - CapFPS(); progress = fnfunc(); progress_Render(progress); DrawMouse(); diff --git a/Stub/DiabloUI/sdlrender.h b/Stub/DiabloUI/sdlrender.h index 87da85591..52ac23498 100644 --- a/Stub/DiabloUI/sdlrender.h +++ b/Stub/DiabloUI/sdlrender.h @@ -26,6 +26,42 @@ typedef enum _artFontColors { AFC_GOLD, } _artFontColors; +typedef enum UiTypes { + UI_TEXT, + UI_IMAGE, + UI_BUTTON, + UI_LIST, + UI_EDIT, +} UiTypes; + +typedef enum UiFlags { + UIS_SMALL = 0x1, + UIS_MED = 0x10, + UIS_BIG = 0x100, + UIS_HUGE = 0x1000, + UIS_CENTER = 0x10000, + UIS_RIGHT = 0x100000, + UIS_VCENTER = 0x1000000, + UIS_SILVER = 0x10000000, + UIS_GOLD = 0x100000000, + UIS_SML1 = 0x1000000000, + UIS_SML2 = 0x10000000000, + UIS_LIST = 0x100000000000, + UIS_DISABLED = 0x1000000000000, + UIS_HIDDEN = 0x10000000000000, +} UiFlags; + +typedef enum selheromenu_selections +{ + SELHERO_LIST, + SELHERO_CLASSES, + SELHERO_NAME, + SELHERO_LOAD, + SELHERO_SELECT_GAME, + SELHERO_DIFFICULTY, +} selheromenu_selections; + + typedef struct Art { BYTE *data; DWORD width; @@ -34,6 +70,15 @@ typedef struct Art { BYTE mask; } Art; +typedef struct UI_Item { + SDL_Rect rect; + UiTypes type; + UiFlags flags; + int value; + BYTE *caption; + void *context; +} UI_Item; + extern TTF_Font *font; extern BYTE *FontTables[4]; @@ -44,44 +89,44 @@ extern Art ArtBackground; extern Art ArtCursor; extern Art ArtHero; -extern int SelectedItem; -extern int SelectedItemMax; - extern int SCREEN_WIDTH; extern int SCREEN_HEIGHT; -extern int submenu; - typedef enum TXT_JUST { JustLeft = 0, JustCentre = 1, JustRight = 2, } TXT_JUST; +template +constexpr size_t size(T (&)[N]) +{ + return N; +} + extern void(__stdcall *gfnSoundFunction)(char *file); -DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, char *lpBuffer, DWORD nSize, va_list *Arguments); -int MAKEINTRESOURCE(int i); -int DialogBoxParam(HINSTANCE hInstance, int msgId, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); -BOOL SetDlgItemText(HWND hDlg, int nIDDlgItem, LPCSTR lpString); BOOL EndDialog(HWND hDlg, INT_PTR nResult); +BOOL SetDlgItemText(HWND hDlg, int nIDDlgItem, LPCSTR lpString); BOOL SetWindowPos(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags); +DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, char *lpBuffer, DWORD nSize, va_list *Arguments); +int DialogBoxParam(HINSTANCE hInstance, int msgId, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); +int MAKEINTRESOURCE(int i); bool IsInsideRect(const SDL_Event *event, const SDL_Rect *rect); bool UiFadeIn(int steps = 16); +bool UiFocusNavigation(SDL_Event *event, bool wrap = false); +bool UiItemMouseEvents(SDL_Event *event, UI_Item *items, int size); int GetAnimationFrame(int frames, int fps = 60); int GetCenterOffset(int w, int bw = 0); -void CapFPS(); void DrawArt(int screenX, int screenY, Art *art, int nFrame = 0, int drawW = 0); -void DrawArtStr(int x, int y, int size, int color, BYTE *str, TXT_JUST align = JustLeft, int bw = 0); void DrawLogo(int t = 0, int size = LOGO_MED); void DrawMouse(); -void DrawSelector(int x, int y, int width, int padding, int spacing = 0, int size = FOCUS_MED); void LoadArt(char *pszFile, Art *art, int frames = 1, PALETTEENTRY *pPalette = NULL); -void LoadMaskedArtFont(char *pszFile, Art *art, int frames, int mask = 250); void LoadBackgroundArt(char *pszFile); +void LoadMaskedArtFont(char *pszFile, Art *art, int frames, int mask = 250); void SetMenu(int MenuId); -void UiFocuse(int move, bool wrap = false); -bool UiFocuseNavigation(SDL_Event *event, bool wrap = false); -void UiPlayMoveSound(); -void UiPlaySelectSound(); +void UiFocusNavigationSelect(); +void UiInitList(int min, int max, void(__stdcall *fnFocus)(int value) = NULL, void(__stdcall *fnSelect)(int value) = NULL); +void UiRenderItems(UI_Item *items, int size); +void WordWrap(UI_Item *item); diff --git a/Stub/DiabloUI/selconn.cpp b/Stub/DiabloUI/selconn.cpp index c5a7a6e64..347963766 100644 --- a/Stub/DiabloUI/selconn.cpp +++ b/Stub/DiabloUI/selconn.cpp @@ -1,67 +1,108 @@ -#include "../../types.h" +#include "selconn.h" + +char selconn_MaxPlayers[21]; +char selconn_Description[64]; +char selconn_Gateway[129]; +bool selconn_ReturnValue = false; +bool selconn_EndMenu = false; +_SNETPROGRAMDATA *selconn_ClientInfo; +_SNETPLAYERDATA *selconn_UserInfo; +_SNETUIDATA *selconn_UiInfo; +_SNETVERSIONDATA *selconn_FileInfo; + +UI_Item SELCONNECT_DIALOG[] = { + { { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground }, + { { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Multi Player Game" }, + { { 300, 211, 295, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Connection" }, + { { 305, 256, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD, 0, "Local Area Network (UDP)" }, + { { 305, 282, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD, 1, "Solo" }, + { { 305, 308, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD }, + { { 305, 334, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD }, + { { 305, 360, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD }, + { { 305, 386, 285, 26 }, UI_LIST, UIS_CENTER | UIS_VCENTER | UIS_GOLD }, + { { 35, 218, 205, 21 }, UI_TEXT, 0, 0, selconn_MaxPlayers }, // Max players + { { 35, 256, 205, 21 }, UI_TEXT, 0, 0, "Requirements:" }, + { { 35, 275, 205, 66 }, UI_TEXT, 0, 0, selconn_Description }, //Description + { { 30, 356, 220, 31 }, UI_TEXT, UIS_CENTER | UIS_MED, 0, "no gateway needed" }, + { { 35, 393, 205, 21 }, UI_TEXT, UIS_CENTER, 0, selconn_Gateway }, // Gateway + { { 16, 427, 250, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD | UIS_HIDDEN, 0, "Change Gateway" }, + { { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", UiFocusNavigationSelect }, + { { 454, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel", selconn_Esc }, +}; -void selconn_Render() +void selconn_Load() { - DrawArt(0, 0, &ArtBackground); - DrawLogo(); - - DrawArtStr(0, 161, AFT_BIG, AFC_SILVER, "Multi Player Game", JustCentre); + LoadBackgroundArt("ui_art\\selconn.pcx"); + UiInitList(0, 1, selconn_Focus, selconn_Select); +} - int w = 335; - int x = 280; - int y = 261; +void selconn_Free() +{ + mem_free_dbg(ArtBackground.data); + ArtBackground.data = NULL; +} - DrawArtStr(x, 211, AFT_BIG, AFC_SILVER, "Select Connection", JustCentre, w); +void selconn_Esc() +{ + selconn_ReturnValue = false; + selconn_EndMenu = true; +} - char *connections[2] = { - //"Battle.net", - //"Local Area Network (IPC)", - //"Modem", - //"Direct Cable Connection", - "Local Area Network (UDP)", - "Solo", - }; +void selconn_Focus(int value) +{ + int players = 4; + switch (value) { + case 0: + sprintf(selconn_Description, "All computers must be connected to an UDP-compatible network."); + players = 4; + break; + case 1: + sprintf(selconn_Description, "Play by your self with no network exposure."); + players = 1; + break; + } - int spacing = 26; - int selectorTop = y; + sprintf(selconn_MaxPlayers, "Players Supported: %d", players); - for (int i = 0; i < 2; i++) { - DrawArtStr(x, y, AFT_SMALL, AFC_GOLD, connections[i], JustCentre, w); - y += spacing; + for (auto &item : SELCONNECT_DIALOG) { + if (item.caption != NULL && !(item.flags & (UIS_VCENTER | UIS_CENTER))) + WordWrap(&item); } +} - DrawSelector(x, selectorTop - 2, w, 25, spacing, FOCUS_SMALL); - - if (SelectedItem == 1) { - DrawArtStr(35, 218, AFT_SMALL, AFC_SILVER, "Players Supported: 4"); - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Requirements:"); - // TODO need a word wrap function - DrawArtStr(35, 275, AFT_SMALL, AFC_SILVER, "All computers must be"); - DrawArtStr(35, 291, AFT_SMALL, AFC_SILVER, "connected to an"); - DrawArtStr(35, 307, AFT_SMALL, AFC_SILVER, "UDP-compatible network."); - } else { - DrawArtStr(35, 218, AFT_SMALL, AFC_SILVER, "Players Supported: 1"); - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Play by your self with"); - DrawArtStr(35, 275, AFT_SMALL, AFC_SILVER, "no network exposure."); +void selconn_Select(int value) +{ + DWORD provider; + switch (value) { + case 0: + provider = 'UDPN'; + break; + case 1: + provider = 'SCBL'; + break; } - DrawArtStr(26, 356, AFT_MED, AFC_SILVER, "no gateway needed", JustCentre, 226); - - DrawArtStr(349, 429, AFT_BIG, AFC_GOLD, "OK"); - DrawArtStr(476, 429, AFT_BIG, AFC_GOLD, "Cancel"); + selconn_Free(); + selconn_EndMenu = SNetInitializeProvider(provider, selconn_ClientInfo, selconn_UserInfo, selconn_UiInfo, selconn_FileInfo); + selconn_Load(); } -void selconn_Load() +bool selconn_Event(SDL_Event *event) { - LoadBackgroundArt("ui_art\\selconn.pcx"); - SelectedItem = 1; - SelectedItemMax = 2; -} + switch (event->type) { + case SDL_KEYDOWN: + if (UiFocusNavigation(event)) + return true; + if (event->key.keysym.sym == SDLK_ESCAPE) { + selconn_Esc(); + return true; + } + break; + case SDL_QUIT: + exit(0); + } -void selconn_Free() -{ - mem_free_dbg(ArtBackground.data); - ArtBackground.data = NULL; + return false; } int __stdcall UiSelectProvider( @@ -72,69 +113,30 @@ int __stdcall UiSelectProvider( _SNETVERSIONDATA *file_info, int *type) { + selconn_ClientInfo = client_info; + selconn_UserInfo = user_info; + selconn_UiInfo = ui_info; + selconn_FileInfo = file_info; selconn_Load(); SDL_Event event; - bool rv = true; - bool endMenu = false; - while (!endMenu) { - CapFPS(); - selconn_Render(); + selconn_ReturnValue = true; + selconn_EndMenu = false; + while (!selconn_EndMenu) { + UiRenderItems(SELCONNECT_DIALOG, size(SELCONNECT_DIALOG)); + DrawLogo(); DrawMouse(); UiFadeIn(); while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_KEYDOWN: - if (UiFocuseNavigation(&event)) - break; - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - rv = false; - endMenu = true; - break; - case SDLK_RETURN: - case SDLK_KP_ENTER: - case SDLK_SPACE: - UiPlaySelectSound(); - DWORD provider; - switch (SelectedItem) { - /* - case 1: - provider = 'BNET'; - break; - case 2: - provider = 'IPXN'; - break; - case 3: - provider = 'MODM'; - break; - case 4: - provider = 'SCBL'; - break; - case 5:*/ - case 1: - provider = 'UDPN'; - break; - case 2: - provider = 'SCBL'; - break; - } - selconn_Free(); - endMenu = SNetInitializeProvider(provider, client_info, user_info, ui_info, file_info); - selconn_Load(); - break; - } - break; - case SDL_QUIT: - exit(0); - } + if (selconn_Event(&event)) + continue; + UiItemMouseEvents(&event, SELCONNECT_DIALOG, size(SELCONNECT_DIALOG)); } } BlackPalette(); - selconn_Free(); - return rv; + return selconn_ReturnValue; } diff --git a/Stub/DiabloUI/selconn.h b/Stub/DiabloUI/selconn.h new file mode 100644 index 000000000..d92b76191 --- /dev/null +++ b/Stub/DiabloUI/selconn.h @@ -0,0 +1,5 @@ +#include "../../types.h" + +void selconn_Esc(); +void selconn_Focus(int value); +void selconn_Select(int value); diff --git a/Stub/DiabloUI/selhero.cpp b/Stub/DiabloUI/selhero.cpp index 604524f8c..f793bb1a7 100644 --- a/Stub/DiabloUI/selhero.cpp +++ b/Stub/DiabloUI/selhero.cpp @@ -1,101 +1,119 @@ -#include "../../types.h" +#include "selhero.h" #include int selhero_SaveCount = 0; _uiheroinfo heros[MAX_CHARACTERS]; _uiheroinfo heroInfo; - -void RenderStats() -{ - char lvl[4] = "--"; - char str[4] = "--"; - char mag[4] = "--"; - char dex[4] = "--"; - char vit[4] = "--"; - - if (heroInfo.heroclass != UI_NUM_CLASSES) { - sprintf(lvl, "%d", heroInfo.level); - sprintf(str, "%d", heroInfo.strength); - sprintf(mag, "%d", heroInfo.magic); - sprintf(dex, "%d", heroInfo.dexterity); - sprintf(vit, "%d", heroInfo.vitality); - } - - DrawArtStr(31, 323, AFT_SMALL, AFC_SILVER, "Level:", JustRight, 118); - DrawArtStr(149, 323, AFT_SMALL, AFC_SILVER, lvl, JustCentre, 61); - DrawArtStr(31, 358, AFT_SMALL, AFC_SILVER, "Strength:", JustRight, 118); - DrawArtStr(149, 358, AFT_SMALL, AFC_SILVER, str, JustCentre, 61); - DrawArtStr(31, 380, AFT_SMALL, AFC_SILVER, "Magic:", JustRight, 118); - DrawArtStr(149, 380, AFT_SMALL, AFC_SILVER, mag, JustCentre, 61); - DrawArtStr(31, 401, AFT_SMALL, AFC_SILVER, "Dexterity:", JustRight, 118); - DrawArtStr(149, 401, AFT_SMALL, AFC_SILVER, dex, JustCentre, 61); - DrawArtStr(31, 422, AFT_SMALL, AFC_SILVER, "Vitality:", JustRight, 118); - DrawArtStr(149, 422, AFT_SMALL, AFC_SILVER, vit, JustCentre, 61); -} - -void selhero_Render(bool multiPlayer) +char listItems[6][16]; +char textStats[5][4]; +char title[32]; +char selhero_Lable[32]; +char selhero_Description[256]; +int selhero_result; +bool selhero_return; +bool selhero_endMenu; +bool selhero_endMenu_Single; +int submenu = 0; +bool isMultiPlayer; +bool heroIsCreated; + +BOOL(__stdcall *gfnHeroStats) +(unsigned int, _uidefaultstats *); + +UI_Item SELHERO_DIALOG[] = { + { { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground }, + { { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, title }, + { { 30, 211, 180, 76 }, UI_IMAGE, 0, UI_NUM_CLASSES, NULL, &ArtHero }, + { { 39, 323, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Level:" }, + { { 159, 323, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[0] }, + { { 39, 358, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Strength:" }, + { { 159, 358, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[1] }, + { { 39, 380, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Magic:" }, + { { 159, 380, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[2] }, + { { 39, 401, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Dexterity:" }, + { { 159, 401, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[3] }, + { { 39, 422, 110, 21 }, UI_TEXT, UIS_RIGHT, 0, "Vitality:" }, + { { 159, 422, 40, 21 }, UI_TEXT, UIS_CENTER, 0, textStats[4] }, +}; + +UI_Item SELLIST_DIALOG[] = { + { { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Hero" }, + { { 265, 256, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 0, listItems[0] }, + { { 265, 282, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 1, listItems[1] }, + { { 265, 308, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 2, listItems[2] }, + { { 265, 334, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 3, listItems[3] }, + { { 265, 360, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 4, listItems[4] }, + { { 265, 386, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 5, listItems[5] }, + { { 239, 429, 120, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "OK", UiFocusNavigationSelect }, + { { 364, 429, 120, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_DISABLED, 0, "Delete" }, + { { 489, 429, 120, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "Cancel" }, +}; + +UI_Item SELCLASS_DIALOG[] = { + { { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Choose Class" }, + { { 264, 285, 320, 33 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, UI_WARRIOR, "Warrior" }, + { { 264, 318, 320, 33 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, UI_ROGUE, "Rogue" }, + { { 264, 352, 320, 33 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, UI_SORCERER, "Sorcerer" }, + { { 279, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "OK", UiFocusNavigationSelect }, + { { 429, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "Cancel" }, +}; + +UI_Item ENTERNAME_DIALOG[] = { + { { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Enter Name" }, + { { 265, 317, 320, 33 }, UI_EDIT, UIS_LIST | UIS_MED | UIS_GOLD, 0, heroInfo.name, 15 }, + { { 279, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "OK", UiFocusNavigationSelect }, + { { 429, 429, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_BIG | UIS_GOLD, 0, "Cancel" }, +}; + +UI_Item SELLOAD_DIALOG[] = { + { { 264, 211, 320, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Save File Exists" }, + { { 265, 285, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 0, "Load Game" }, + { { 265, 318, 320, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 1, "New Game" }, + { { 279, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", UiFocusNavigationSelect }, + { { 429, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel" }, +}; + +UI_Item SELUDPGAME_DIALOG[] = { + { { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground }, + { { 25, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Join UDP Games" }, + { { 300, 211, 295, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Action" }, + { { 305, 255, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 0, "Create Game" }, + { { 305, 281, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 1, "Enter IP" }, + { { 305, 307, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, 2, "Localhost" }, + { { 305, 333, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD }, + { { 305, 359, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD }, + { { 305, 385, 285, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD }, + { { 35, 211, 205, 33 }, UI_TEXT, UIS_MED, 0, "Description:" }, + { { 35, 256, 205, 192 }, UI_TEXT, 0, 0, selhero_Description }, // Description + { { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", UiFocusNavigationSelect }, + { { 449, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel" }, +}; + +UI_Item SELDIFF_DIALOG[] = { + { { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground }, + { { 24, 161, 590, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Create Game" }, + { { 299, 211, 295, 35 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, "Select Difficulty" }, + { { 300, 282, 295, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, DIFF_NORMAL, "Normal" }, + { { 300, 308, 295, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, DIFF_NIGHTMARE, "Nightmare" }, + { { 300, 334, 295, 26 }, UI_LIST, UIS_CENTER | UIS_MED | UIS_GOLD, DIFF_HELL, "Hell" }, + { { 34, 211, 205, 33 }, UI_TEXT, UIS_CENTER | UIS_BIG, 0, selhero_Lable }, // DIFF + { { 35, 256, 205, 192 }, UI_TEXT, 0, 0, selhero_Description }, // Description + { { 299, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "OK", UiFocusNavigationSelect }, + { { 449, 427, 140, 35 }, UI_BUTTON, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD, 0, "Cancel" }, +}; + +void selhero_SetStats() { - heroInfo.heroclass = UI_NUM_CLASSES; - if (SelectedItem <= selhero_SaveCount) { - memcpy(&heroInfo, &heros[SelectedItem - 1], sizeof(heroInfo)); - } - - DrawArt(0, 0, &ArtBackground); - DrawLogo(); - - char *title = "Single Player Characters"; - if (multiPlayer) { - title = "Multi Player Characters"; - } - DrawArtStr(0, 161, AFT_BIG, AFC_SILVER, title, JustCentre); - - DrawArt(30, 211, &ArtHero, heroInfo.heroclass); - RenderStats(); - - int w = 368; - int x = 241; - - DrawArtStr(x, 211, AFT_BIG, AFC_SILVER, "Select Hero", JustCentre, w); - - int spacing = 26; - int selectorTop = 256; - int y = selectorTop; - for (int i = 0; i < selhero_SaveCount; i++) { - DrawArtStr(x, y, AFT_MED, AFC_GOLD, heros[i].name, JustCentre, w); - y += spacing; - } - DrawArtStr(x, y, AFT_MED, AFC_GOLD, "New Hero", JustCentre, w); - - DrawSelector(x, selectorTop + 3, w, 24, spacing, FOCUS_SMALL); - - DrawArtStr(279, 429, AFT_BIG, AFC_GOLD, "OK"); - DrawArtStr(378, 429, AFT_BIG, AFC_GOLD, "Delete"); - DrawArtStr(501, 429, AFT_BIG, AFC_GOLD, "Cancel"); + SELHERO_DIALOG[2].value = heroInfo.heroclass; + sprintf(textStats[0], "%d", heroInfo.level); + sprintf(textStats[1], "%d", heroInfo.strength); + sprintf(textStats[2], "%d", heroInfo.magic); + sprintf(textStats[3], "%d", heroInfo.dexterity); + sprintf(textStats[4], "%d", heroInfo.vitality); } -void selhero_Render_Name(bool multiPlayer) +void selhero_Render_Name() { - DrawArt(0, 0, &ArtBackground); - DrawLogo(); - - DrawArt(30, 211, &ArtHero, heroInfo.heroclass); - RenderStats(); - - char *title = "New Single Player Hero"; - if (multiPlayer) { - title = "New Multi Player Hero"; - } - - DrawArtStr(0, 161, AFT_BIG, AFC_SILVER, title, JustCentre); - - int w = 368; - int x = 241; - int y = 318; - - DrawArtStr(x, 211, AFT_BIG, AFC_SILVER, "Enter Name", JustCentre, w); - - DrawSelector(x, y - 2, w, 24); - char lable[17]; strcpy(lable, heroInfo.name); if (GetAnimationFrame(2, 500)) { @@ -103,56 +121,77 @@ void selhero_Render_Name(bool multiPlayer) lable[len] = '|'; lable[len + 1] = '\0'; } + ENTERNAME_DIALOG[1].caption = lable; - DrawArtStr(x + 67, y, AFT_MED, AFC_GOLD, lable); // todo add blinking "|" - - DrawArtStr(329, 429, AFT_BIG, AFC_GOLD, "OK"); - DrawArtStr(451, 429, AFT_BIG, AFC_GOLD, "Cancel"); + UiRenderItems(ENTERNAME_DIALOG, size(ENTERNAME_DIALOG)); } -// Have this load the function above and then render it in the main menu. -// Cnacel box is also needed. -void selhero_Render_ClassSelector(bool multiPlayer) +BOOL __stdcall SelHero_GetHeroInfo(_uiheroinfo *pInfo) { - DrawArt(0, 0, &ArtBackground); - DrawLogo(); + heros[selhero_SaveCount] = *pInfo; + selhero_SaveCount++; - DrawArt(30, 211, &ArtHero, heroInfo.heroclass); - RenderStats(); + return TRUE; +} - char *title = "New Single Player Hero"; - if (multiPlayer) { - title = "New Multi Player Hero"; +void selhero_Focus_List(int value) +{ + if (selhero_SaveCount && value < selhero_SaveCount) { + memcpy(&heroInfo, &heros[value], sizeof(heroInfo)); + selhero_SetStats(); + return; } - DrawArtStr(0, 161, AFT_BIG, AFC_SILVER, title, JustCentre); - - int w = 369; - int x = 241; - int y = 285; - DrawArtStr(x, 211, AFT_BIG, AFC_SILVER, "Choose Class", JustCentre, w); - - char *heroclasses[3] = { "Warrior", "Rogue", "Sorcerer" }; + SELHERO_DIALOG[2].value = UI_NUM_CLASSES; + sprintf(textStats[0], "--"); + sprintf(textStats[1], "--"); + sprintf(textStats[2], "--"); + sprintf(textStats[3], "--"); + sprintf(textStats[4], "--"); +} - int spacing = 33; - int selectorTop = y; - for (int i = 0; i < 3; i++) { - DrawArtStr(x, y, AFT_MED, AFC_GOLD, heroclasses[i], JustCentre, w); - y += spacing; +void selhero_Select_ClassSelector(int value) +{ + submenu = SELHERO_NAME; + sprintf(title, "New Single Player Hero"); + if (isMultiPlayer) { + sprintf(title, "New Multi Player Hero"); } + memset(heroInfo.name, '\0', 16); + SDL_StartTextInput(); +} + +void selhero_Focus_ClassSelector(int value) +{ + _uidefaultstats defaults; + gfnHeroStats(value, &defaults); - DrawSelector(x, selectorTop - 2, w, 39, spacing); + heroInfo.level = 1; + heroInfo.heroclass = value; + heroInfo.strength = defaults.strength; + heroInfo.magic = defaults.magic; + heroInfo.dexterity = defaults.dexterity; + heroInfo.vitality = defaults.vitality; - DrawArtStr(329, 429, AFT_BIG, AFC_GOLD, "OK"); - DrawArtStr(451, 429, AFT_BIG, AFC_GOLD, "Cancel"); + selhero_SetStats(); } -BOOL __stdcall SelHero_GetHeroInfo(_uiheroinfo *pInfo) +void selhero_Select_List(int value) { - heros[selhero_SaveCount] = *pInfo; - selhero_SaveCount++; + if (value == selhero_SaveCount) { + submenu = SELHERO_CLASSES; + UiInitList(0, 2, selhero_Focus_ClassSelector, selhero_Select_ClassSelector); + memset(&heroInfo.name, 0, sizeof(heroInfo.name)); + sprintf(title, "New Single Player Hero"); + if (isMultiPlayer) { + sprintf(title, "New Multi Player Hero"); + } + return; + } - return TRUE; + heroIsCreated = true; + selhero_return = false; + selhero_endMenu = true; } void selhero_Load(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *))) @@ -161,94 +200,85 @@ void selhero_Load(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinf selhero_SaveCount = 0; fninfo(SelHero_GetHeroInfo); - - heroInfo.heroclass = UI_NUM_CLASSES; } void selhero_Free() { mem_free_dbg(ArtBackground.data); ArtBackground.data = NULL; + memset(listItems, 0, sizeof(listItems)); } -void selhero_setDefaultStats(BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *)) +void selhero_List_Esc() { - _uidefaultstats defaults; - fnstats(SelectedItem - 1, &defaults); - - heroInfo.heroclass = SelectedItem - 1; - heroInfo.strength = defaults.strength; - heroInfo.magic = defaults.magic; - heroInfo.dexterity = defaults.dexterity; - heroInfo.vitality = defaults.vitality; + selhero_return = true; + selhero_endMenu = true; } -bool selhero_Event(bool *aborted) +void selhero_Event_List() { SDL_Event event; while (SDL_PollEvent(&event)) { + if (UiFocusNavigation(&event)) + continue; + if (UiItemMouseEvents(&event, SELLIST_DIALOG, size(SELLIST_DIALOG))) + continue; switch (event.type) { case SDL_KEYDOWN: - if (UiFocuseNavigation(&event)) + if (event.key.keysym.sym == SDLK_ESCAPE) { + selhero_List_Esc(); break; - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - *aborted = true; - return true; - case SDLK_RETURN: - case SDLK_KP_ENTER: - case SDLK_SPACE: - if (SelectedItem == SelectedItemMax) { - memset(&heroInfo.name, 0, sizeof(heroInfo.name)); - SetMenu(SELHERO_CLASSES); - break; - } - return true; } break; case SDL_QUIT: exit(0); } } +} - return false; +void selhero_init_List() +{ + submenu = SELHERO_LIST; + UiInitList(0, selhero_SaveCount, selhero_Focus_List, selhero_Select_List); + int i; + for (i = 0; i < selhero_SaveCount && i < 6; i++) { + sprintf(listItems[i], heros[i].name); + } + if (i < 6) + sprintf(listItems[i], "New Hero"); + + sprintf(title, "Single Player Characters"); + if (isMultiPlayer) { + sprintf(title, "Multi Player Characters"); + } } -bool selhero_Event_ClassSelector(bool *aborted) +void selhero_Event_ClassSelector() { SDL_Event event; while (SDL_PollEvent(&event)) { + if (UiFocusNavigation(&event)) + continue; + if (UiItemMouseEvents(&event, SELCLASS_DIALOG, size(SELCLASS_DIALOG))) + continue; switch (event.type) { case SDL_KEYDOWN: - if (UiFocuseNavigation(&event, true)) - break; - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: + if (event.key.keysym.sym == SDLK_ESCAPE) { if (selhero_SaveCount) { - SetMenu(SELHERO_LOAD); - SelectedItemMax += selhero_SaveCount; + selhero_init_List(); break; } - *aborted = true; - return true; - case SDLK_RETURN: - case SDLK_KP_ENTER: - case SDLK_SPACE: - SetMenu(SELHERO_NAME); - memset(heroInfo.name, '\0', 16); - SDL_StartTextInput(); - break; + selhero_return = true; + selhero_endMenu = true; } break; case SDL_QUIT: exit(0); } } - - return false; } -bool selhero_CatToName(char *in_buf) +void selhero_CatToName(char *in_buf) { iconv_t cd = iconv_open("ISO_8859-1//TRANSLIT//IGNORE", "UTF-8"); if (cd == (iconv_t)-1) { @@ -267,11 +297,10 @@ bool selhero_CatToName(char *in_buf) strncat(heroInfo.name, output, 15 - strlen(heroInfo.name)); } -bool selhero_Event_Name() +void selhero_Event_Name() { SDL_Event event; while (SDL_PollEvent(&event)) { - switch (event.type) { case SDL_QUIT: exit(0); @@ -285,13 +314,13 @@ bool selhero_Event_Name() break; case SDLK_ESCAPE: SDL_StopTextInput(); - SetMenu(SELHERO_CLASSES); + selhero_Select_List(selhero_SaveCount); break; case SDLK_RETURN: case SDLK_RETURN2: case SDLK_KP_ENTER: SDL_StopTextInput(); - return true; + selhero_endMenu = true; break; case SDLK_BACKSPACE: case SDLK_LEFT: @@ -307,55 +336,88 @@ bool selhero_Event_Name() break; } } +} - return false; +void selhero_Event_Load() +{ + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (UiFocusNavigation(&event, true)) + continue; + if (UiItemMouseEvents(&event, SELLOAD_DIALOG, size(SELLOAD_DIALOG))) + continue; + switch (event.type) { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_ESCAPE: + selhero_result = EXIT_MENU; + selhero_endMenu_Single = true; + } + break; + case SDL_QUIT: + exit(0); + } + } } bool UiSelHeroDialog( BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *), - BOOL(__stdcall *fnstats)(unsigned int, _uidefaultstats *), bool multiPlayer) { - bool aborted = false; - bool endMenu = false; + isMultiPlayer = multiPlayer; + selhero_return = false; + selhero_endMenu = false; + heroIsCreated = false; - SelectedItem = 1; - submenu = SELHERO_LOAD; - SelectedItemMax = 1 + selhero_SaveCount; - if (!selhero_SaveCount) { - submenu = SELHERO_CLASSES; - SelectedItemMax = 3; + if (selhero_SaveCount) { + selhero_init_List(); + } else { + selhero_Select_List(selhero_SaveCount); } - while (endMenu == false) { - CapFPS(); - + while (!selhero_endMenu) { + UiRenderItems(SELHERO_DIALOG, size(SELHERO_DIALOG)); switch (submenu) { - case SELHERO_LOAD: - selhero_Render(multiPlayer); - endMenu = selhero_Event(&aborted); + case SELHERO_LIST: + UiRenderItems(SELLIST_DIALOG, size(SELLIST_DIALOG)); + selhero_Event_List(); break; case SELHERO_CLASSES: - selhero_setDefaultStats(fnstats); - selhero_Render_ClassSelector(multiPlayer); - endMenu = selhero_Event_ClassSelector(&aborted); + UiRenderItems(SELCLASS_DIALOG, size(SELCLASS_DIALOG)); + selhero_Event_ClassSelector(); break; case SELHERO_NAME: - selhero_Render_Name(multiPlayer); - endMenu = selhero_Event_Name(); + selhero_Render_Name(); + selhero_Event_Name(); break; } + DrawLogo(); DrawMouse(); UiFadeIn(); } - if (!aborted && !heroInfo.hassaved) { - fncreate(&heroInfo); // todo don't overwrite + if (!heroIsCreated) { + fncreate(&heroInfo); + } + + return selhero_return; +} + +void selhero_Select_Load(int value) +{ + selhero_endMenu_Single = true; + if (value == 0) { + selhero_result = LOAD_GAME; + return; } - return aborted; + selhero_result = NEW_GAME; +} + +void selhero_Focus_Load(int value) +{ } BOOL __stdcall UiSelHeroSingDialog( @@ -367,20 +429,38 @@ BOOL __stdcall UiSelHeroSingDialog( char *name, int *difficulty) { + gfnHeroStats = fnstats; + selhero_Load(fninfo); - if (UiSelHeroDialog(fncreate, fnremove, fnstats, false)) { + bool abort = UiSelHeroDialog(fncreate, fnremove, false); + if (abort) { + BlackPalette(); + selhero_Free(); *dlgresult = EXIT_MENU; - } else { - strcpy(name, heroInfo.name); + return TRUE; + } - if (heroInfo.hassaved) { - *dlgresult = LOAD_GAME; + strcpy(name, heroInfo.name); + + if (heroInfo.hassaved) { + UiInitList(0, 1, selhero_Focus_Load, selhero_Select_Load); + sprintf(title, "Single Player Characters"); + + selhero_endMenu_Single = false; + while (!selhero_endMenu_Single) { + UiRenderItems(SELHERO_DIALOG, size(SELHERO_DIALOG)); + UiRenderItems(SELLOAD_DIALOG, size(SELLOAD_DIALOG)); + DrawLogo(); + DrawMouse(); + UiFadeIn(); + selhero_Event_Load(); } } BlackPalette(); selhero_Free(); + *dlgresult = selhero_result; return TRUE; } @@ -399,192 +479,107 @@ void selhero_multi_Free() ArtBackground.data = NULL; } -void selhero_Render_DifficultySelection() +void selhero_Focus_Diff(int value) { - DrawArt(0, 0, &ArtBackground); - DrawLogo(); - - DrawArtStr(0, 161, AFT_BIG, AFC_SILVER, "Create Game", JustCentre); - - int w = 333; - int x = 281; - int y = 282; - - DrawArtStr(x, 211, AFT_BIG, AFC_SILVER, "Select Difficulty", JustCentre, w); - - char *gameOptions[] = { "Normal", "Nightmare", "Hell" }; - - DrawArtStr(23, 211, AFT_BIG, AFC_SILVER, gameOptions[SelectedItem - 1], JustCentre, 226); - if (SelectedItem == 1) { - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Normal Difficulty"); - DrawArtStr(35, 272, AFT_SMALL, AFC_SILVER, "This is where a starting"); - DrawArtStr(35, 288, AFT_SMALL, AFC_SILVER, "character should begin"); - DrawArtStr(35, 304, AFT_SMALL, AFC_SILVER, "the quest to defeat"); - DrawArtStr(35, 320, AFT_SMALL, AFC_SILVER, "Diablo."); - } else if (SelectedItem == 2) { - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Nightmare Difficulty"); - DrawArtStr(35, 272, AFT_SMALL, AFC_SILVER, "The denizens of the"); - DrawArtStr(35, 288, AFT_SMALL, AFC_SILVER, "Labyrinth have been"); - DrawArtStr(35, 304, AFT_SMALL, AFC_SILVER, "bolstered and will prove"); - DrawArtStr(35, 320, AFT_SMALL, AFC_SILVER, "to be a greater"); - DrawArtStr(35, 336, AFT_SMALL, AFC_SILVER, "challenge. This is"); - DrawArtStr(35, 352, AFT_SMALL, AFC_SILVER, "recommended for"); - DrawArtStr(35, 368, AFT_SMALL, AFC_SILVER, "experienced characters"); - DrawArtStr(35, 384, AFT_SMALL, AFC_SILVER, "only."); - } else if (SelectedItem == 3) { - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Hell Difficulty"); - DrawArtStr(35, 272, AFT_SMALL, AFC_SILVER, "The most powerful of"); - DrawArtStr(35, 288, AFT_SMALL, AFC_SILVER, "the underworld's"); - DrawArtStr(35, 304, AFT_SMALL, AFC_SILVER, "creatures lurk at the"); - DrawArtStr(35, 320, AFT_SMALL, AFC_SILVER, "gateway into Hell. Only"); - DrawArtStr(35, 336, AFT_SMALL, AFC_SILVER, "the most experienced"); - DrawArtStr(35, 352, AFT_SMALL, AFC_SILVER, "characters should"); - DrawArtStr(35, 368, AFT_SMALL, AFC_SILVER, "venture in this realm."); + switch (value) { + case DIFF_NORMAL: + sprintf(selhero_Lable, "Normal"); + sprintf(selhero_Description, "Normal Difficulty\nThis is where a starting character should begin the quest to defeat Diablo."); + break; + case DIFF_NIGHTMARE: + sprintf(selhero_Lable, "Nightmare"); + sprintf(selhero_Description, "Nightmare Difficulty\nThe denizens of the Labyrinth have been bolstered and will prove to be a greater challenge. This is recommended for experienced characters only."); + break; + case DIFF_HELL: + sprintf(selhero_Lable, "Hell"); + sprintf(selhero_Description, "Hell Difficulty\nThe most powerful of the underworld's creatures lurk at the gateway into Hell. Only the most experienced characters should venture in this realm."); + break; } - int selectorTop = y; - - int spacing = 26; - for (int i = 0; i < 3; i++) { - DrawArtStr(x, y, AFT_MED, AFC_GOLD, gameOptions[i], JustCentre, w); - y += spacing; + for (auto &item : SELDIFF_DIALOG) { + if (item.caption != NULL && !(item.flags & (UIS_VCENTER | UIS_CENTER))) + WordWrap(&item); } +} - DrawSelector(x, selectorTop + 3, w, 19, spacing, FOCUS_SMALL); +void selhero_Select_Diff(int value) +{ + gnDifficulty = value; + selhero_result = NEW_GAME; +} - DrawArtStr(349, 429, AFT_BIG, AFC_GOLD, "OK"); - DrawArtStr(471, 429, AFT_BIG, AFC_GOLD, "Cancel"); +void selhero_Select_GameSelection(int value) +{ + submenu = SELHERO_DIFFICULTY; + UiInitList(0, 2, selhero_Focus_Diff, selhero_Select_Diff); } -bool selhero_Event_GameSelection(int *dlgresult) +void selhero_Event_GameSelection() { SDL_Event event; while (SDL_PollEvent(&event)) { + if (UiFocusNavigation(&event)) + continue; + if (UiItemMouseEvents(&event, SELUDPGAME_DIALOG, size(SELUDPGAME_DIALOG))) + continue; switch (event.type) { case SDL_KEYDOWN: - if (UiFocuseNavigation(&event)) - break; - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - *dlgresult = EXIT_MENU; - return true; - case SDLK_RETURN: - case SDLK_KP_ENTER: - case SDLK_SPACE: - SetMenu(SELHERO_DIFFICULTY); - break; + if (event.key.keysym.sym == SDLK_ESCAPE) { + selhero_result = EXIT_MENU; + selhero_endMenu_Single = true; } break; case SDL_QUIT: exit(0); } } +} + +void selhero_Focus_GameSelection(int value) +{ + switch (value) { + case 0: + sprintf(selhero_Description, "Create a new game with a difficulty setting of your choice."); + break; + case 1: + sprintf(selhero_Description, "Join a game directly via a know host IP."); + break; + default: + sprintf(selhero_Description, "%s.\nCreated by %s, a level %d %s.", "Normal Difficulty", "Localhost", 1, "Warrior"); + break; + } - return false; + for (auto &item : SELUDPGAME_DIALOG) { + if (item.caption != NULL && !(item.flags & (UIS_VCENTER | UIS_CENTER))) + WordWrap(&item); + } } -bool selhero_Event_DifficultySelection(int *dlgresult) +void selhero_Event_DifficultySelection() { SDL_Event event; while (SDL_PollEvent(&event)) { + if (UiFocusNavigation(&event)) + continue; + if (UiItemMouseEvents(&event, SELDIFF_DIALOG, size(SELDIFF_DIALOG))) + continue; switch (event.type) { case SDL_KEYDOWN: - if (UiFocuseNavigation(&event, true)) - break; switch (event.key.keysym.sym) { case SDLK_ESCAPE: - SetMenu(SELHERO_SELECT_GAME); - SelectedItemMax += 1; + submenu = SELHERO_SELECT_GAME; + UiInitList(0, 2, selhero_Focus_GameSelection, selhero_Select_GameSelection); break; case SDLK_RETURN: case SDLK_KP_ENTER: case SDLK_SPACE: - switch (SelectedItem) { - case 1: - gnDifficulty = DIFF_NORMAL; - break; - case 2: - gnDifficulty = DIFF_NIGHTMARE; - break; - case 3: - gnDifficulty = DIFF_HELL; - break; - } - *dlgresult = NEW_GAME; - return true; - } - break; - case SDL_MOUSEBUTTONDOWN: - if (event.button.button == SDL_BUTTON_LEFT) { - SDL_Rect CreateHeroCancelBox; - CreateHeroCancelBox.y = 550; - CreateHeroCancelBox.x = 675; - CreateHeroCancelBox.w = 100; - CreateHeroCancelBox.h = 30; - - SDL_Rect NormalSelectBox; - NormalSelectBox.x = 280; - NormalSelectBox.y = 350; - NormalSelectBox.w = 300; - NormalSelectBox.h = 30; - - if (IsInsideRect(&event, &NormalSelectBox)) { - gnDifficulty = DIFF_NORMAL; - *dlgresult = LOAD_GAME; - } - break; + selhero_endMenu_Single = true; } break; case SDL_QUIT: exit(0); } } - - return false; -} - -void selhero_Render_GameSelection() -{ - - DrawArt(0, 0, &ArtBackground); - DrawLogo(); - - DrawArtStr(0, 161, AFT_BIG, AFC_SILVER, "Join UPD Game", JustCentre); - - int w = 333; - int x = 281; - int y = 282; - - DrawArtStr(x, 211, AFT_BIG, AFC_SILVER, "Select Action", JustCentre, w); - - char *gameOptions[] = { "Create Game", "Enter IP", "Localhost" }; - - DrawArtStr(35, 211, AFT_MED, AFC_SILVER, "Description:"); - if (SelectedItem == 1) { - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Create a new game with"); - DrawArtStr(35, 272, AFT_SMALL, AFC_SILVER, "a difficulty setting of"); - DrawArtStr(35, 288, AFT_SMALL, AFC_SILVER, "your choice."); - } else if (SelectedItem == 2) { - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Join a game directly"); - DrawArtStr(35, 272, AFT_SMALL, AFC_SILVER, "via a know host IP."); - } else { - DrawArtStr(35, 256, AFT_SMALL, AFC_SILVER, "Normal Difficulty"); - DrawArtStr(35, 272, AFT_SMALL, AFC_SILVER, "Created by Localhost, A"); - DrawArtStr(35, 288, AFT_SMALL, AFC_SILVER, "level 1 Warrior."); - } - - int selectorTop = y; - - int spacing = 26; - for (int i = 0; i < 3; i++) { - DrawArtStr(x, y, AFT_MED, AFC_GOLD, gameOptions[i], JustCentre, w); - y += spacing; - } - - DrawSelector(x, selectorTop + 3, w, 19, spacing, FOCUS_SMALL); - - DrawArtStr(349, 429, AFT_BIG, AFC_GOLD, "OK"); - DrawArtStr(471, 429, AFT_BIG, AFC_GOLD, "Cancel"); } BOOL __stdcall UiSelHeroMultDialog( @@ -596,10 +591,11 @@ BOOL __stdcall UiSelHeroMultDialog( BOOL *hero_is_created, char *name) { + gfnHeroStats = fnstats; *hero_is_created = false; selhero_Load(fninfo); - bool abort = UiSelHeroDialog(fncreate, fnremove, fnstats, true); + bool abort = UiSelHeroDialog(fncreate, fnremove, true); BlackPalette(); selhero_Free(); if (abort) { @@ -612,35 +608,28 @@ BOOL __stdcall UiSelHeroMultDialog( selhero_multi_Load(); submenu = SELHERO_SELECT_GAME; + UiInitList(0, 2, selhero_Focus_GameSelection, selhero_Select_GameSelection); - SelectedItem = 1; - SelectedItemMax = 2 + 1; - - bool endMenu = false; - while (endMenu == false) { - CapFPS(); - + selhero_endMenu_Single = false; + while (!selhero_endMenu_Single) { switch (submenu) { case SELHERO_SELECT_GAME: - selhero_Render_GameSelection(); - endMenu = selhero_Event_GameSelection(dlgresult); + UiRenderItems(SELUDPGAME_DIALOG, size(SELUDPGAME_DIALOG)); + selhero_Event_GameSelection(); break; case SELHERO_DIFFICULTY: - selhero_Render_DifficultySelection(); - endMenu = selhero_Event_DifficultySelection(dlgresult); + UiRenderItems(SELDIFF_DIALOG, size(SELDIFF_DIALOG)); + selhero_Event_DifficultySelection(); break; } - + DrawLogo(); DrawMouse(); UiFadeIn(); } - if (*dlgresult != EXIT_MENU) { - strcpy(name, heroInfo.name); - } - BlackPalette(); selhero_Free(); + *dlgresult = selhero_result; return TRUE; } diff --git a/Stub/DiabloUI/selhero.h b/Stub/DiabloUI/selhero.h new file mode 100644 index 000000000..7908bfa2d --- /dev/null +++ b/Stub/DiabloUI/selhero.h @@ -0,0 +1,3 @@ +#include "../../types.h" + +void selhero_Select_List(int value); diff --git a/Stub/DiabloUI/title.cpp b/Stub/DiabloUI/title.cpp index 8f2862c73..680c4e09b 100644 --- a/Stub/DiabloUI/title.cpp +++ b/Stub/DiabloUI/title.cpp @@ -1,12 +1,5 @@ #include "../../types.h" -void title_Render() -{ - DrawArt(0, 0, &ArtBackground); - DrawArtStr(0, 409, AFT_MED, AFC_SILVER, "Copyright \xA9 1996-2001 Blizzard Entertainment", JustCentre); - DrawLogo(182, LOGO_BIG); -} - void title_Load() { LoadBackgroundArt("ui_art\\title.pcx"); @@ -23,6 +16,11 @@ void title_Free() BOOL __stdcall UiTitleDialog(int a1) { + UI_Item TITLESCREEN_DIALOG[] = { + { { 0, 0, 640, 480 }, UI_IMAGE, 0, 0, NULL, &ArtBackground }, + { { 49, 410, 550, 26 }, UI_TEXT, UIS_MED | UIS_CENTER, 0, "Copyright \xA9 1996-2001 Blizzard Entertainment" }, + }; + title_Load(); bool endMenu = false; @@ -30,13 +28,13 @@ BOOL __stdcall UiTitleDialog(int a1) SDL_Event event; while (!endMenu && SDL_GetTicks() < timeOut) { - CapFPS(); - title_Render(); + UiRenderItems(TITLESCREEN_DIALOG, size(TITLESCREEN_DIALOG)); + DrawLogo(182, LOGO_BIG); UiFadeIn(); while (SDL_PollEvent(&event)) { switch (event.type) { - case SDL_KEYDOWN:/* + case SDL_KEYDOWN: /* To match the original uncomment this if (event.key.keysym.sym == SDLK_UP || event.key.keysym.sym == SDLK_UP || event.key.keysym.sym == SDLK_LEFT diff --git a/enums.h b/enums.h index 8d2e06a5a..a688e0a3f 100644 --- a/enums.h +++ b/enums.h @@ -2252,15 +2252,6 @@ typedef enum _mainmenu_selections { MAINMENU_ATTRACT_MODE = 6, } _mainmenu_selections; -typedef enum menus -{ - SELHERO_LOAD, - SELHERO_CLASSES, - SELHERO_NAME, - SELHERO_SELECT_GAME, - SELHERO_DIFFICULTY, -} menus; - typedef enum dlgresults { NEW_GAME = 0,