Devilution
Diablo devolved - magic behind the 1996 computer game
gmenu.cpp
Go to the documentation of this file.
1 
6 #include "all.h"
7 
9 
10 BYTE *optbar_cel;
19 BYTE *option_cel;
20 BYTE *sgpLogo;
22 
24 const BYTE lfontframe[127] = {
25  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28  0, 0, 0, 37, 49, 38, 0, 39, 40, 47,
29  42, 43, 41, 45, 52, 44, 53, 55, 36, 27,
30  28, 29, 30, 31, 32, 33, 34, 35, 51, 50,
31  0, 46, 0, 54, 0, 1, 2, 3, 4, 5,
32  6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
33  16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
34  26, 42, 0, 43, 0, 0, 0, 1, 2, 3,
35  4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
36  14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
37  24, 25, 26, 20, 0, 21, 0
38 };
39 
41 const BYTE lfontkern[56] = {
42  18, 33, 21, 26, 28, 19, 19, 26, 25, 11,
43  12, 25, 19, 34, 28, 32, 20, 32, 28, 20,
44  28, 36, 35, 46, 33, 33, 24, 11, 23, 22,
45  22, 21, 22, 21, 21, 21, 32, 10, 20, 36,
46  31, 17, 13, 12, 13, 18, 16, 11, 20, 21,
47  11, 10, 12, 11, 21, 23
48 };
49 
51 {
52  if (currlevel != 0)
53  RedBack();
54  if (!sgpCurrentMenu) {
56  gmenu_print_text(316 + PANEL_LEFT, 336, "Pause");
57  }
58 }
59 
60 void gmenu_print_text(int x, int y, char *pszStr)
61 {
62  BYTE c;
63 
64  while (*pszStr) {
65  c = gbFontTransTbl[(BYTE)*pszStr++];
66  c = lfontframe[c];
67  if (c)
68  CelDrawLight(x, y, BigTGold_cel, c, 46, NULL);
69  x += lfontkern[c] + 2;
70  }
71 }
72 
73 void FreeGMenu()
74 {
80 }
81 
83 {
84  PentSpin_frame = 1;
85  sgpCurrentMenu = NULL;
86  sgpCurrItem = 0;
87  dword_63447C = 0;
88  sgCurrentMenuIdx = 0;
89  mouseNavigation = FALSE;
90  sgpLogo = LoadFileInMem("Data\\Diabsmal.CEL", NULL);
91  BigTGold_cel = LoadFileInMem("Data\\BigTGold.CEL", NULL);
92  PentSpin_cel = LoadFileInMem("Data\\PentSpin.CEL", NULL);
93  option_cel = LoadFileInMem("Data\\option.CEL", NULL);
94  optbar_cel = LoadFileInMem("Data\\optbar.CEL", NULL);
95 }
96 
98 {
99  return sgpCurrentMenu != NULL;
100 }
101 
102 void gmenu_set_items(TMenuItem *pItem, void (*gmFunc)(TMenuItem *))
103 {
104  int i;
105 
106  PauseMode = 0;
107  mouseNavigation = FALSE;
108  sgpCurrentMenu = pItem;
109  dword_63447C = gmFunc;
110  if (gmFunc) {
112  pItem = sgpCurrentMenu;
113  }
114  sgCurrentMenuIdx = 0;
115  if (sgpCurrentMenu) {
116  for (i = 0; sgpCurrentMenu[i].fnMenu; i++) {
118  }
119  }
120  // BUGFIX: OOB access when sgCurrentMenuIdx is 0; should be set to NULL instead. (fixed)
122  gmenu_up_down(TRUE);
123 }
124 
125 void gmenu_up_down(BOOL isDown)
126 {
127  int i;
128 
129  if (!sgpCurrItem) {
130  return;
131  }
132  mouseNavigation = FALSE;
133  i = sgCurrentMenuIdx;
134  if (sgCurrentMenuIdx) {
135  while (i) {
136  i--;
137  if (isDown) {
138  sgpCurrItem++;
139  if (!sgpCurrItem->fnMenu)
141  } else {
144  sgpCurrItem--;
145  }
146  if ((sgpCurrItem->dwFlags & GMENU_ENABLED) != 0) {
147  if (i)
149  return;
150  }
151  }
152  }
153 }
154 
156 {
157  int y;
158  TMenuItem *i;
159  DWORD ticks;
160 
161  if (sgpCurrentMenu) {
162  if (dword_63447C)
164  CelDraw((SCREEN_WIDTH - 296) / 2 + SCREEN_X, 102 + SCREEN_Y, sgpLogo, 1, 296);
165  y = 160 + SCREEN_Y;
166  i = sgpCurrentMenu;
167  if (sgpCurrentMenu->fnMenu) {
168  while (i->fnMenu) {
169  gmenu_draw_menu_item(i, y);
170  i++;
171  y += 45;
172  }
173  }
174 
175  ticks = SDL_GetTicks();
176  if ((int)(ticks - PentSpin_tick) > 50) { // BUGFIX: thould be 50ms (Fixed)
177  PentSpin_frame++;
178  if (PentSpin_frame == 9)
179  PentSpin_frame = 1;
180  PentSpin_tick = ticks;
181  }
182  }
183 }
184 
185 void gmenu_draw_menu_item(TMenuItem *pItem, int y)
186 {
187  DWORD w, x, nSteps, step, pos, t;
188  t = y - 2;
189  w = gmenu_get_lfont(pItem);
190  if (pItem->dwFlags & GMENU_SLIDER) {
191  x = 16 + w / 2 + SCREEN_X;
192  CelDraw(x + PANEL_LEFT, t - 8, optbar_cel, 1, 287);
193  step = pItem->dwFlags & 0xFFF;
194  nSteps = (pItem->dwFlags & 0xFFF000) >> 12;
195  if (nSteps < 2)
196  nSteps = 2;
197  pos = step * 256 / nSteps;
198  gmenu_clear_buffer(x + 2 + PANEL_LEFT, t - 10, pos + 13, 28);
199  CelDraw(x + 2 + pos + PANEL_LEFT, y - 12, option_cel, 1, 27);
200  }
201  x = SCREEN_WIDTH / 2 - w / 2 + SCREEN_X;
202  light_table_index = (pItem->dwFlags & GMENU_ENABLED) ? 0 : 15;
203  gmenu_print_text(x, y, pItem->pszStr);
204  if (pItem == sgpCurrItem) {
205  CelDraw(x - 54, y + 1, PentSpin_cel, PentSpin_frame, 48);
206  CelDraw(x + 4 + w, y + 1, PentSpin_cel, PentSpin_frame, 48);
207  }
208 }
209 
210 void gmenu_clear_buffer(int x, int y, int width, int height)
211 {
212  BYTE *i;
213 
214  i = gpBuffer + BUFFER_WIDTH * y + x;
215  while (height--) {
216  memset(i, 205, width);
217  i -= BUFFER_WIDTH;
218  }
219 }
220 
222 {
223  char *text;
224  int i;
225  BYTE c;
226 
227  if (pItem->dwFlags & GMENU_SLIDER)
228  return 490;
229  text = pItem->pszStr;
230  i = 0;
231  while (*text) {
232  c = gbFontTransTbl[(BYTE)*text++];
233  i += lfontkern[lfontframe[c]] + 2;
234  }
235  return i - 2;
236 }
237 
238 BOOL gmenu_presskeys(int vkey)
239 {
240  if (!sgpCurrentMenu)
241  return FALSE;
242  switch (vkey) {
243  case VK_RETURN:
244  if ((sgpCurrItem->dwFlags & GMENU_ENABLED) != 0) {
246  sgpCurrItem->fnMenu(TRUE);
247  }
248  break;
249  case VK_ESCAPE:
251  gmenu_set_items(0, 0);
252  break;
253  case VK_SPACE:
254  return FALSE;
255  case VK_LEFT:
256  gmenu_left_right(FALSE);
257  break;
258  case VK_RIGHT:
259  gmenu_left_right(TRUE);
260  break;
261  case VK_UP:
262  gmenu_up_down(FALSE);
263  break;
264  case VK_DOWN:
265  gmenu_up_down(TRUE);
266  break;
267  }
268  return TRUE;
269 }
270 
271 void gmenu_left_right(BOOL isRight)
272 {
273  int step;
274 
276  step = sgpCurrItem->dwFlags & 0xFFF;
277  if (isRight) {
278  if (step == (int)(sgpCurrItem->dwFlags & 0xFFF000) >> 12)
279  return;
280  step++;
281  } else {
282  if (!step)
283  return;
284  step--;
285  }
286  sgpCurrItem->dwFlags &= 0xFFFFF000;
287  sgpCurrItem->dwFlags |= step;
288  sgpCurrItem->fnMenu(FALSE);
289  }
290 }
291 
293 {
294  int step, nSteps;
295 
296  if (!mouseNavigation)
297  return FALSE;
298  gmenu_get_mouse_slider(&step);
299  nSteps = (int)(sgpCurrItem->dwFlags & 0xFFF000) >> 12;
300  step *= nSteps;
301  step /= 256;
302 
303  sgpCurrItem->dwFlags &= 0xFFFFF000;
304  sgpCurrItem->dwFlags |= step;
305  sgpCurrItem->fnMenu(FALSE);
306  return TRUE;
307 }
308 
309 BOOLEAN gmenu_get_mouse_slider(int *plOffset)
310 {
311  *plOffset = 282;
312  if (MouseX < 282 + PANEL_LEFT) {
313  *plOffset = 0;
314  return FALSE;
315  }
316  if (MouseX > 538 + PANEL_LEFT) {
317  *plOffset = 256;
318  return FALSE;
319  }
320  *plOffset = MouseX - 282 - PANEL_LEFT;
321  return TRUE;
322 }
323 
324 BOOL gmenu_left_mouse(BOOL isDown)
325 {
326  TMenuItem *pItem;
327  DWORD i, w;
328  int dummy;
329 
330  if (!isDown) {
331  if (mouseNavigation) {
332  mouseNavigation = FALSE;
333  return TRUE;
334  } else {
335  return FALSE;
336  }
337  }
338 
339  if (!sgpCurrentMenu) {
340  return FALSE;
341  }
342  if (MouseY >= PANEL_TOP) {
343  return FALSE;
344  }
345  if (MouseY - 117 < 0) {
346  return TRUE;
347  }
348  i = (MouseY - 117) / 45;
349  if (i >= sgCurrentMenuIdx) {
350  return TRUE;
351  }
352  pItem = &sgpCurrentMenu[i];
353  if (!(sgpCurrentMenu[i].dwFlags & GMENU_ENABLED)) {
354  return TRUE;
355  }
356  w = gmenu_get_lfont(pItem);
357  if (MouseX < SCREEN_WIDTH / 2 - w / 2) {
358  return TRUE;
359  }
360  if (MouseX > SCREEN_WIDTH / 2 + w / 2) {
361  return TRUE;
362  }
363  sgpCurrItem = pItem;
365  if (pItem->dwFlags & GMENU_SLIDER) {
368  } else {
369  sgpCurrItem->fnMenu(TRUE);
370  }
371  return TRUE;
372 }
373 
374 void gmenu_enable(TMenuItem *pMenuItem, BOOL enable)
375 {
376  if (enable)
377  pMenuItem->dwFlags |= GMENU_ENABLED;
378  else
379  pMenuItem->dwFlags &= ~GMENU_ENABLED;
380 }
381 
385 void gmenu_slider_set(TMenuItem *pItem, int min, int max, int value)
386 {
387  int nSteps;
388 
390  nSteps = (int)(pItem->dwFlags & 0xFFF000) >> 12;
391  if (nSteps < 2)
392  nSteps = 2;
393  pItem->dwFlags &= 0xFFFFF000;
394  pItem->dwFlags |= ((max - min - 1) / 2 + (value - min) * nSteps) / (max - min);
395 }
396 
400 int gmenu_slider_get(TMenuItem *pItem, int min, int max)
401 {
402  int nSteps, step;
403 
404  step = pItem->dwFlags & 0xFFF;
405  nSteps = (int)(pItem->dwFlags & 0xFFF000) >> 12;
406  if (nSteps < 2)
407  nSteps = 2;
408  return min + (step * (max - min) + (nSteps - 1) / 2) / nSteps;
409 }
410 
414 void gmenu_slider_steps(TMenuItem *pItem, int steps)
415 {
416  pItem->dwFlags &= 0xFF000FFF;
417  pItem->dwFlags |= (steps << 12) & 0xFFF000;
418 }
419 
gpBuffer
BYTE * gpBuffer
BigTGold_cel
BYTE * BigTGold_cel
Definition: gmenu.cpp:14
gmenu_slider_steps
void gmenu_slider_steps(TMenuItem *pItem, int steps)
Set the number of steps for the slider.
Definition: gmenu.cpp:414
MouseY
int MouseY
Definition: diablo.cpp:17
IS_TITLEMOV
@ IS_TITLEMOV
Definition: enums.h:352
currlevel
BYTE currlevel
Definition: gendung.cpp:40
SCREEN_Y
#define SCREEN_Y
Definition: defs.h:126
sgpLogo
BYTE * sgpLogo
Definition: gmenu.cpp:20
GMENU_ENABLED
#define GMENU_ENABLED
Definition: defs.h:13
gmenu_init_menu
void gmenu_init_menu()
Definition: gmenu.cpp:82
MemFreeDbg
#define MemFreeDbg(p)
Definition: defs.h:157
gmenu_presskeys
BOOL gmenu_presskeys(int vkey)
Definition: gmenu.cpp:238
all.h
gmenu_up_down
void gmenu_up_down(BOOL isDown)
Definition: gmenu.cpp:125
PauseMode
int PauseMode
Definition: diablo.cpp:41
TMenuItem::pszStr
char * pszStr
Definition: structs.h:1005
SCREEN_WIDTH
#define SCREEN_WIDTH
Definition: defs.h:105
gmenu_get_lfont
int gmenu_get_lfont(TMenuItem *pItem)
Definition: gmenu.cpp:221
gmenu_is_active
BOOL gmenu_is_active()
Definition: gmenu.cpp:97
lfontkern
const BYTE lfontkern[56]
Maps from bigtgold.cel frame number to character width.
Definition: gmenu.cpp:41
DEVILUTION_END_NAMESPACE
#define DEVILUTION_END_NAMESPACE
Definition: types.h:10
light_table_index
DEVILUTION_BEGIN_NAMESPACE int light_table_index
Specifies the current light entry.
Definition: scrollrt.cpp:8
PentSpin_tick
int PentSpin_tick
Definition: gmenu.cpp:15
FreeGMenu
void FreeGMenu()
Definition: gmenu.cpp:73
TMenuItem
Definition: structs.h:1003
dword_63447C
void(* dword_63447C)(TMenuItem *)
Definition: gmenu.cpp:17
LoadFileInMem
BYTE * LoadFileInMem(char *pszName, DWORD *pdwFileLen)
Load a file in to a buffer.
Definition: engine.cpp:801
CelDraw
void CelDraw(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth)
Blit CEL sprite to the back buffer at the given coordinates.
Definition: engine.cpp:47
sgpCurrItem
TMenuItem * sgpCurrItem
Definition: gmenu.cpp:13
option_cel
BYTE * option_cel
Definition: gmenu.cpp:19
gmenu_draw_pause
void gmenu_draw_pause()
Definition: gmenu.cpp:50
PlaySFX
void PlaySFX(int psfx)
Definition: effects.cpp:1043
gmenu_draw_menu_item
void gmenu_draw_menu_item(TMenuItem *pItem, int y)
Definition: gmenu.cpp:185
gmenu_left_mouse
BOOL gmenu_left_mouse(BOOL isDown)
Definition: gmenu.cpp:324
TMenuItem::dwFlags
DWORD dwFlags
Definition: structs.h:1004
gmenu_set_items
void gmenu_set_items(TMenuItem *pItem, void(*gmFunc)(TMenuItem *))
Definition: gmenu.cpp:102
TMenuItem::fnMenu
void(* fnMenu)(BOOL)
Definition: structs.h:1006
BUFFER_WIDTH
#define BUFFER_WIDTH
Definition: defs.h:128
sgCurrentMenuIdx
int sgCurrentMenuIdx
Definition: gmenu.cpp:21
PentSpin_frame
BYTE PentSpin_frame
Definition: gmenu.cpp:16
gmenu_on_mouse_move
BOOL gmenu_on_mouse_move()
Definition: gmenu.cpp:292
GMENU_SLIDER
#define GMENU_SLIDER
Definition: defs.h:12
DEVILUTION_BEGIN_NAMESPACE
Definition: sha.cpp:10
gmenu_clear_buffer
void gmenu_clear_buffer(int x, int y, int width, int height)
Definition: gmenu.cpp:210
gmenu_left_right
void gmenu_left_right(BOOL isRight)
Definition: gmenu.cpp:271
optbar_cel
DEVILUTION_BEGIN_NAMESPACE BYTE * optbar_cel
Definition: gmenu.cpp:10
gmenu_slider_set
void gmenu_slider_set(TMenuItem *pItem, int min, int max, int value)
Set the TMenuItem slider position based on the given value.
Definition: gmenu.cpp:385
PANEL_TOP
#define PANEL_TOP
Definition: defs.h:134
SCREEN_X
#define SCREEN_X
Definition: defs.h:125
PANEL_LEFT
#define PANEL_LEFT
Definition: defs.h:135
lfontframe
const BYTE lfontframe[127]
Maps from font index to bigtgold.cel frame number.
Definition: gmenu.cpp:24
sgpCurrentMenu
TMenuItem * sgpCurrentMenu
Definition: gmenu.cpp:18
gbFontTransTbl
const BYTE gbFontTransTbl[256]
Maps ASCII character code to font index, as used by the small, medium and large sized fonts; which co...
Definition: control.cpp:106
gmenu_slider_get
int gmenu_slider_get(TMenuItem *pItem, int min, int max)
Get the current value for the slider.
Definition: gmenu.cpp:400
PentSpin_cel
BYTE * PentSpin_cel
Definition: gmenu.cpp:12
RedBack
void RedBack()
Definition: control.cpp:1715
gmenu_get_mouse_slider
BOOLEAN gmenu_get_mouse_slider(int *plOffset)
Definition: gmenu.cpp:309
mouseNavigation
BOOLEAN mouseNavigation
Definition: gmenu.cpp:11
gmenu_enable
void gmenu_enable(TMenuItem *pMenuItem, BOOL enable)
Definition: gmenu.cpp:374
MouseX
int MouseX
Definition: diablo.cpp:18
gmenu_draw
void gmenu_draw()
Definition: gmenu.cpp:155
gmenu_print_text
void gmenu_print_text(int x, int y, char *pszStr)
Definition: gmenu.cpp:60
CelDrawLight
void CelDrawLight(int sx, int sy, BYTE *pCelBuff, int nCel, int nWidth, BYTE *tbl)
Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates.
Definition: engine.cpp:104