You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
9.6 KiB

/**
* @file gmenu.cpp
*
* Implementation of the in-game navigation and interaction.
*/
#include "all.h"
7 years ago
DEVILUTION_BEGIN_NAMESPACE
BYTE *optbar_cel;
BOOLEAN mouseNavigation;
BYTE *PentSpin_cel;
TMenuItem *sgpCurrItem;
BYTE *BigTGold_cel;
#ifdef HELLFIRE
int LogoAnim_tick;
BYTE LogoAnim_frame;
#endif
int PentSpin_tick;
void (*dword_63447C)(TMenuItem *);
TMenuItem *sgpCurrentMenu;
BYTE *option_cel;
BYTE *sgpLogo;
int sgCurrentMenuIdx;
/** Maps from font index to bigtgold.cel frame number. */
const BYTE lfontframe[] = {
7 years ago
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 37, 49, 38, 0, 39, 40, 47,
42, 43, 41, 45, 52, 44, 53, 55, 36, 27,
28, 29, 30, 31, 32, 33, 34, 35, 51, 50,
0, 46, 0, 54, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 42, 0, 43, 0, 0, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 20, 0, 21, 0, 0
7 years ago
};
/** Maps from bigtgold.cel frame number to character width. */
const BYTE lfontkern[] = {
7 years ago
18, 33, 21, 26, 28, 19, 19, 26, 25, 11,
12, 25, 19, 34, 28, 32, 20, 32, 28, 20,
28, 36, 35, 46, 33, 33, 24, 11, 23, 22,
22, 21, 22, 21, 21, 21, 32, 10, 20, 36,
31, 17, 13, 12, 13, 18, 16, 11, 20, 21,
11, 10, 12, 11, 21, 23
};
static void gmenu_print_text(int x, int y, const char *pszStr)
{
BYTE c;
while (*pszStr) {
c = gbFontTransTbl[(BYTE)*pszStr++];
c = lfontframe[c];
if (c != 0)
CelDrawLight(x, y, BigTGold_cel, c, 46, NULL);
x += lfontkern[c] + 2;
}
}
void gmenu_draw_pause()
{
if (currlevel != 0)
RedBack();
if (!sgpCurrentMenu) {
light_table_index = 0;
gmenu_print_text(316 + PANEL_LEFT, 336, "Pause");
}
}
void FreeGMenu()
{
MemFreeDbg(sgpLogo);
MemFreeDbg(BigTGold_cel);
MemFreeDbg(PentSpin_cel);
MemFreeDbg(option_cel);
MemFreeDbg(optbar_cel);
}
void gmenu_init_menu()
{
#ifdef HELLFIRE
LogoAnim_frame = 1;
#endif
6 years ago
sgpCurrentMenu = NULL;
sgpCurrItem = NULL;
dword_63447C = NULL;
sgCurrentMenuIdx = 0;
mouseNavigation = FALSE;
#ifdef HELLFIRE
sgpLogo = LoadFileInMem("Data\\hf_logo3.CEL", NULL);
#else
sgpLogo = LoadFileInMem("Data\\Diabsmal.CEL", NULL);
#endif
BigTGold_cel = LoadFileInMem("Data\\BigTGold.CEL", NULL);
PentSpin_cel = LoadFileInMem("Data\\PentSpin.CEL", NULL);
option_cel = LoadFileInMem("Data\\option.CEL", NULL);
optbar_cel = LoadFileInMem("Data\\optbar.CEL", NULL);
}
BOOL gmenu_is_active()
{
6 years ago
return sgpCurrentMenu != NULL;
}
static void gmenu_up_down(BOOL isDown)
{
int i;
if (!sgpCurrItem) {
return;
}
mouseNavigation = FALSE;
i = sgCurrentMenuIdx;
if (sgCurrentMenuIdx) {
while (i) {
i--;
if (isDown) {
sgpCurrItem++;
if (!sgpCurrItem->fnMenu)
sgpCurrItem = &sgpCurrentMenu[0];
7 years ago
} else {
if (sgpCurrItem == sgpCurrentMenu)
sgpCurrItem = &sgpCurrentMenu[sgCurrentMenuIdx];
sgpCurrItem--;
}
if ((sgpCurrItem->dwFlags & GMENU_ENABLED) != 0) {
if (i)
PlaySFX(IS_TITLEMOV);
return;
}
}
}
}
void gmenu_set_items(TMenuItem *pItem, void (*gmFunc)(TMenuItem *))
{
int i;
PauseMode = 0;
mouseNavigation = FALSE;
sgpCurrentMenu = pItem;
dword_63447C = gmFunc;
if (gmFunc) {
dword_63447C(sgpCurrentMenu);
pItem = sgpCurrentMenu;
}
sgCurrentMenuIdx = 0;
if (sgpCurrentMenu) {
for (i = 0; sgpCurrentMenu[i].fnMenu; i++) {
sgCurrentMenuIdx++;
}
}
// BUGFIX: OOB access when sgCurrentMenuIdx is 0; should be set to NULL instead. (fixed)
sgpCurrItem = sgCurrentMenuIdx > 0 ? &sgpCurrentMenu[sgCurrentMenuIdx - 1] : NULL;
gmenu_up_down(TRUE);
}
static void gmenu_clear_buffer(int x, int y, int width, int height)
{
BYTE *i;
i = gpBuffer + BUFFER_WIDTH * y + x;
while (height--) {
memset(i, 205, width);
i -= BUFFER_WIDTH;
}
}
static int gmenu_get_lfont(TMenuItem *pItem)
{
const char *text;
int i;
BYTE c;
if (pItem->dwFlags & GMENU_SLIDER)
return 490;
text = pItem->pszStr;
i = 0;
while (*text) {
c = gbFontTransTbl[(BYTE)*text++];
i += lfontkern[lfontframe[c]] + 2;
}
return i - 2;
}
static void gmenu_draw_menu_item(TMenuItem *pItem, int y)
{
DWORD w, x, nSteps, step, pos, t;
#ifndef HELLFIRE
t = y - 2;
#endif
w = gmenu_get_lfont(pItem);
if (pItem->dwFlags & GMENU_SLIDER) {
x = 16 + w / 2 + SCREEN_X;
#ifdef HELLFIRE
CelDraw(x + PANEL_LEFT, y - 10, optbar_cel, 1, 287);
#else
CelDraw(x + PANEL_LEFT, t - 8, optbar_cel, 1, 287);
#endif
step = pItem->dwFlags & 0xFFF;
nSteps = (pItem->dwFlags & 0xFFF000) >> 12;
if (nSteps < 2)
nSteps = 2;
pos = step * 256 / nSteps;
#ifdef HELLFIRE
gmenu_clear_buffer(x + 2 + PANEL_LEFT, y - 12, pos + 13, 28);
#else
gmenu_clear_buffer(x + 2 + PANEL_LEFT, t - 10, pos + 13, 28);
#endif
CelDraw(x + 2 + pos + PANEL_LEFT, y - 12, option_cel, 1, 27);
}
x = SCREEN_WIDTH / 2 - w / 2 + SCREEN_X;
light_table_index = (pItem->dwFlags & GMENU_ENABLED) ? 0 : 15;
gmenu_print_text(x, y, pItem->pszStr);
if (pItem == sgpCurrItem) {
CelDraw(x - 54, y + 1, PentSpin_cel, PentSpn2Spin(), 48);
CelDraw(x + 4 + w, y + 1, PentSpin_cel, PentSpn2Spin(), 48);
}
}
void gmenu_draw()
{
int y;
TMenuItem *i;
DWORD ticks;
if (sgpCurrentMenu) {
if (dword_63447C)
dword_63447C(sgpCurrentMenu);
#ifdef HELLFIRE
ticks = SDL_GetTicks();
if ((int)(ticks - LogoAnim_tick) > 25) {
LogoAnim_frame++;
if (LogoAnim_frame > 16)
LogoAnim_frame = 1;
LogoAnim_tick = ticks;
}
CelDraw((SCREEN_WIDTH - 430) / 2 + SCREEN_X, 102 + SCREEN_Y + UI_OFFSET_Y, sgpLogo, LogoAnim_frame, 430);
#else
CelDraw((SCREEN_WIDTH - 296) / 2 + SCREEN_X, 102 + SCREEN_Y + UI_OFFSET_Y, sgpLogo, 1, 296);
#endif
y = 160 + SCREEN_Y + UI_OFFSET_Y;
i = sgpCurrentMenu;
if (sgpCurrentMenu->fnMenu) {
while (i->fnMenu) {
gmenu_draw_menu_item(i, y);
i++;
y += 45;
}
}
}
}
static void gmenu_left_right(BOOL isRight)
{
int step;
if (sgpCurrItem->dwFlags & GMENU_SLIDER) {
step = sgpCurrItem->dwFlags & 0xFFF;
if (isRight) {
if (step == (int)(sgpCurrItem->dwFlags & 0xFFF000) >> 12)
return;
step++;
} else {
if (!step)
return;
step--;
}
sgpCurrItem->dwFlags &= 0xFFFFF000;
sgpCurrItem->dwFlags |= step;
sgpCurrItem->fnMenu(FALSE);
}
}
BOOL gmenu_presskeys(int vkey)
{
if (!sgpCurrentMenu)
6 years ago
return FALSE;
switch (vkey) {
case DVL_VK_RETURN:
if ((sgpCurrItem->dwFlags & GMENU_ENABLED) != 0) {
PlaySFX(IS_TITLEMOV);
sgpCurrItem->fnMenu(TRUE);
}
break;
case DVL_VK_ESCAPE:
PlaySFX(IS_TITLEMOV);
gmenu_set_items(NULL, NULL);
break;
case DVL_VK_SPACE:
return FALSE;
case DVL_VK_LEFT:
gmenu_left_right(FALSE);
break;
case DVL_VK_RIGHT:
gmenu_left_right(TRUE);
break;
case DVL_VK_UP:
gmenu_up_down(FALSE);
break;
case DVL_VK_DOWN:
gmenu_up_down(TRUE);
break;
}
return TRUE;
}
static BOOLEAN gmenu_get_mouse_slider(int *plOffset)
{
*plOffset = 282;
if (MouseX < 282 + PANEL_LEFT) {
*plOffset = 0;
return FALSE;
}
if (MouseX > 538 + PANEL_LEFT) {
*plOffset = 256;
return FALSE;
}
*plOffset = MouseX - 282 - PANEL_LEFT;
return TRUE;
}
BOOL gmenu_on_mouse_move()
{
int step, nSteps;
if (!mouseNavigation)
return FALSE;
gmenu_get_mouse_slider(&step);
nSteps = (int)(sgpCurrItem->dwFlags & 0xFFF000) >> 12;
step *= nSteps;
step /= 256;
sgpCurrItem->dwFlags &= 0xFFFFF000;
sgpCurrItem->dwFlags |= step;
sgpCurrItem->fnMenu(FALSE);
return TRUE;
}
BOOL gmenu_left_mouse(BOOL isDown)
{
TMenuItem *pItem;
DWORD i, w;
int dummy;
if (!isDown) {
if (mouseNavigation) {
mouseNavigation = FALSE;
return TRUE;
} else {
return FALSE;
}
}
if (!sgpCurrentMenu) {
return FALSE;
}
if (MouseY >= PANEL_TOP) {
return FALSE;
}
if (MouseY - (117 + UI_OFFSET_Y) < 0) {
return TRUE;
}
i = (MouseY - (117 + UI_OFFSET_Y)) / 45;
if (i >= sgCurrentMenuIdx) {
return TRUE;
}
pItem = &sgpCurrentMenu[i];
if (!(sgpCurrentMenu[i].dwFlags & GMENU_ENABLED)) {
return TRUE;
}
w = gmenu_get_lfont(pItem);
if (MouseX < SCREEN_WIDTH / 2 - w / 2) {
return TRUE;
}
if (MouseX > SCREEN_WIDTH / 2 + w / 2) {
return TRUE;
}
sgpCurrItem = pItem;
PlaySFX(IS_TITLEMOV);
if (pItem->dwFlags & GMENU_SLIDER) {
mouseNavigation = gmenu_get_mouse_slider(&dummy);
gmenu_on_mouse_move();
} else {
sgpCurrItem->fnMenu(TRUE);
}
return TRUE;
}
void gmenu_enable(TMenuItem *pMenuItem, BOOL enable)
{
if (enable)
pMenuItem->dwFlags |= GMENU_ENABLED;
else
pMenuItem->dwFlags &= ~GMENU_ENABLED;
}
/**
* @brief Set the TMenuItem slider position based on the given value
*/
void gmenu_slider_set(TMenuItem *pItem, int min, int max, int value)
{
int nSteps;
assert(pItem);
nSteps = (int)(pItem->dwFlags & 0xFFF000) >> 12;
if (nSteps < 2)
nSteps = 2;
pItem->dwFlags &= 0xFFFFF000;
pItem->dwFlags |= ((max - min - 1) / 2 + (value - min) * nSteps) / (max - min);
}
/**
* @brief Get the current value for the slider
*/
int gmenu_slider_get(TMenuItem *pItem, int min, int max)
{
int nSteps, step;
step = pItem->dwFlags & 0xFFF;
nSteps = (int)(pItem->dwFlags & 0xFFF000) >> 12;
if (nSteps < 2)
nSteps = 2;
return min + (step * (max - min) + (nSteps - 1) / 2) / nSteps;
}
/**
* @brief Set the number of steps for the slider
*/
void gmenu_slider_steps(TMenuItem *pItem, int steps)
{
pItem->dwFlags &= 0xFF000FFF;
pItem->dwFlags |= (steps << 12) & 0xFFF000;
}
DEVILUTION_END_NAMESPACE