mirror of
https://github.com/jmarshall23/Hellfire.git
synced 2026-08-11 23:40:51 +02:00
528 lines
14 KiB
C++
528 lines
14 KiB
C++
/*-----------------------------------------------------------------------**
|
|
** Diablo
|
|
**
|
|
** Game Menu file
|
|
**
|
|
** (C)1995 Condor, Inc. All rights reserved.
|
|
**
|
|
**-----------------------------------------------------------------------**
|
|
** $Header: /Diablo/GMENU.CPP 1 1/22/97 2:06p Dgartner $
|
|
**-----------------------------------------------------------------------**
|
|
**
|
|
** File Routines
|
|
**-----------------------------------------------------------------------*/
|
|
|
|
#include "diablo.h"
|
|
#pragma hdrstop
|
|
#include "sound.h"
|
|
#include "gendung.h"
|
|
#include "gamemenu.h"
|
|
#include "scrollrt.h"
|
|
#include "engine.h"
|
|
#include "effects.h"
|
|
|
|
|
|
//******************************************************************
|
|
// extern
|
|
//******************************************************************
|
|
void RedBack();
|
|
|
|
|
|
//******************************************************************
|
|
// kerning
|
|
//******************************************************************
|
|
#define KERNSPACE 2
|
|
static const BYTE mfonttrans[128] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
|
|
0, 37, 49, 38, 0, 39, 40, 47, 42, 43, 41, 45, 52, 44, 53, 55, // 32-47
|
|
36, 27, 28, 29, 30, 31, 32, 33, 34, 35, 51, 50, 0, 46, 0, 54, // 48-63
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 64-79
|
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 42, 0, 43, 0, 0, // 80-95
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 96-111
|
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 20, 0, 21, 0, 0 // 112-127
|
|
};
|
|
static const BYTE mfontkern[56] = { 18, // Space/Invalid
|
|
33, 21, 26, 28, 19, 19, 26, 25, 11, 12, 25, 19, 34, 28, 32, 20, // a-p
|
|
32, 28, 20, 28, 36, 35, 46, 33, 33, 24, // q-z
|
|
11, 23, 22, 22, 21, 22, 21, 21, 21, 32, // 1-0
|
|
10, 20, 36, 31, 17, 13, 12, 13, 18, 16, 11, 20, 21, 11, 10, 12, 11, 21, 23 // misc
|
|
};
|
|
|
|
|
|
//******************************************************************
|
|
// private data
|
|
//******************************************************************
|
|
static BYTE sgbGameSpin;
|
|
static BYTE sgbTitleAnimate;
|
|
static BYTE * sgpLogo;
|
|
static BYTE * sgpSpinCels;
|
|
static BYTE * sgpMenuCels;
|
|
static BYTE * sgpSliderCels;
|
|
static BYTE * sgpBarCels;
|
|
static TMenuItem * sgpMenu;
|
|
static TMenuUpdateFcn sgfnMenuUpdateFcn;
|
|
static TMenuItem * sgpCurrItem;
|
|
static DWORD sgdwMenuItems;
|
|
static long sglSpinnerTime;
|
|
static long sglTitleTime;
|
|
static BYTE sgbTracking;
|
|
|
|
#define MENU_STARTY 320
|
|
#define MENU_CLICKY (MENU_STARTY - 203)
|
|
#define MENU_LINEHGT 45
|
|
#define SLIDER_WDT 256
|
|
#define SLIDER_ITEM_WDT 27
|
|
#define SLIDER_TOTAL_WDT 490
|
|
|
|
#define ENABLE_LVAL 0
|
|
#define DISABLE_LVAL 15
|
|
|
|
#define MIN_SLIDER_TICKS 2
|
|
#define SLIDER_TICK_SHIFT 12
|
|
#define MAX_SLIDER_TICKS 0xfff
|
|
#define mf_SLIDER_VAL_MASK 0x00000fff
|
|
#define mf_SLIDER_TICK_MASK 0x00fff000
|
|
|
|
#define SPINNER_TIME 25 // milliseconds
|
|
#define TITLE_TIME 25 // milliseconds
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void DrawBigFontXY(int x, int y,const char * pszStr) {
|
|
app_assert(pszStr);
|
|
while (*pszStr) {
|
|
BYTE c = char2print(*pszStr++);
|
|
c = mfonttrans[c];
|
|
if (c != 0) DrawCelL(x, y, sgpMenuCels, c, 46);
|
|
x += mfontkern[c] + KERNSPACE;
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void DrawPause() {
|
|
if (currlevel != 0) RedBack();
|
|
if (! sgpMenu) {
|
|
nLVal = 0; // set light level
|
|
DrawBigFontXY(316, 336, "Pause");
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void gmenu_free() {
|
|
DiabloFreePtr(sgpLogo);
|
|
DiabloFreePtr(sgpMenuCels);
|
|
DiabloFreePtr(sgpSpinCels);
|
|
DiabloFreePtr(sgpSliderCels);
|
|
DiabloFreePtr(sgpBarCels);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void gmenu_init() {
|
|
sgbGameSpin = 1;
|
|
sgbTitleAnimate = 1;
|
|
sgpMenu = NULL;
|
|
sgpCurrItem = NULL;
|
|
sgfnMenuUpdateFcn = NULL;
|
|
sgdwMenuItems = 0;
|
|
sgbTracking = FALSE;
|
|
|
|
app_assert(! sgpLogo);
|
|
//sgpLogo = LoadFileInMemSig("Data\\Diabsmal.CEL",NULL,'MENU');
|
|
sgpLogo = LoadFileInMemSig("Data\\hf_logo3.CEL",NULL,'MENU');
|
|
sgpMenuCels = LoadFileInMemSig("Data\\BigTGold.CEL",NULL,'MENU');
|
|
sgpSpinCels = LoadFileInMemSig("Data\\PentSpin.CEL",NULL,'MENU');
|
|
sgpSliderCels = LoadFileInMemSig("Data\\option.CEL",NULL,'MENU');
|
|
sgpBarCels = LoadFileInMemSig("Data\\optbar.CEL",NULL,'MENU');
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
BOOL gmenu_is_on() {
|
|
return sgpMenu != NULL;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void gmenu_change(BOOL bNext) {
|
|
if (! sgpCurrItem) return;
|
|
sgbTracking = FALSE;
|
|
for (DWORD d = sgdwMenuItems; d--; ) {
|
|
if (bNext) {
|
|
// next item
|
|
sgpCurrItem++;
|
|
|
|
// wrap at end of list
|
|
if (! sgpCurrItem->fnMenu)
|
|
sgpCurrItem = sgpMenu;
|
|
}
|
|
else {
|
|
// wrap at beginning of list
|
|
if (sgpCurrItem == sgpMenu)
|
|
sgpCurrItem = sgpMenu + sgdwMenuItems;
|
|
|
|
// prev item
|
|
sgpCurrItem--;
|
|
}
|
|
|
|
if (sgpCurrItem->dwFlags & mf_ENABLED) {
|
|
if (d) PlaySFX(IS_TITLEMOV);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void gmenu_set_menu(TMenuItem * pMenuItems,TMenuUpdateFcn fnUpdate) {
|
|
PauseMode = 0;
|
|
|
|
sgpMenu = pMenuItems;
|
|
sgbTracking = FALSE;
|
|
sgfnMenuUpdateFcn = fnUpdate;
|
|
if (sgfnMenuUpdateFcn) sgfnMenuUpdateFcn(sgpMenu);
|
|
|
|
// calculate number of items in menu
|
|
sgdwMenuItems = 0;
|
|
if (sgpMenu) {
|
|
for (TMenuItem * pItem = sgpMenu; pItem->fnMenu; pItem++)
|
|
sgdwMenuItems++;
|
|
}
|
|
|
|
// move to the first active item in the menu
|
|
sgpCurrItem = sgpMenu + sgdwMenuItems - 1;
|
|
gmenu_change(TRUE);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void DrawBar(DWORD x,DWORD y,DWORD wdt,DWORD hgt) {
|
|
app_assert(gpBuffer);
|
|
BYTE * pbDst = gpBuffer + nBuffWTbl[y] + x;
|
|
while (hgt--) {
|
|
FillMemory(pbDst,wdt,0xcd);
|
|
pbDst -= 768;
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static DWORD gmenu_calc_item_width(const TMenuItem * pItem) {
|
|
// hardcode the size of sliders so they all justify uniformly
|
|
// so that the slider bars line up vertically
|
|
if (pItem->dwFlags & mf_SLIDER)
|
|
return SLIDER_TOTAL_WDT;
|
|
|
|
DWORD wdt = 0;
|
|
const char * pszStr = pItem->pszStr;
|
|
while (*pszStr) {
|
|
BYTE c = char2print(*pszStr++);
|
|
c = mfonttrans[c];
|
|
wdt += mfontkern[c] + KERNSPACE;
|
|
}
|
|
wdt -= KERNSPACE;
|
|
return wdt;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void gmenu_draw_item(const TMenuItem * pItem,int yPos) {
|
|
DWORD wdt = gmenu_calc_item_width(pItem);
|
|
|
|
if (pItem->dwFlags & mf_SLIDER) {
|
|
int xPos = 640/2 + wdt/2 + 43 - SLIDER_WDT - SLIDER_ITEM_WDT;
|
|
DrawCel(xPos + 0,yPos - 10,sgpBarCels, 1, 287);
|
|
DWORD dwLen = pItem->dwFlags & mf_SLIDER_VAL_MASK;
|
|
|
|
// scale 0..ticks to 0..SLIDER_WDT
|
|
DWORD dwTicks = pItem->dwFlags & mf_SLIDER_TICK_MASK;
|
|
dwTicks >>= SLIDER_TICK_SHIFT;
|
|
if (dwTicks < MIN_SLIDER_TICKS) dwTicks = MIN_SLIDER_TICKS;
|
|
dwLen *= SLIDER_WDT;
|
|
dwLen /= dwTicks;
|
|
|
|
DrawBar(xPos + 2,yPos - 12,dwLen + SLIDER_ITEM_WDT/2,28);
|
|
xPos += dwLen;
|
|
DrawCel(xPos + 2,yPos - 12,sgpSliderCels, 1, 27);
|
|
}
|
|
|
|
// draw string with lighting
|
|
int xPos = 640/2 - wdt/2 + 64;
|
|
nLVal = (pItem->dwFlags & mf_ENABLED) ? ENABLE_LVAL : DISABLE_LVAL;
|
|
DrawBigFontXY(xPos, yPos, pItem->pszStr);
|
|
|
|
if (pItem == sgpCurrItem) {
|
|
DrawCel(xPos - 54, yPos + 1, sgpSpinCels, sgbGameSpin, 48);
|
|
DrawCel(xPos + wdt + 4, yPos + 1, sgpSpinCels, sgbGameSpin, 48);
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void gmenu_draw() {
|
|
if (! sgpMenu) return;
|
|
if (sgfnMenuUpdateFcn) sgfnMenuUpdateFcn(sgpMenu);
|
|
|
|
const TMenuItem * pItem;
|
|
long lCurrTime = (long) GetTickCount();
|
|
//DrawCel(236, 262, sgpLogo, 1, 296);
|
|
if (lCurrTime - sglTitleTime > TITLE_TIME){
|
|
++sgbTitleAnimate;
|
|
if (sgbTitleAnimate > 16) sgbTitleAnimate = 1;
|
|
sglTitleTime = lCurrTime;
|
|
}
|
|
DrawCel(169, 262, sgpLogo, sgbTitleAnimate, 430);
|
|
|
|
// draw items
|
|
DWORD yPos = MENU_STARTY;
|
|
for (pItem = sgpMenu; pItem->fnMenu; pItem++) {
|
|
gmenu_draw_item(pItem,yPos);
|
|
yPos += MENU_LINEHGT;
|
|
}
|
|
|
|
// adjust spinner
|
|
if (lCurrTime - sglSpinnerTime > SPINNER_TIME) {
|
|
sgbGameSpin++;
|
|
if (sgbGameSpin == 9) sgbGameSpin = 1;
|
|
sglSpinnerTime = lCurrTime;
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void gmenu_slider(BOOL bNext) {
|
|
if (! (sgpCurrItem->dwFlags & mf_SLIDER)) return;
|
|
|
|
LONG lVal = sgpCurrItem->dwFlags & mf_SLIDER_VAL_MASK;
|
|
LONG lTicks = sgpCurrItem->dwFlags & mf_SLIDER_TICK_MASK;
|
|
lTicks >>= SLIDER_TICK_SHIFT;
|
|
if (bNext) {
|
|
if (lVal == lTicks) return;
|
|
lVal++;
|
|
}
|
|
else {
|
|
if (! lVal) return;
|
|
lVal--;
|
|
}
|
|
|
|
sgpCurrItem->dwFlags &= ~mf_SLIDER_VAL_MASK;
|
|
sgpCurrItem->dwFlags |= lVal;
|
|
sgpCurrItem->fnMenu(FALSE);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
BOOL gmenu_key(WPARAM wKey) {
|
|
|
|
if (! sgpMenu) return FALSE;
|
|
app_assert(sgpCurrItem);
|
|
|
|
switch (wKey) {
|
|
case VK_SPACE:
|
|
// allow spacebar
|
|
return FALSE;
|
|
|
|
case VK_LEFT:
|
|
gmenu_slider(FALSE);
|
|
break;
|
|
|
|
case VK_RIGHT:
|
|
gmenu_slider(TRUE);
|
|
break;
|
|
|
|
case VK_UP:
|
|
gmenu_change(FALSE);
|
|
break;
|
|
|
|
case VK_DOWN:
|
|
gmenu_change(TRUE);
|
|
break;
|
|
|
|
case VK_RETURN:
|
|
app_assert(sgpCurrItem);
|
|
if (sgpCurrItem->dwFlags & mf_ENABLED) {
|
|
PlaySFX(IS_TITLEMOV);
|
|
sgpCurrItem->fnMenu(TRUE);
|
|
}
|
|
break;
|
|
|
|
case VK_ESCAPE:
|
|
PlaySFX(IS_TITLEMOV);
|
|
gmenu_set_menu(NULL,NULL);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static BYTE gmenu_mouse_in_slider(LONG * plOffset) {
|
|
app_assert(plOffset);
|
|
*plOffset = 640/2 + SLIDER_TOTAL_WDT/2 - SLIDER_WDT - SLIDER_ITEM_WDT;
|
|
if (MouseX < *plOffset) {
|
|
*plOffset = 0;
|
|
return FALSE;
|
|
}
|
|
else if (MouseX > *plOffset + SLIDER_WDT) {
|
|
*plOffset = SLIDER_WDT;
|
|
return FALSE;
|
|
}
|
|
|
|
*plOffset = MouseX - *plOffset;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
BOOL gmenu_mousemove() {
|
|
if (! sgbTracking) return FALSE;
|
|
app_assert(sgpCurrItem);
|
|
|
|
// get position = 0..SLIDER_WDT
|
|
LONG lOffset;
|
|
gmenu_mouse_in_slider(&lOffset);
|
|
|
|
// scale to 0..ticks
|
|
LONG lTicks = sgpCurrItem->dwFlags & mf_SLIDER_TICK_MASK;
|
|
lTicks >>= SLIDER_TICK_SHIFT;
|
|
lOffset *= lTicks;
|
|
lOffset /= SLIDER_WDT;
|
|
|
|
// set item value
|
|
sgpCurrItem->dwFlags &= ~mf_SLIDER_VAL_MASK;
|
|
sgpCurrItem->dwFlags |= lOffset;
|
|
sgpCurrItem->fnMenu(FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
BOOL gmenu_click(BOOL bMouseDown) {
|
|
// handle mouseup
|
|
if (! bMouseDown) {
|
|
if (! sgbTracking) return FALSE;
|
|
sgbTracking = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
if (! sgpMenu) return FALSE;
|
|
if (MouseY >= 352) return FALSE;
|
|
|
|
int nItem = MouseY - MENU_CLICKY;
|
|
if (nItem < 0) return TRUE;
|
|
nItem /= MENU_LINEHGT;
|
|
if ((DWORD) nItem >= sgdwMenuItems) return TRUE;
|
|
|
|
// only click menu item if it is enabled
|
|
TMenuItem * pItem = sgpMenu + nItem;
|
|
if (! (pItem->dwFlags & mf_ENABLED)) return TRUE;
|
|
|
|
DWORD wdt = gmenu_calc_item_width(pItem);
|
|
if ((DWORD) MouseX < 640/2-wdt/2) return TRUE;
|
|
if ((DWORD) MouseX > 640/2+wdt/2) return TRUE;
|
|
|
|
// set current item
|
|
sgpCurrItem = pItem;
|
|
PlaySFX(IS_TITLEMOV);
|
|
|
|
if (pItem->dwFlags & mf_SLIDER) {
|
|
LONG lTemp;
|
|
sgbTracking = gmenu_mouse_in_slider(&lTemp);
|
|
gmenu_mousemove();
|
|
}
|
|
else {
|
|
sgpCurrItem->fnMenu(TRUE);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void gmenu_set_enable(TMenuItem * pMenuItem,BOOL bEnable) {
|
|
app_assert(pMenuItem);
|
|
if (bEnable)
|
|
pMenuItem->dwFlags |= mf_ENABLED;
|
|
else
|
|
pMenuItem->dwFlags &= ~mf_ENABLED;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void gmenu_set_slider(TMenuItem * pItem,LONG lMin,LONG lMax,LONG lVal) {
|
|
app_assert(pItem);
|
|
|
|
LONG lTicks = pItem->dwFlags & mf_SLIDER_TICK_MASK;
|
|
lTicks >>= SLIDER_TICK_SHIFT;
|
|
if (lTicks < MIN_SLIDER_TICKS) lTicks = MIN_SLIDER_TICKS;
|
|
|
|
// make lVal zero-based
|
|
lVal -= lMin;
|
|
|
|
// scale to slider
|
|
lVal *= lTicks;
|
|
lVal += (lMax - lMin - 1) / 2;
|
|
lVal /= lMax - lMin;
|
|
|
|
// store into menu item
|
|
pItem->dwFlags &= ~mf_SLIDER_VAL_MASK;
|
|
pItem->dwFlags |= lVal;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
LONG gmenu_get_slider(const TMenuItem * pItem,LONG lMin,LONG lMax) {
|
|
app_assert(pItem);
|
|
|
|
// get value from menu item
|
|
LONG lVal = pItem->dwFlags & mf_SLIDER_VAL_MASK;
|
|
|
|
LONG lTicks = pItem->dwFlags & mf_SLIDER_TICK_MASK;
|
|
lTicks >>= SLIDER_TICK_SHIFT;
|
|
if (lTicks < MIN_SLIDER_TICKS) lTicks = MIN_SLIDER_TICKS;
|
|
|
|
// restore scale
|
|
lVal *= lMax - lMin;
|
|
lVal += (lTicks - 1) / 2;
|
|
lVal /= lTicks;
|
|
|
|
// re-base
|
|
lVal += lMin;
|
|
|
|
return lVal;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void gmenu_set_slider_ticks(TMenuItem * pItem,DWORD dwTicks) {
|
|
app_assert(pItem);
|
|
app_assert(dwTicks >= MIN_SLIDER_TICKS && dwTicks <= MAX_SLIDER_TICKS);
|
|
|
|
pItem->dwFlags &= ~mf_SLIDER_TICK_MASK;
|
|
pItem->dwFlags |= mf_SLIDER_TICK_MASK & (dwTicks << SLIDER_TICK_SHIFT);
|
|
}
|