1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5
6 This file is part of NBlood.
7
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 #include "build.h"
24 #include "compat.h"
25 #include "mouse.h"
26 #include "common_game.h"
27 #include "blood.h"
28 #include "config.h"
29 #include "gamemenu.h"
30 #include "globals.h"
31 #include "gui.h"
32 #include "inifile.h"
33 #include "levels.h"
34 #include "menu.h"
35 #include "qav.h"
36 #include "resource.h"
37 #include "view.h"
38
39 CMenuTextMgr gMenuTextMgr;
40 CGameMenuMgr gGameMenuMgr;
41
42 extern CGameMenuItemPicCycle itemSorryPicCycle;
43 extern CGameMenuItemQAV itemBloodQAV;
44
CMenuTextMgr()45 CMenuTextMgr::CMenuTextMgr()
46 {
47 at0 = -1;
48 }
49
50 static char buffer[21][45];
51
DrawText(const char * pString,int nFont,int x,int y,int nShade,int nPalette,bool shadow)52 void CMenuTextMgr::DrawText(const char *pString, int nFont, int x, int y, int nShade, int nPalette, bool shadow )
53 {
54 viewDrawText(nFont, pString, x, y, nShade, nPalette, 0, shadow);
55 }
56
GetFontInfo(int nFont,const char * pString,int * pXSize,int * pYSize)57 void CMenuTextMgr::GetFontInfo(int nFont, const char *pString, int *pXSize, int *pYSize)
58 {
59 if (nFont < 0 || nFont >= 5)
60 return;
61 viewGetFontInfo(nFont, pString, pXSize, pYSize);
62 }
63
64 bool CGameMenuMgr::m_bInitialized = false;
65 bool CGameMenuMgr::m_bActive = false;
66 bool CGameMenuMgr::m_bScanning = false;
67
CGameMenuMgr()68 CGameMenuMgr::CGameMenuMgr()
69 {
70 dassert(!m_bInitialized);
71 m_bInitialized = true;
72 Clear();
73 }
74
~CGameMenuMgr()75 CGameMenuMgr::~CGameMenuMgr()
76 {
77 m_bInitialized = false;
78 Clear();
79 }
80
InitializeMenu(void)81 void CGameMenuMgr::InitializeMenu(void)
82 {
83 if (pActiveMenu)
84 {
85 CGameMenuEvent event;
86 event.at0 = kMenuEventInit;
87 event.at2 = 0;
88 pActiveMenu->Event(event);
89 }
90 }
91
DeInitializeMenu(void)92 void CGameMenuMgr::DeInitializeMenu(void)
93 {
94 if (pActiveMenu)
95 {
96 CGameMenuEvent event;
97 event.at0 = kMenuEventDeInit;
98 event.at2 = 0;
99 pActiveMenu->Event(event);
100 }
101 }
102
Push(CGameMenu * pMenu,int nItem)103 bool CGameMenuMgr::Push(CGameMenu *pMenu, int nItem)
104 {
105 if (nMenuPointer == 0)
106 {
107 m_mouselastactivity = -M_MOUSETIMEOUT;
108 m_mousewake_watchpoint = 0;
109 mouseLockToWindow(0);
110 mouseMoveToCenter();
111 mouseReadAbs(&m_prevmousepos, &g_mouseAbs);
112 }
113 dassert(pMenu != NULL);
114 if (nMenuPointer == 8)
115 return false;
116 pActiveMenu = pMenuStack[nMenuPointer] = pMenu;
117 nMenuPointer++;
118 if (nItem >= 0)
119 pMenu->SetFocusItem(nItem);
120 m_bActive = true;
121 gInputMode = INPUT_MODE_1;
122 InitializeMenu();
123 m_menuchange_watchpoint = 1;
124 m_mousecaught = 1;
125 return true;
126 }
127
Pop(void)128 void CGameMenuMgr::Pop(void)
129 {
130 if (nMenuPointer > 0)
131 {
132 DeInitializeMenu();
133 nMenuPointer--;
134 if (nMenuPointer == 0)
135 Deactivate();
136 else
137 pActiveMenu = pMenuStack[nMenuPointer-1];
138
139 m_menuchange_watchpoint = 1;
140 }
141 m_mousecaught = 1;
142 }
143
PostPop(void)144 void CGameMenuMgr::PostPop(void)
145 {
146 m_postPop = true;
147 }
148
Draw(void)149 void CGameMenuMgr::Draw(void)
150 {
151 if (pActiveMenu)
152 {
153 pActiveMenu->Draw();
154 viewUpdatePages();
155 }
156
157 if (m_postPop)
158 {
159 Pop();
160 m_postPop = false;
161 }
162
163 int32_t mousestatus = mouseReadAbs(&m_mousepos, &g_mouseAbs);
164 if (mousestatus && g_mouseClickState == MOUSE_PRESSED)
165 m_mousedownpos = m_mousepos;
166
167 int16_t mousetile = 1043; // red arrow
168 if (tilesiz[mousetile].x > 0 && mousestatus)
169 {
170 if (!MOUSEACTIVECONDITION)
171 m_mousewake_watchpoint = 1;
172
173 if (MOUSEACTIVECONDITIONAL(mouseAdvanceClickState()) || m_mousepos.x != m_prevmousepos.x || m_mousepos.y != m_prevmousepos.y)
174 {
175 m_prevmousepos = m_mousepos;
176 m_mouselastactivity = (int)totalclock;
177 }
178 else
179 m_mousewake_watchpoint = 0;
180
181 m_mousecaught = 0;
182 }
183 else
184 {
185 m_mouselastactivity = -M_MOUSETIMEOUT;
186
187 m_mousewake_watchpoint = 0;
188 }
189
190 // Display the mouse cursor, except on touch devices.
191 if (MOUSEACTIVECONDITION)
192 {
193 vec2_t cursorpos = { m_mousepos.x + (7 << 16), m_mousepos.y + (6 << 16) };
194
195 if ((unsigned) mousetile < MAXTILES)
196 {
197 int32_t scale = 65536;
198 int16_t rotate = 768;
199 uint32_t stat = 2|4|8;
200 int8_t alpha = MOUSEALPHA; //CURSORALPHA;
201 rotatesprite_fs_alpha(cursorpos.x, cursorpos.y, scale, rotate, mousetile, 0, 0, stat, alpha);
202 }
203 }
204 else
205 g_mouseClickState = MOUSE_IDLE;
206 }
207
Clear(void)208 void CGameMenuMgr::Clear(void)
209 {
210 pActiveMenu = NULL;
211 memset(pMenuStack, 0, sizeof(pMenuStack));
212 nMenuPointer = 0;
213 m_postPop = false;
214 }
215
Process(void)216 void CGameMenuMgr::Process(void)
217 {
218 if (!pActiveMenu)
219 return;
220
221 if (m_menuchange_watchpoint > 0)
222 m_menuchange_watchpoint++;
223
224 CGameMenuEvent event;
225 event.at0 = 0;
226 event.at2 = 0;
227 char key;
228 if (!pActiveMenu->MouseEvent(event) && (key = keyGetScan()) != 0 )
229 {
230 keyFlushScans();
231 keyFlushChars();
232 event.at2 = key;
233 switch (key)
234 {
235 case sc_Escape:
236 event.at0 = kMenuEventEscape;
237 break;
238 case sc_Tab:
239 if (keystatus[sc_LeftShift] || keystatus[sc_RightShift])
240 event.at0 = kMenuEventUp;
241 else
242 event.at0 = kMenuEventDown;
243 break;
244 case sc_UpArrow:
245 case sc_kpad_8:
246 event.at0 = kMenuEventUp;
247 gGameMenuMgr.m_mouselastactivity = -M_MOUSETIMEOUT;
248 break;
249 case sc_DownArrow:
250 case sc_kpad_2:
251 event.at0 = kMenuEventDown;
252 gGameMenuMgr.m_mouselastactivity = -M_MOUSETIMEOUT;
253 break;
254 case sc_Enter:
255 case sc_kpad_Enter:
256 event.at0 = kMenuEventEnter;
257 break;
258 case sc_Space:
259 event.at0 = kMenuEventSpace;
260 break;
261 case sc_LeftArrow:
262 case sc_kpad_4:
263 event.at0 = kMenuEventLeft;
264 break;
265 case sc_RightArrow:
266 case sc_kpad_6:
267 event.at0 = kMenuEventRight;
268 break;
269 case sc_Delete:
270 case sc_kpad_Period:
271 event.at0 = kMenuEventDelete;
272 break;
273 case sc_BackSpace:
274 event.at0 = kMenuEventBackSpace;
275 break;
276 default:
277 event.at0 = kMenuEventKey;
278 break;
279 }
280 }
281 if (pActiveMenu->Event(event))
282 Pop();
283
284 if (m_menuchange_watchpoint >= 3)
285 m_menuchange_watchpoint = 0;
286 }
287
Deactivate(void)288 void CGameMenuMgr::Deactivate(void)
289 {
290 Clear();
291 keyFlushScans();
292 keyFlushChars();
293 m_bActive = false;
294
295 mouseLockToWindow(1);
296 gInputMode = INPUT_MODE_0;
297 }
298
MouseOutsideBounds(vec2_t const * const pos,const int32_t x,const int32_t y,const int32_t width,const int32_t height)299 bool CGameMenuMgr::MouseOutsideBounds(vec2_t const * const pos, const int32_t x, const int32_t y, const int32_t width, const int32_t height)
300 {
301 return pos->x < x || pos->x >= x + width || pos->y < y || pos->y >= y + height;
302 }
303
CGameMenu()304 CGameMenu::CGameMenu()
305 {
306 m_nItems = 0;
307 m_nFocus = at8 = -1;
308 atc = 0;
309 }
310
CGameMenu(int unk)311 CGameMenu::CGameMenu(int unk)
312 {
313 m_nItems = 0;
314 m_nFocus = at8 = -1;
315 atc = unk;
316 }
317
~CGameMenu()318 CGameMenu::~CGameMenu()
319 {
320 if (!atc)
321 return;
322 for (int i = 0; i < m_nItems; i++)
323 {
324 if (pItemList[i] != &itemBloodQAV && pItemList[i] != &itemSorryPicCycle)
325 delete pItemList[i];
326 }
327 }
328
InitializeItems(CGameMenuEvent & event)329 void CGameMenu::InitializeItems(CGameMenuEvent &event)
330 {
331 for (int i = 0; i < m_nItems; i++)
332 {
333 pItemList[i]->Event(event);
334 }
335 }
336
Draw(void)337 void CGameMenu::Draw(void)
338 {
339 for (int i = 0; i < m_nItems; i++)
340 {
341 if (pItemList[i]->pPreDrawCallback)
342 pItemList[i]->pPreDrawCallback(pItemList[i]);
343 if (i == m_nFocus || (i != m_nFocus && !pItemList[i]->bNoDraw))
344 pItemList[i]->Draw();
345 }
346 }
347
Event(CGameMenuEvent & event)348 bool CGameMenu::Event(CGameMenuEvent &event)
349 {
350 if (m_nItems <= 0)
351 return true;
352 switch (event.at0)
353 {
354 case kMenuEventInit:
355 case kMenuEventDeInit:
356 if (at8 >= 0)
357 m_nFocus = at8;
358 InitializeItems(event);
359 return false;
360 }
361 if (m_nFocus < 0)
362 return true;
363 return pItemList[m_nFocus]->Event(event);
364 }
365
Add(CGameMenuItem * pItem,bool active)366 void CGameMenu::Add(CGameMenuItem *pItem, bool active)
367 {
368 dassert(pItem != NULL);
369 dassert(m_nItems < kMaxGameMenuItems);
370 pItemList[m_nItems] = pItem;
371 pItem->pMenu = this;
372 if (active)
373 m_nFocus = at8 = m_nItems;
374 m_nItems++;
375 }
376
SetFocusItem(int nItem)377 void CGameMenu::SetFocusItem(int nItem)
378 {
379 dassert(nItem >= 0 && nItem < m_nItems && nItem < kMaxGameMenuItems);
380 if (CanSelectItem(nItem))
381 m_nFocus = at8 = nItem;
382 }
383
SetFocusItem(CGameMenuItem * pItem)384 void CGameMenu::SetFocusItem(CGameMenuItem *pItem)
385 {
386 for (int i = 0; i < m_nItems; i++)
387 if (pItemList[i] == pItem)
388 {
389 SetFocusItem(i);
390 break;
391 }
392 }
393
CanSelectItem(int nItem)394 bool CGameMenu::CanSelectItem(int nItem)
395 {
396 dassert(nItem >= 0 && nItem < m_nItems && nItem < kMaxGameMenuItems);
397 return pItemList[nItem]->bCanSelect && pItemList[nItem]->bEnable;
398 }
399
FocusPrevItem(void)400 void CGameMenu::FocusPrevItem(void)
401 {
402 dassert(m_nFocus >= -1 && m_nFocus < m_nItems && m_nFocus < kMaxGameMenuItems);
403 int t = m_nFocus;
404 do
405 {
406 m_nFocus--;
407 if (m_nFocus < 0)
408 m_nFocus += m_nItems;
409 if (CanSelectItem(m_nFocus))
410 break;
411 } while(t != m_nFocus);
412 }
413
FocusNextItem(void)414 void CGameMenu::FocusNextItem(void)
415 {
416 dassert(m_nFocus >= -1 && m_nFocus < m_nItems && m_nFocus < kMaxGameMenuItems);
417 int t = m_nFocus;
418 do
419 {
420 m_nFocus++;
421 if (m_nFocus >= m_nItems)
422 m_nFocus = 0;
423 if (CanSelectItem(m_nFocus))
424 break;
425 } while(t != m_nFocus);
426 }
427
IsFocusItem(CGameMenuItem * pItem)428 bool CGameMenu::IsFocusItem(CGameMenuItem *pItem)
429 {
430 if (m_nFocus < 0)
431 return false;
432 dassert(m_nFocus >= 0 && m_nFocus < m_nItems && m_nFocus < kMaxGameMenuItems);
433 return pItemList[m_nFocus] == pItem;
434 }
435
MouseEvent(CGameMenuEvent & event)436 bool CGameMenu::MouseEvent(CGameMenuEvent &event)
437 {
438 if (m_nItems <= 0 || m_nFocus < 0)
439 return true;
440 return pItemList[m_nFocus]->MouseEvent(event);
441 }
442
CGameMenuItem()443 CGameMenuItem::CGameMenuItem()
444 {
445 m_pzText = NULL;
446 m_nX = m_nY = m_nWidth = 0;
447 bCanSelect = 1;
448 bEnable = 1;
449 m_nFont = -1;
450 pMenu = NULL;
451 bNoDraw = 0;
452 pPreDrawCallback = NULL;
453 }
454
~CGameMenuItem()455 CGameMenuItem::~CGameMenuItem()
456 {
457 }
458
Event(CGameMenuEvent & event)459 bool CGameMenuItem::Event(CGameMenuEvent &event)
460 {
461 switch (event.at0)
462 {
463 case kMenuEventEscape:
464 return true;
465 case kMenuEventUp:
466 pMenu->FocusPrevItem();
467 break;
468 case kMenuEventDown:
469 pMenu->FocusNextItem();
470 break;
471 }
472 return false;
473 }
474
MouseEvent(CGameMenuEvent & event)475 bool CGameMenuItem::MouseEvent(CGameMenuEvent &event)
476 {
477 event.at0 = kMenuEventNone;
478 if (MOUSEINACTIVECONDITIONAL(MOUSE_GetButtons()&LEFT_MOUSE))
479 {
480 event.at0 = kMenuEventEnter;
481 MOUSE_ClearButton(LEFT_MOUSE);
482 }
483 else if (MOUSE_GetButtons()&RIGHT_MOUSE)
484 {
485 event.at0 = kMenuEventEscape;
486 MOUSE_ClearButton(RIGHT_MOUSE);
487 }
488 #if 0
489 else if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELUP_MOUSE)))
490 {
491 MOUSE_ClearButton(WHEELUP_MOUSE);
492 event.bAutoAim = kMenuEventScrollLeft;
493 }
494 else if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELDOWN_MOUSE)))
495 {
496 MOUSE_ClearButton(WHEELDOWN_MOUSE);
497 event.bAutoAim = kMenuEventScrollRight;
498 }
499 #endif
500 else if (MOUSE_GetButtons()&WHEELUP_MOUSE)
501 {
502 MOUSE_ClearButton(WHEELUP_MOUSE);
503 event.at0 = kMenuEventUp;
504 }
505 else if (MOUSE_GetButtons()&WHEELDOWN_MOUSE)
506 {
507 MOUSE_ClearButton(WHEELDOWN_MOUSE);
508 event.at0 = kMenuEventDown;
509 }
510 return event.at0 != kMenuEventNone;
511 }
512
CGameMenuItemText()513 CGameMenuItemText::CGameMenuItemText()
514 {
515 m_pzText = 0;
516 bEnable = 0;
517 }
518
CGameMenuItemText(const char * a1,int a2,int a3,int a4,int a5)519 CGameMenuItemText::CGameMenuItemText(const char *a1, int a2, int a3, int a4, int a5)
520 {
521 m_nWidth = 0;
522 m_pzText = a1;
523 m_nFont = a2;
524 m_nX = a3;
525 m_nY = a4;
526 at20 = a5;
527 bEnable = 0;
528 }
529
Draw(void)530 void CGameMenuItemText::Draw(void)
531 {
532 if (m_pzText)
533 {
534 int width;
535 int x = m_nX;
536 switch (at20)
537 {
538 case 1:
539 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
540 x = m_nX-width/2;
541 break;
542 case 2:
543 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
544 x = m_nX-width;
545 break;
546 }
547 gMenuTextMgr.DrawText(m_pzText,m_nFont, x, m_nY, -128, 0, false);
548 }
549 }
550
CGameMenuItemTitle()551 CGameMenuItemTitle::CGameMenuItemTitle()
552 {
553 m_pzText = 0;
554 bEnable = 0;
555 }
556
CGameMenuItemTitle(const char * a1,int a2,int a3,int a4,int a5)557 CGameMenuItemTitle::CGameMenuItemTitle(const char *a1, int a2, int a3, int a4, int a5)
558 {
559 m_nWidth = 0;
560 m_pzText = a1;
561 m_nFont = a2;
562 m_nX = a3;
563 m_nY = a4;
564 at20 = a5;
565 bEnable = 0;
566 }
567
Draw(void)568 void CGameMenuItemTitle::Draw(void)
569 {
570 if (m_pzText)
571 {
572 int height;
573 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
574 if (at20 >= 0)
575 rotatesprite(320<<15, m_nY<<16, 65536, 0, at20, -128, 0, 78, 0, 0, xdim-1, ydim-1);
576 viewDrawText(m_nFont, m_pzText, m_nX, m_nY-height/2, -128, 0, 1, false);
577 }
578 }
579
CGameMenuItemZBool()580 CGameMenuItemZBool::CGameMenuItemZBool()
581 {
582 at20 = false;
583 m_pzText = 0;
584 at21 = "On";
585 at25 = "Off";
586 }
587
CGameMenuItemZBool(const char * a1,int a2,int a3,int a4,int a5,bool a6,void (* a7)(CGameMenuItemZBool *),const char * a8,const char * a9)588 CGameMenuItemZBool::CGameMenuItemZBool(const char *a1, int a2, int a3, int a4, int a5, bool a6, void(*a7)(CGameMenuItemZBool *), const char *a8, const char *a9)
589 {
590 m_pzText = a1;
591 m_nFont = a2;
592 m_nX = a3;
593 m_nY = a4;
594 m_nWidth = a5;
595 at20 = a6;
596 at29 = a7;
597 if (!a8)
598 at21 = "On";
599 else
600 at21 = a8;
601 if (!a9)
602 at25 = "Off";
603 else
604 at25 = a9;
605 }
606
Draw(void)607 void CGameMenuItemZBool::Draw(void)
608 {
609 int shade = bEnable ? 32 : 48;
610 int pal = bEnable ? 0 : 5;
611 if (pMenu->IsFocusItem(this))
612 shade = 32-((int)totalclock&63);
613 if (m_pzText)
614 gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
615 const char *value = at20 ? at21 : at25;
616 int width, height;
617 gMenuTextMgr.GetFontInfo(m_nFont, value, &width, &height);
618 gMenuTextMgr.DrawText(value, m_nFont, m_nWidth-1+m_nX-width, m_nY, shade, pal, false);
619 int mx = m_nX<<16;
620 int my = m_nY<<16;
621 int mw = m_nWidth<<16;
622 int mh = height<<16;
623 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
624 {
625 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
626 {
627 pMenu->SetFocusItem(this);
628 }
629
630 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
631 {
632 pMenu->SetFocusItem(this);
633
634 CGameMenuEvent event = { kMenuEventEnter, 0 };
635
636 gGameMenuMgr.m_mousecaught = 1;
637
638 if (Event(event))
639 gGameMenuMgr.PostPop();
640 }
641 }
642 }
643
Event(CGameMenuEvent & event)644 bool CGameMenuItemZBool::Event(CGameMenuEvent &event)
645 {
646 switch (event.at0)
647 {
648 case kMenuEventEnter:
649 case kMenuEventSpace:
650 at20 = !at20;
651 if (at29)
652 at29(this);
653 return false;
654 }
655 return CGameMenuItem::Event(event);
656 }
657
CGameMenuItemChain()658 CGameMenuItemChain::CGameMenuItemChain()
659 {
660 m_pzText = NULL;
661 at24 = NULL;
662 at28 = -1;
663 at2c = NULL;
664 at30 = 0;
665 }
666
CGameMenuItemChain(const char * a1,int a2,int a3,int a4,int a5,int a6,CGameMenu * a7,int a8,void (* a9)(CGameMenuItemChain *),int a10)667 CGameMenuItemChain::CGameMenuItemChain(const char *a1, int a2, int a3, int a4, int a5, int a6, CGameMenu *a7, int a8, void(*a9)(CGameMenuItemChain *), int a10)
668 {
669 m_pzText = a1;
670 m_nFont = a2;
671 m_nX = a3;
672 m_nY = a4;
673 m_nWidth = a5;
674 at20 = a6;
675 at24 = a7;
676 at28 = a8;
677 at2c = a9;
678 at30 = a10;
679 }
680
Draw(void)681 void CGameMenuItemChain::Draw(void)
682 {
683 if (!m_pzText) return;
684 int shade = bEnable ? 32 : 48;
685 int pal = bEnable ? 0 : 5;
686 if (pMenu->IsFocusItem(this))
687 shade = 32-((int)totalclock&63);
688 int width, height;
689 int x = m_nX;
690 int y = m_nY;
691 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, &height);
692 switch (at20)
693 {
694 case 1:
695 x = m_nX+m_nWidth/2-width/2;
696 break;
697 case 2:
698 x = m_nX+m_nWidth-1-width;
699 break;
700 case 0:
701 default:
702 break;
703 }
704 gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, pal, true);
705 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, x<<16, y<<16, width<<16, height<<16)))
706 {
707 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, x<<16, y<<16, width<<16, height<<16)))
708 {
709 pMenu->SetFocusItem(this);
710 }
711
712 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, x<<16, y<<16, width<<16, height<<16))
713 {
714 pMenu->SetFocusItem(this);
715
716 CGameMenuEvent event = { kMenuEventEnter, 0 };
717
718 gGameMenuMgr.m_mousecaught = 1;
719
720 if (Event(event))
721 gGameMenuMgr.PostPop();
722 }
723 }
724 }
725
Event(CGameMenuEvent & event)726 bool CGameMenuItemChain::Event(CGameMenuEvent &event)
727 {
728 switch (event.at0)
729 {
730 case kMenuEventEnter:
731 if (at2c)
732 at2c(this);
733 if (at24)
734 gGameMenuMgr.Push(at24, at28);
735 return false;
736 }
737 return CGameMenuItem::Event(event);
738 }
739
CGameMenuItem7EA1C()740 CGameMenuItem7EA1C::CGameMenuItem7EA1C()
741 {
742 m_pzText = NULL;
743 at24 = NULL;
744 at28 = -1;
745 at2c = NULL;
746 at30 = 0;
747 at34 = NULL;
748 at38[0] = 0;
749 at48[0] = 0;
750 }
751
CGameMenuItem7EA1C(const char * a1,int a2,int a3,int a4,int a5,const char * a6,const char * a7,int a8,int a9,void (* a10)(CGameMenuItem7EA1C *),int a11)752 CGameMenuItem7EA1C::CGameMenuItem7EA1C(const char *a1, int a2, int a3, int a4, int a5, const char *a6, const char *a7, int a8, int a9, void(*a10)(CGameMenuItem7EA1C *), int a11)
753 {
754 m_pzText = a1;
755 m_nFont = a2;
756 m_nX = a3;
757 m_nY = a4;
758 m_nWidth = a5;
759 at20 = a8;
760 at28 = a9;
761 at2c = a10;
762 at30 = a11;
763 strncpy(at38, a6, 15);
764 strncpy(at48, a7, 15);
765 }
766
Draw(void)767 void CGameMenuItem7EA1C::Draw(void)
768 {
769 if (!m_pzText) return;
770 int shade = bEnable ? 32 : 48;
771 int pal = bEnable ? 0 : 5;
772 if (pMenu->IsFocusItem(this))
773 shade = 32-((int)totalclock&63);
774 int width;
775 int x = m_nX;
776 switch (at20)
777 {
778 case 1:
779 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
780 x = m_nX+m_nWidth/2-width/2;
781 break;
782 case 2:
783 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
784 x = m_nX+m_nWidth-1-width;
785 break;
786 case 0:
787 default:
788 break;
789 }
790 gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, pal, true);
791 }
792
Setup(void)793 void CGameMenuItem7EA1C::Setup(void)
794 {
795 if (!at34 || !at24)
796 return;
797 if (!at34->SectionExists(at48))
798 return;
799 const char *title = at34->GetKeyString(at48, "Title", at48);
800 at24->Add(new CGameMenuItemTitle(title, 1, 160, 20, 2038), false);
801 at24->Add(&itemSorryPicCycle, true);
802 int y = 40;
803 for (int i = 0; i < 21; i++)
804 {
805 sprintf(buffer[i], "Line%d", i+1);
806 if (!at34->KeyExists(at48, buffer[i]))
807 break;
808 const char *line = at34->GetKeyString(at48, buffer[i], NULL);
809 if (line)
810 {
811 if (*line == 0)
812 {
813 y += 10;
814 continue;
815 }
816 at24->Add(new CGameMenuItemText(line, 1, 160, y, 1), false);
817 y += 20;
818 }
819 }
820 at24->Add(&itemBloodQAV, false);
821 }
822
Event(CGameMenuEvent & event)823 bool CGameMenuItem7EA1C::Event(CGameMenuEvent &event)
824 {
825 switch (event.at0)
826 {
827 case kMenuEventEnter:
828 {
829 if (at2c)
830 at2c(this);
831 if (at24)
832 delete at24;
833 at24 = new CGameMenu(1);
834 DICTNODE *pRes = gGuiRes.Lookup(at38, "MNU");
835 if (pRes)
836 {
837 at34 = new IniFile(gGuiRes.Load(pRes));
838 Setup();
839 }
840 if (at24)
841 gGameMenuMgr.Push(at24, at28);
842 return false;
843 }
844 case kMenuEventDeInit:
845 if (at34)
846 {
847 delete at34;
848 at34 = NULL;
849 }
850 if (at24)
851 {
852 delete at24;
853 at24 = NULL;
854 }
855 return false;
856 }
857 return CGameMenuItem::Event(event);
858 }
859
CGameMenuItem7EE34()860 CGameMenuItem7EE34::CGameMenuItem7EE34()
861 {
862 m_pzText = NULL;
863 at28 = NULL;
864 at20 = -1;
865 at2c = NULL;
866 }
867
CGameMenuItem7EE34(const char * a1,int a2,int a3,int a4,int a5,int a6)868 CGameMenuItem7EE34::CGameMenuItem7EE34(const char *a1, int a2, int a3, int a4, int a5, int a6)
869 {
870 m_pzText = NULL;
871 at28 = NULL;
872 at20 = -1;
873 at2c = NULL;
874 m_nFont = a2;
875 m_nX = a3;
876 m_pzText = a1;
877 m_nY = a4;
878 m_nWidth = a5;
879 at24 = a6;
880 }
881
Draw(void)882 void CGameMenuItem7EE34::Draw(void)
883 {
884 if (!m_pzText) return;
885 int shade = bEnable ? 32 : 48;
886 int pal = bEnable ? 0 : 5;
887 if (pMenu->IsFocusItem(this))
888 shade = 32-((int)totalclock&63);
889 int width;
890 int x = m_nX;
891 switch (at24)
892 {
893 case 1:
894 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
895 x = m_nX+m_nWidth/2-width/2;
896 break;
897 case 2:
898 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
899 x = m_nX+m_nWidth-1-width;
900 break;
901 case 0:
902 default:
903 break;
904 }
905 gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, pal, true);
906 }
907
908 extern void SetVideoModeOld(CGameMenuItemChain *pItem);
909
Setup(void)910 void CGameMenuItem7EE34::Setup(void)
911 {
912 if (!at28)
913 return;
914 at28->Add(new CGameMenuItemTitle("Video Mode", 1, 160, 20, 2038), false);
915 if (!at2c)
916 {
917 at2c = new CGameMenu(1);
918 at2c->Add(new CGameMenuItemTitle(" Mode Change ", 1, 160, 20, 2038), false);
919 at2c->Add(&itemSorryPicCycle, true);
920 CGameMenuItem *pItem1 = new CGameMenuItemText("VIDEO MODE WAS SET", 1, 160, 90, 1);
921 CGameMenuItem *pItem2 = new CGameMenuItemText("NOT ALL MODES Work correctly", 1, 160, 110, 1);
922 CGameMenuItem *pItem3 = new CGameMenuItemText("Press ESC to exit", 3, 160, 140, 1);
923 at2c->Add(pItem1, false);
924 pItem1->bEnable = 0;
925 at2c->Add(pItem2, false);
926 pItem2->bEnable = 0;
927 at2c->Add(pItem3, true);
928 pItem3->bEnable = 1;
929 at2c->Add(&itemBloodQAV, false);
930 }
931 sprintf(buffer[0], "640 x 480 (default)");
932 int y = 40;
933 at28->Add(new CGameMenuItemChain(buffer[0], 3, 0, y, 320, 1, at2c, -1, SetVideoModeOld, validmodecnt), true);
934 y += 20;
935 for (int i = 0; i < validmodecnt && i < 20; i++)
936 {
937 sprintf(buffer[i+1], "%d x %d", validmode[i].xdim, validmode[i].ydim);
938 at28->Add(new CGameMenuItemChain(buffer[i+1], 3, 0, y, 320, 1, at2c, -1, SetVideoModeOld, i), false);
939 if (validmodecnt > 10)
940 y += 7;
941 else
942 y += 15;
943 }
944 at28->Add(&itemBloodQAV, false);
945 }
946
Event(CGameMenuEvent & event)947 bool CGameMenuItem7EE34::Event(CGameMenuEvent &event)
948 {
949 switch (event.at0)
950 {
951 case kMenuEventEnter:
952 if (at28)
953 delete at28;
954 at28 = new CGameMenu(1);
955 Setup();
956 if (at28)
957 gGameMenuMgr.Push(at28, at20);
958 return false;
959 case kMenuEventDeInit:
960 if (at28)
961 {
962 delete at28;
963 at28 = 0;
964 }
965 return false;
966 }
967 return CGameMenuItem::Event(event);
968 }
969
CGameMenuItemChain7F2F0()970 CGameMenuItemChain7F2F0::CGameMenuItemChain7F2F0()
971 {
972 at34 = -1;
973 }
974
CGameMenuItemChain7F2F0(char * a1,int a2,int a3,int a4,int a5,int a6,CGameMenu * a7,int a8,void (* a9)(CGameMenuItemChain *),int a10)975 CGameMenuItemChain7F2F0::CGameMenuItemChain7F2F0(char *a1, int a2, int a3, int a4, int a5, int a6, CGameMenu *a7, int a8, void(*a9)(CGameMenuItemChain *), int a10) :
976 CGameMenuItemChain(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
977 {
978 at34 = a10;
979 }
980
Event(CGameMenuEvent & event)981 bool CGameMenuItemChain7F2F0::Event(CGameMenuEvent &event)
982 {
983 switch (event.at0)
984 {
985 case kMenuEventEnter:
986 if (at34 > -1)
987 {
988 gGameOptions.nEpisode = at34;
989 Bstrcpy(gGameOptions.szUserMap, "\0");
990 }
991 return CGameMenuItemChain::Event(event);
992 }
993 return CGameMenuItem::Event(event);
994 }
995
CGameMenuItemBitmap()996 CGameMenuItemBitmap::CGameMenuItemBitmap()
997 {
998 m_pzText = NULL;
999 }
1000
CGameMenuItemBitmap(const char * a1,int a2,int a3,int a4,int a5)1001 CGameMenuItemBitmap::CGameMenuItemBitmap(const char *a1, int a2, int a3, int a4, int a5)
1002 {
1003 m_pzText = a1;
1004 m_nFont = a2;
1005 m_nX = a3;
1006 m_nY = a4;
1007 at20 = a5;
1008 }
1009
Draw(void)1010 void CGameMenuItemBitmap::Draw(void)
1011 {
1012 int shade = bEnable ? 32 : 48;
1013 int pal = bEnable ? 0 : 5;
1014 if (bEnable && pMenu->IsFocusItem(this))
1015 shade = 32-((int)totalclock&63);
1016 int x = m_nX;
1017 int y = m_nY;
1018 if (m_pzText)
1019 {
1020 int height;
1021 gMenuTextMgr.DrawText(m_pzText, m_nFont, x, y, shade, pal, false);
1022 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
1023 y += height + 2;
1024 }
1025 rotatesprite(x<<15,y<<15, 65536, 0, at20, 0, 0, 82, 0, 0, xdim-1,ydim-1);
1026 }
1027
Event(CGameMenuEvent & event)1028 bool CGameMenuItemBitmap::Event(CGameMenuEvent &event)
1029 {
1030 if (bEnable && pMenu->IsFocusItem(this))
1031 pMenu->FocusNextItem();
1032 return CGameMenuItem::Event(event);
1033 }
1034
CGameMenuItemBitmapLS()1035 CGameMenuItemBitmapLS::CGameMenuItemBitmapLS()
1036 {
1037 m_pzText = NULL;
1038 }
1039
CGameMenuItemBitmapLS(const char * a1,int a2,int a3,int a4,int a5)1040 CGameMenuItemBitmapLS::CGameMenuItemBitmapLS(const char *a1, int a2, int a3, int a4, int a5)
1041 {
1042 at24 = -1;
1043 m_pzText = a1;
1044 m_nFont = a2;
1045 m_nX = a3;
1046 m_nY = a4;
1047 at28 = a5;
1048 }
1049
Draw(void)1050 void CGameMenuItemBitmapLS::Draw(void)
1051 {
1052 int shade = bEnable ? 32 : 48;
1053 int pal = bEnable ? 0 : 5;
1054 if (bEnable && pMenu->IsFocusItem(this))
1055 shade = 32-((int)totalclock&63);
1056 int x = m_nX;
1057 int y = m_nY;
1058 if (m_pzText)
1059 {
1060 int height;
1061 gMenuTextMgr.DrawText(m_pzText, m_nFont, x, y, shade, pal, false);
1062 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
1063 y += height + 2;
1064 }
1065 char stat;
1066 int16_t ang;
1067 int picnum;
1068 if (at24 == -1)
1069 {
1070 stat = 66;
1071 ang = 0;
1072 picnum = at28;
1073 }
1074 else
1075 {
1076 ang = 512;
1077 stat = 70;
1078 picnum = at24;
1079 }
1080 rotatesprite(200<<15,215<<15,32768, ang, picnum, 0, 0, stat, 0, 0, xdim-1, ydim-1);
1081 }
1082
Event(CGameMenuEvent & event)1083 bool CGameMenuItemBitmapLS::Event(CGameMenuEvent &event)
1084 {
1085 if (bEnable && pMenu->IsFocusItem(this))
1086 pMenu->FocusNextItem();
1087 return CGameMenuItem::Event(event);
1088 }
1089
CGameMenuItemKeyList()1090 CGameMenuItemKeyList::CGameMenuItemKeyList()
1091 {
1092 m_pzText = NULL;
1093 m_nFont = 3;
1094 m_nX = 0;
1095 m_nY = 0;
1096 nRows = 0;
1097 nTopDelta = 0;
1098 nFocus = 0;
1099 nGameFuncs = 0;
1100 bScan = false;
1101 }
1102
CGameMenuItemKeyList(const char * a1,int a2,int a3,int a4,int a5,int a6,int a7,void (* a8)(CGameMenuItemKeyList *))1103 CGameMenuItemKeyList::CGameMenuItemKeyList(const char *a1, int a2, int a3, int a4, int a5, int a6, int a7, void(*a8)(CGameMenuItemKeyList *))
1104 {
1105 nTopDelta = 0;
1106 nFocus = 0;
1107 bScan = false;
1108 m_pzText = a1;
1109 m_nFont = a2;
1110 m_nX = a3;
1111 m_nY = a4;
1112 m_nWidth = a5;
1113 nRows = a6;
1114 pCallback = a8;
1115 nGameFuncs = a7;
1116 }
1117
Scan(void)1118 void CGameMenuItemKeyList::Scan(void)
1119 {
1120 KB_FlushKeyboardQueue();
1121 KB_FlushKeyboardQueueScans();
1122 KB_ClearKeysDown();
1123 KB_LastScan = 0;
1124 bScan = true;
1125 }
1126
1127 extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
Draw(void)1128 void CGameMenuItemKeyList::Draw(void)
1129 {
1130 char buffer[40], buffer2[40];
1131 int width, height;
1132 int shade;
1133 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
1134 int y = m_nY;
1135 int k = nFocus - nTopDelta;
1136 int nNewFocus = nFocus;
1137 bool bClick = false;
1138 for (int i = 0; i < nRows; i++, y += height, k++)
1139 {
1140 char key1, key2;
1141 key1 = KeyboardKeys[k][0];
1142 key2 = KeyboardKeys[k][1];
1143 const char *sKey1 = key1 == sc_Tilde ? "Tilde" : KB_ScanCodeToString(key1);
1144 const char *sKey2 = key2 == sc_Tilde ? "Tilde" : KB_ScanCodeToString(key2);
1145 sprintf(buffer, "%s", CONFIG_FunctionNumToName(k));
1146 if (key2 == 0 || key2 == 0xff)
1147 {
1148 if (key1 == 0 || key1 == 0xff)
1149 sprintf(buffer2, "????");
1150 else
1151 sprintf(buffer2, "%s", sKey1);
1152 }
1153 else
1154 sprintf(buffer2, "%s or %s", sKey1, sKey2);
1155
1156 if (k == nFocus)
1157 {
1158 shade = 32;
1159 if (pMenu->IsFocusItem(this))
1160 shade = 32-((int)totalclock&63);
1161 viewDrawText(3, buffer, m_nX, y, shade, 0, 0, false);
1162 const char *sVal;
1163 if (bScan && ((int)totalclock & 32))
1164 sVal = "____";
1165 else
1166 sVal = buffer2;
1167 gMenuTextMgr.GetFontInfo(m_nFont, sVal, &width, 0);
1168 viewDrawText(m_nFont, sVal, m_nX+m_nWidth-1-width, y, shade, 0, 0, false);
1169 }
1170 else
1171 {
1172 viewDrawText(3, buffer, m_nX, y, 24, 0, 0, false);
1173 gMenuTextMgr.GetFontInfo(m_nFont, buffer2, &width, 0);
1174 viewDrawText(m_nFont, buffer2, m_nX+m_nWidth-1-width, y, 24, 0, 0, false);
1175 }
1176 int mx = m_nX<<16;
1177 int my = y<<16;
1178 int mw = m_nWidth<<16;
1179 int mh = height<<16;
1180 if (!bScan && bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
1181 {
1182 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
1183 {
1184 nNewFocus = k;
1185 }
1186
1187 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
1188 {
1189 nNewFocus = k;
1190 bClick = true;
1191 }
1192 }
1193 }
1194 nTopDelta += nNewFocus-nFocus;
1195 nFocus = nNewFocus;
1196 if (bClick)
1197 {
1198 CGameMenuEvent event = { kMenuEventEnter, 0 };
1199
1200 gGameMenuMgr.m_mousecaught = 1;
1201
1202 if (Event(event))
1203 gGameMenuMgr.PostPop();
1204 }
1205 }
1206
Event(CGameMenuEvent & event)1207 bool CGameMenuItemKeyList::Event(CGameMenuEvent &event)
1208 {
1209 if (bScan)
1210 {
1211 if (KB_LastScan && KB_LastScan != sc_Pause)
1212 {
1213 if (KB_KeyWaiting())
1214 KB_GetCh();
1215 char key1, key2;
1216 extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
1217 key1 = KeyboardKeys[nFocus][0];
1218 key2 = KeyboardKeys[nFocus][1];
1219 if (key1 > 0 && key2 != KB_LastScan)
1220 key2 = key1;
1221 key1 = KB_LastScan;
1222 if (key1 == key2)
1223 key2 = 0;
1224 uint8_t oldKey[2];
1225 oldKey[0] = KeyboardKeys[nFocus][0];
1226 oldKey[1] = KeyboardKeys[nFocus][1];
1227 KeyboardKeys[nFocus][0] = key1;
1228 KeyboardKeys[nFocus][1] = key2;
1229 CONFIG_MapKey(nFocus, key1, oldKey[0], key2, oldKey[1]);
1230 KB_FlushKeyboardQueue();
1231 KB_FlushKeyboardQueueScans();
1232 KB_ClearKeysDown();
1233 keyFlushScans();
1234 keyFlushChars();
1235 bScan = 0;
1236 }
1237 return false;
1238 }
1239 switch (event.at0)
1240 {
1241 case kMenuEventUp:
1242 if (event.at2 == sc_Tab || nFocus == 0)
1243 {
1244 pMenu->FocusPrevItem();
1245 return false;
1246 }
1247 nFocus--;
1248 if (nTopDelta > 0)
1249 nTopDelta--;
1250 return false;
1251 case kMenuEventDown:
1252 if (event.at2 == sc_Tab || nFocus == nGameFuncs-1)
1253 {
1254 pMenu->FocusNextItem();
1255 return false;
1256 }
1257 nFocus++;
1258 if (nTopDelta+1 < nRows)
1259 nTopDelta++;
1260 return false;
1261 case kMenuEventEnter:
1262 if (pCallback)
1263 pCallback(this);
1264 Scan();
1265 return false;
1266 case kMenuEventBackSpace:
1267 case kMenuEventDelete:
1268 uint8_t oldKey[2];
1269 oldKey[0] = KeyboardKeys[nFocus][0];
1270 oldKey[1] = KeyboardKeys[nFocus][1];
1271 KeyboardKeys[nFocus][0] = 0;
1272 KeyboardKeys[nFocus][1] = 0;
1273 CONFIG_MapKey(nFocus, 0, oldKey[0], 0, oldKey[1]);
1274 return false;
1275 case kMenuEventScrollUp:
1276 if (nFocus-nTopDelta > 0)
1277 {
1278 nTopDelta++;
1279 if (nTopDelta>0)
1280 {
1281 nFocus--;
1282 nTopDelta--;
1283 }
1284 }
1285 return false;
1286 case kMenuEventScrollDown:
1287 if (nFocus-nTopDelta+nRows < nGameFuncs)
1288 {
1289 nTopDelta--;
1290 if (nTopDelta+1 < nRows)
1291 {
1292 nFocus++;
1293 nTopDelta++;
1294 }
1295 }
1296 return false;
1297 }
1298 return CGameMenuItem::Event(event);
1299 }
1300
MouseEvent(CGameMenuEvent & event)1301 bool CGameMenuItemKeyList::MouseEvent(CGameMenuEvent &event)
1302 {
1303 event.at0 = kMenuEventNone;
1304 if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELUP_MOUSE))
1305 {
1306 gGameMenuMgr.m_mouselastactivity = (int)totalclock;
1307 MOUSE_ClearButton(WHEELUP_MOUSE);
1308 event.at0 = kMenuEventScrollUp;
1309 }
1310 else if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELDOWN_MOUSE))
1311 {
1312 gGameMenuMgr.m_mouselastactivity = (int)totalclock;
1313 MOUSE_ClearButton(WHEELDOWN_MOUSE);
1314 event.at0 = kMenuEventScrollDown;
1315 }
1316 else
1317 return CGameMenuItem::MouseEvent(event);
1318 return event.at0 != kMenuEventNone;
1319 }
1320
CGameMenuItemSlider()1321 CGameMenuItemSlider::CGameMenuItemSlider()
1322 {
1323 m_pzText = NULL;
1324 m_nFont = -1;
1325 m_nX = 0;
1326 m_nY = 0;
1327 nValue = 0;
1328 nRangeLow = 0;
1329 nStep = 0;
1330 pCallback = NULL;
1331 pValue = NULL;
1332 nSliderTile = 2204;
1333 nCursorTile = 2028;
1334 nShowValue = kMenuSliderNone;
1335 }
1336
CGameMenuItemSlider(const char * _pzText,int _nFont,int _nX,int _nY,int _nWidth,int _nValue,int _nRangeLow,int _nRangeHigh,int _nStep,void (* _pCallback)(CGameMenuItemSlider *),int _nSliderTile,int _nCursorTile,int _nShowValue)1337 CGameMenuItemSlider::CGameMenuItemSlider(const char *_pzText, int _nFont, int _nX, int _nY, int _nWidth, int _nValue, int _nRangeLow, int _nRangeHigh, int _nStep, void(*_pCallback)(CGameMenuItemSlider *), int _nSliderTile, int _nCursorTile, int _nShowValue)
1338 {
1339 m_pzText = _pzText;
1340 m_nFont = _nFont;
1341 m_nX = _nX;
1342 m_nY = _nY;
1343 m_nWidth = _nWidth;
1344 nRangeLow = _nRangeLow;
1345 nRangeHigh = _nRangeHigh;
1346 nStep = _nStep;
1347 nValue = ClipRange(_nValue, nRangeLow, nRangeHigh);
1348 pCallback = _pCallback;
1349 nSliderTile = 2204;
1350 nCursorTile = 2028;
1351 if (_nSliderTile >= 0)
1352 nSliderTile = _nSliderTile;
1353 if (_nCursorTile >= 0)
1354 nCursorTile = _nCursorTile;
1355 nShowValue = _nShowValue;
1356 }
1357
CGameMenuItemSlider(const char * _pzText,int _nFont,int _nX,int _nY,int _nWidth,int * pnValue,int _nRangeLow,int _nRangeHigh,int _nStep,void (* _pCallback)(CGameMenuItemSlider *),int _nSliderTile,int _nCursorTile,int _nShowValue)1358 CGameMenuItemSlider::CGameMenuItemSlider(const char *_pzText, int _nFont, int _nX, int _nY, int _nWidth, int *pnValue, int _nRangeLow, int _nRangeHigh, int _nStep, void(*_pCallback)(CGameMenuItemSlider *), int _nSliderTile, int _nCursorTile, int _nShowValue)
1359 {
1360 m_pzText = _pzText;
1361 m_nFont = _nFont;
1362 m_nX = _nX;
1363 m_nY = _nY;
1364 m_nWidth = _nWidth;
1365 nRangeLow = _nRangeLow;
1366 nRangeHigh = _nRangeHigh;
1367 nStep = _nStep;
1368 dassert(pnValue != NULL);
1369 pValue = pnValue;
1370 nValue = ClipRange(*pnValue, nRangeLow, nRangeHigh);
1371 pCallback = _pCallback;
1372 nSliderTile = 2204;
1373 nCursorTile = 2028;
1374 if (_nSliderTile >= 0)
1375 nSliderTile = _nSliderTile;
1376 if (_nCursorTile >= 0)
1377 nCursorTile = _nCursorTile;
1378 nShowValue = _nShowValue;
1379 }
1380
Draw(void)1381 void CGameMenuItemSlider::Draw(void)
1382 {
1383 char buffer[16];
1384 int height;
1385 nValue = pValue ? *pValue : nValue;
1386 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
1387 int shade = bEnable ? 32 : 48;
1388 int shade2 = bEnable ? 0 : 16;
1389 int pal = bEnable ? 0 : 5;
1390 if (pMenu->IsFocusItem(this))
1391 shade = 32-((int)totalclock&63);
1392 if (m_pzText)
1393 gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
1394 int sliderX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x/2;
1395 rotatesprite(sliderX<<16, (m_nY+height/2)<<16, 65536, 0, nSliderTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
1396 int nRange = nRangeHigh - nRangeLow;
1397 dassert(nRange > 0);
1398 int value = nValue - nRangeLow;
1399 int width = tilesiz[nSliderTile].x-8;
1400 int cursorX = sliderX + ksgn(nStep)*(value * width / nRange - width / 2);
1401 rotatesprite(cursorX<<16, (m_nY+height/2)<<16, 65536, 0, nCursorTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
1402
1403 buffer[0] = 0;
1404 switch (nShowValue)
1405 {
1406 case kMenuSliderNone:
1407 break;
1408 case kMenuSliderValue:
1409 sprintf(buffer, "%i ", nValue);
1410 break;
1411 case kMenuSliderPercent:
1412 sprintf(buffer, "%i%% ", roundscale(value, 100, nRange));
1413 break;
1414 case kMenuSliderQ16:
1415 snprintf(buffer, 16, "%.3f ", nValue/65536.f);
1416 break;
1417 }
1418 int valueWidth;
1419 gMenuTextMgr.GetFontInfo(m_nFont, buffer, &valueWidth, NULL);
1420 int valueX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x-valueWidth;
1421 gMenuTextMgr.DrawText(buffer, m_nFont, valueX, m_nY, 32, 0, false);
1422
1423 int mx = m_nX;
1424 int my = m_nY;
1425 int mw = m_nWidth;
1426 int mh = height;
1427 if (height < tilesiz[nSliderTile].y)
1428 {
1429 my -= (tilesiz[nSliderTile].y-height)/2;
1430 height = tilesiz[nSliderTile].y;
1431 }
1432 mx <<= 16;
1433 my <<= 16;
1434 mw <<= 16;
1435 mh <<= 16;
1436
1437 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
1438 {
1439 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
1440 {
1441 pMenu->SetFocusItem(this);
1442 }
1443
1444 if (!gGameMenuMgr.m_mousecaught && (g_mouseClickState == MOUSE_PRESSED || g_mouseClickState == MOUSE_HELD))
1445 {
1446 pMenu->SetFocusItem(this);
1447
1448 int sliderx = m_nX+m_nWidth-1-tilesiz[nSliderTile].x;
1449 int sliderwidth = tilesiz[nSliderTile].x;
1450 int regionwidth = sliderwidth-8;
1451 int regionx = sliderx+(sliderwidth-regionwidth)/2;
1452 sliderx <<= 16;
1453 sliderwidth <<= 16;
1454 regionwidth <<= 16;
1455 regionx <<= 16;
1456
1457 // region between the x-midline of the slidepoint at the extremes slides proportionally
1458 if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, regionx, my, regionwidth, mh))
1459 {
1460 int dx = (gGameMenuMgr.m_mousepos.x - (regionx+regionwidth/2))*ksgn(nStep);
1461 nValue = nRangeLow + roundscale(dx+regionwidth/2, nRange, regionwidth);
1462 nValue = ClipRange(nValue, nRangeLow, nRangeHigh);
1463 if (pCallback)
1464 pCallback(this);
1465 gGameMenuMgr.m_mousecaught = 1;
1466 }
1467 // region outside the x-midlines clamps to the extremes
1468 else if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, sliderx, my, sliderwidth, mh))
1469 {
1470 if ((gGameMenuMgr.m_mousepos.x-(regionx+regionwidth/2))*ksgn(nStep) > 0)
1471 nValue = nRangeHigh;
1472 else
1473 nValue = nRangeLow;
1474 if (pCallback)
1475 pCallback(this);
1476 gGameMenuMgr.m_mousecaught = 1;
1477 }
1478 }
1479 }
1480 }
1481
Event(CGameMenuEvent & event)1482 bool CGameMenuItemSlider::Event(CGameMenuEvent &event)
1483 {
1484 nValue = pValue ? *pValue : nValue;
1485 switch (event.at0)
1486 {
1487 case kMenuEventUp:
1488 pMenu->FocusPrevItem();
1489 return false;
1490 case kMenuEventDown:
1491 pMenu->FocusNextItem();
1492 return false;
1493 case kMenuEventLeft:
1494 if (nStep > 0)
1495 nValue = DecBy(nValue, nStep);
1496 else
1497 nValue = IncBy(nValue, -nStep);
1498 nValue = ClipRange(nValue, nRangeLow, nRangeHigh);
1499 if (pCallback)
1500 pCallback(this);
1501 return false;
1502 case kMenuEventRight:
1503 if (nStep >= 0)
1504 nValue = IncBy(nValue, nStep);
1505 else
1506 nValue = DecBy(nValue, -nStep);
1507 nValue = ClipRange(nValue, nRangeLow, nRangeHigh);
1508 if (pCallback)
1509 pCallback(this);
1510 return false;
1511 case kMenuEventEnter:
1512 if (pCallback)
1513 pCallback(this);
1514 return false;
1515 }
1516 return CGameMenuItem::Event(event);
1517 }
1518
MouseEvent(CGameMenuEvent & event)1519 bool CGameMenuItemSlider::MouseEvent(CGameMenuEvent &event)
1520 {
1521 event.at0 = kMenuEventNone;
1522 if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELUP_MOUSE)))
1523 {
1524 MOUSE_ClearButton(WHEELUP_MOUSE);
1525 event.at0 = kMenuEventLeft;
1526 }
1527 else if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELDOWN_MOUSE)))
1528 {
1529 MOUSE_ClearButton(WHEELDOWN_MOUSE);
1530 event.at0 = kMenuEventRight;
1531 }
1532 else if (MOUSE_GetButtons()&RIGHT_MOUSE)
1533 {
1534 MOUSE_ClearButton(RIGHT_MOUSE);
1535 event.at0 = kMenuEventEscape;
1536 }
1537 else if (MOUSE_GetButtons()&WHEELUP_MOUSE)
1538 {
1539 MOUSE_ClearButton(WHEELUP_MOUSE);
1540 MOUSE_ClearButton(LEFT_MOUSE);
1541 event.at0 = kMenuEventUp;
1542 }
1543 else if (MOUSE_GetButtons()&WHEELDOWN_MOUSE)
1544 {
1545 MOUSE_ClearButton(WHEELDOWN_MOUSE);
1546 MOUSE_ClearButton(LEFT_MOUSE);
1547 event.at0 = kMenuEventDown;
1548 }
1549 return event.at0 != kMenuEventNone;
1550 }
1551
CGameMenuItemSliderFloat()1552 CGameMenuItemSliderFloat::CGameMenuItemSliderFloat()
1553 {
1554 m_pzText = NULL;
1555 m_nFont = -1;
1556 m_nX = 0;
1557 m_nY = 0;
1558 fValue = 0;
1559 fRangeLow = 0;
1560 fStep = 0;
1561 pCallback = NULL;
1562 pValue = NULL;
1563 nSliderTile = 2204;
1564 nCursorTile = 2028;
1565 nShowValue = kMenuSliderNone;
1566 }
1567
CGameMenuItemSliderFloat(const char * _pzText,int _nFont,int _nX,int _nY,int _nWidth,float _fValue,float _fRangeLow,float _fRangeHigh,float _fStep,void (* _pCallback)(CGameMenuItemSliderFloat *),int _nSliderTile,int _nCursorTile,int _nShowValue)1568 CGameMenuItemSliderFloat::CGameMenuItemSliderFloat(const char *_pzText, int _nFont, int _nX, int _nY, int _nWidth, float _fValue, float _fRangeLow, float _fRangeHigh, float _fStep, void(*_pCallback)(CGameMenuItemSliderFloat *), int _nSliderTile, int _nCursorTile, int _nShowValue)
1569 {
1570 m_pzText = _pzText;
1571 m_nFont = _nFont;
1572 m_nX = _nX;
1573 m_nY = _nY;
1574 m_nWidth = _nWidth;
1575 fRangeLow = _fRangeLow;
1576 fRangeHigh = _fRangeHigh;
1577 fStep = _fStep;
1578 fValue = ClipRangeF(_fValue, fRangeLow, fRangeHigh);
1579 pCallback = _pCallback;
1580 nSliderTile = 2204;
1581 nCursorTile = 2028;
1582 if (_nSliderTile >= 0)
1583 nSliderTile = _nSliderTile;
1584 if (_nCursorTile >= 0)
1585 nCursorTile = _nCursorTile;
1586 nShowValue = _nShowValue;
1587 }
1588
CGameMenuItemSliderFloat(const char * _pzText,int _nFont,int _nX,int _nY,int _nWidth,float * pnValue,float _fRangeLow,float _fRangeHigh,float _fStep,void (* _pCallback)(CGameMenuItemSliderFloat *),int _nSliderTile,int _nCursorTile,int _nShowValue)1589 CGameMenuItemSliderFloat::CGameMenuItemSliderFloat(const char *_pzText, int _nFont, int _nX, int _nY, int _nWidth, float *pnValue, float _fRangeLow, float _fRangeHigh, float _fStep, void(*_pCallback)(CGameMenuItemSliderFloat *), int _nSliderTile, int _nCursorTile, int _nShowValue)
1590 {
1591 m_pzText = _pzText;
1592 m_nFont = _nFont;
1593 m_nX = _nX;
1594 m_nY = _nY;
1595 m_nWidth = _nWidth;
1596 fRangeLow = _fRangeLow;
1597 fRangeHigh = _fRangeHigh;
1598 fStep = _fStep;
1599 dassert(pnValue != NULL);
1600 pValue = pnValue;
1601 fValue = ClipRangeF(*pnValue, fRangeLow, fRangeHigh);
1602 pCallback = _pCallback;
1603 nSliderTile = 2204;
1604 nCursorTile = 2028;
1605 if (_nSliderTile >= 0)
1606 nSliderTile = _nSliderTile;
1607 if (_nCursorTile >= 0)
1608 nCursorTile = _nCursorTile;
1609 nShowValue = _nShowValue;
1610 }
1611
Draw(void)1612 void CGameMenuItemSliderFloat::Draw(void)
1613 {
1614 char buffer[16];
1615 int height;
1616
1617 fValue = pValue ? *pValue : fValue;
1618 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
1619 int shade = bEnable ? 32 : 48;
1620 int shade2 = bEnable ? 0 : 16;
1621 int pal = bEnable ? 0 : 5;
1622 if (pMenu->IsFocusItem(this))
1623 shade = 32-((int)totalclock&63);
1624 if (m_pzText)
1625 gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
1626 int sliderX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x/2;
1627 rotatesprite(sliderX<<16, (m_nY+height/2)<<16, 65536, 0, nSliderTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
1628 float fRange = fRangeHigh - fRangeLow;
1629 dassert(fRange > 0);
1630 float value = fValue - fRangeLow;
1631 int width = tilesiz[nSliderTile].x-8;
1632 int cursorX = sliderX + (int)(ksgnf(fStep)*(value * width / fRange - width / 2));
1633 rotatesprite(cursorX<<16, (m_nY+height/2)<<16, 65536, 0, nCursorTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
1634
1635 buffer[0] = 0;
1636 switch (nShowValue)
1637 {
1638 case kMenuSliderNone:
1639 break;
1640 case kMenuSliderValue:
1641 snprintf(buffer, 16, "%.3f ", fValue);
1642 break;
1643 case kMenuSliderPercent:
1644 snprintf(buffer, 16, "%.3f%% ", value*100.f/fRange);
1645 break;
1646 }
1647 int valueWidth;
1648 gMenuTextMgr.GetFontInfo(m_nFont, buffer, &valueWidth, NULL);
1649 int valueX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x-valueWidth;
1650 gMenuTextMgr.DrawText(buffer, m_nFont, valueX, m_nY, 32, 0, false);
1651
1652 int mx = m_nX;
1653 int my = m_nY;
1654 int mw = m_nWidth;
1655 int mh = height;
1656 if (height < tilesiz[nSliderTile].y)
1657 {
1658 my -= (tilesiz[nSliderTile].y-height)/2;
1659 height = tilesiz[nSliderTile].y;
1660 }
1661 mx <<= 16;
1662 my <<= 16;
1663 mw <<= 16;
1664 mh <<= 16;
1665
1666 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
1667 {
1668 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
1669 {
1670 pMenu->SetFocusItem(this);
1671 }
1672
1673 if (!gGameMenuMgr.m_mousecaught && (g_mouseClickState == MOUSE_PRESSED || g_mouseClickState == MOUSE_HELD))
1674 {
1675 pMenu->SetFocusItem(this);
1676
1677 int sliderx = m_nX+m_nWidth-1-tilesiz[nSliderTile].x;
1678 int sliderwidth = tilesiz[nSliderTile].x;
1679 int regionwidth = sliderwidth-8;
1680 int regionx = sliderx+(sliderwidth-regionwidth)/2;
1681 sliderx <<= 16;
1682 sliderwidth <<= 16;
1683 regionwidth <<= 16;
1684 regionx <<= 16;
1685
1686 // region between the x-midline of the slidepoint at the extremes slides proportionally
1687 if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, regionx, my, regionwidth, mh))
1688 {
1689 int dx = (gGameMenuMgr.m_mousepos.x - (regionx+regionwidth/2))*ksgnf(fStep);
1690 fValue = fRangeLow + (dx+regionwidth/2) * fRange / regionwidth;
1691 fValue = ClipRangeF(fValue, fRangeLow, fRangeHigh);
1692 if (pCallback)
1693 pCallback(this);
1694 gGameMenuMgr.m_mousecaught = 1;
1695 }
1696 // region outside the x-midlines clamps to the extremes
1697 else if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, sliderx, my, sliderwidth, mh))
1698 {
1699 if ((gGameMenuMgr.m_mousepos.x-(regionx+regionwidth/2))*ksgnf(fStep) > 0)
1700 fValue = fRangeHigh;
1701 else
1702 fValue = fRangeLow;
1703 if (pCallback)
1704 pCallback(this);
1705 gGameMenuMgr.m_mousecaught = 1;
1706 }
1707 }
1708 }
1709 }
1710
Event(CGameMenuEvent & event)1711 bool CGameMenuItemSliderFloat::Event(CGameMenuEvent &event)
1712 {
1713 fValue = pValue ? *pValue : fValue;
1714 switch (event.at0)
1715 {
1716 case kMenuEventUp:
1717 pMenu->FocusPrevItem();
1718 return false;
1719 case kMenuEventDown:
1720 pMenu->FocusNextItem();
1721 return false;
1722 case kMenuEventLeft:
1723 if (fStep > 0)
1724 fValue -= fStep;
1725 else
1726 fValue += fStep;
1727 fValue = ClipRangeF(fValue, fRangeLow, fRangeHigh);
1728 if (pCallback)
1729 pCallback(this);
1730 return false;
1731 case kMenuEventRight:
1732 if (fStep >= 0)
1733 fValue += fStep;
1734 else
1735 fValue -= fStep;
1736 fValue = ClipRangeF(fValue, fRangeLow, fRangeHigh);
1737 if (pCallback)
1738 pCallback(this);
1739 return false;
1740 case kMenuEventEnter:
1741 if (pCallback)
1742 pCallback(this);
1743 return false;
1744 }
1745 return CGameMenuItem::Event(event);
1746 }
1747
CGameMenuItemZEdit()1748 CGameMenuItemZEdit::CGameMenuItemZEdit()
1749 {
1750 m_pzText = NULL;
1751 m_nFont = -1;
1752 m_nX = 0;
1753 m_nY = 0;
1754 at20 = NULL;
1755 at24 = 0;
1756 at32 = 0;
1757 at2c = 0;
1758 at30 = 0;
1759 at28 = 0;
1760 at31 = 1;
1761 }
1762
CGameMenuItemZEdit(const char * a1,int a2,int a3,int a4,int a5,char * a6,int a7,char a8,void (* a9)(CGameMenuItemZEdit *,CGameMenuEvent *),int a10)1763 CGameMenuItemZEdit::CGameMenuItemZEdit(const char *a1, int a2, int a3, int a4, int a5, char *a6, int a7, char a8, void(*a9)(CGameMenuItemZEdit *, CGameMenuEvent *), int a10)
1764 {
1765 at30 = 0;
1766 at31 = 1;
1767 m_pzText = a1;
1768 m_nFont = a2;
1769 m_nX = a3;
1770 m_nY = a4;
1771 m_nWidth = a5;
1772 at20 = a6;
1773 at24 = a7;
1774 at32 = a8;
1775 at2c = a9;
1776 at28 = a10;
1777 }
1778
AddChar(char ch)1779 void CGameMenuItemZEdit::AddChar(char ch)
1780 {
1781 int i = strlen(at20);
1782 if (i + 1 < at24)
1783 {
1784 at20[i] = ch;
1785 at20[i + 1] = 0;
1786 }
1787 }
1788
BackChar(void)1789 void CGameMenuItemZEdit::BackChar(void)
1790 {
1791 int i = strlen(at20);
1792 if (i > 0)
1793 at20[i - 1] = 0;
1794 }
1795
Draw(void)1796 void CGameMenuItemZEdit::Draw(void)
1797 {
1798 int height, width, textWidth = 0;
1799 gMenuTextMgr.GetFontInfo(m_nFont, NULL, &width, &height);
1800 if (at20)
1801 gMenuTextMgr.GetFontInfo(m_nFont, at20, &textWidth, NULL);
1802 int shade = bEnable ? 32 : 48;
1803 int pal = bEnable ? 0 : 5;
1804 if (pMenu->IsFocusItem(this))
1805 shade = 32-((int)totalclock&63);
1806 if (at30)
1807 shade = -128;
1808 if (m_pzText)
1809 gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
1810 int x = m_nX+m_nWidth-1-textWidth;//(at24+1)*width;
1811 if (at20 && *at20)
1812 {
1813 int width;
1814 gMenuTextMgr.GetFontInfo(m_nFont, at20, &width, NULL);
1815 int shade2;
1816 if (at32)
1817 {
1818 if (at30)
1819 shade2 = -128;
1820 else
1821 shade2 = shade;
1822 }
1823 else
1824 {
1825 if (at30)
1826 shade2 = shade;
1827 else
1828 shade2 = 32;
1829 }
1830 gMenuTextMgr.DrawText(at20, m_nFont, x, m_nY, shade2, pal, false);
1831 x += width;
1832 }
1833 if (at30 && ((int)totalclock & 32))
1834 gMenuTextMgr.DrawText("_", m_nFont, x, m_nY, shade, 0, false);
1835
1836 int mx = m_nX<<16;
1837 int my = m_nY<<16;
1838 int mw = m_nWidth<<16;
1839 int mh = height<<16;
1840
1841 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
1842 {
1843 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
1844 {
1845 pMenu->SetFocusItem(this);
1846 }
1847
1848 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
1849 {
1850 pMenu->SetFocusItem(this);
1851
1852 CGameMenuEvent event = { kMenuEventEnter, 0 };
1853
1854 gGameMenuMgr.m_mousecaught = 1;
1855
1856 if (Event(event))
1857 gGameMenuMgr.PostPop();
1858 }
1859 }
1860 }
1861
Event(CGameMenuEvent & event)1862 bool CGameMenuItemZEdit::Event(CGameMenuEvent &event)
1863 {
1864 static char buffer[256];
1865 // Hack
1866 if (event.at2 == sc_kpad_2 || event.at2 == sc_kpad_4 || event.at2 == sc_kpad_6 || event.at2 == sc_kpad_8)
1867 event.at0 = kMenuEventKey;
1868 switch (event.at0)
1869 {
1870 case kMenuEventEscape:
1871 if (at30)
1872 {
1873 strncpy(at20, buffer, at24);
1874 at20[at24-1] = 0;
1875 at30 = 0;
1876 return false;
1877 }
1878 return true;
1879 case kMenuEventEnter:
1880 if (!at31)
1881 {
1882 if (at2c)
1883 at2c(this, &event);
1884 return false;
1885 }
1886 if (at30)
1887 {
1888 if (at2c)
1889 at2c(this, &event);
1890 at30 = 0;
1891 return false;
1892 }
1893 strncpy(buffer, at20, at24);
1894 buffer[at24-1] = 0;
1895 at30 = 1;
1896 return false;
1897 case kMenuEventBackSpace:
1898 if (at30)
1899 BackChar();
1900 return false;
1901 case kMenuEventKey:
1902 case kMenuEventSpace:
1903 {
1904 char key;
1905 if (event.at2 < 128)
1906 {
1907 if (keystatus[sc_LeftShift] || keystatus[sc_RightShift])
1908 key = g_keyAsciiTableShift[event.at2];
1909 else
1910 key = g_keyAsciiTable[event.at2];
1911 if (at30 && (isalnum(key) || ispunct(key) || isspace(key)))
1912 {
1913 AddChar(key);
1914 return false;
1915 }
1916 }
1917 return CGameMenuItem::Event(event);
1918 }
1919 case kMenuEventUp:
1920 if (at30)
1921 return false;
1922 return CGameMenuItem::Event(event);
1923 case kMenuEventDown:
1924 if (at30)
1925 return false;
1926 return CGameMenuItem::Event(event);
1927 }
1928 return CGameMenuItem::Event(event);
1929 }
1930
CGameMenuItemZEditBitmap()1931 CGameMenuItemZEditBitmap::CGameMenuItemZEditBitmap()
1932 {
1933 m_pzText = NULL;
1934 m_nFont = -1;
1935 m_nX = 0;
1936 m_nY = 0;
1937 at20 = NULL;
1938 at24 = 0;
1939 at36 = 0;
1940 at30 = NULL;
1941 at2c = NULL;
1942 bScan = 0;
1943 at28 = 0;
1944 at37 = 0;
1945 at35 = 1;
1946 }
1947
CGameMenuItemZEditBitmap(char * a1,int a2,int a3,int a4,int a5,char * a6,int a7,char a8,void (* a9)(CGameMenuItemZEditBitmap *,CGameMenuEvent *),int a10)1948 CGameMenuItemZEditBitmap::CGameMenuItemZEditBitmap(char *a1, int a2, int a3, int a4, int a5, char *a6, int a7, char a8, void(*a9)(CGameMenuItemZEditBitmap *, CGameMenuEvent *), int a10)
1949 {
1950 at2c = NULL;
1951 bScan = 0;
1952 at35 = 1;
1953 at37 = 0;
1954 m_pzText = a1;
1955 m_nFont = a2;
1956 m_nX = a3;
1957 m_nY = a4;
1958 m_nWidth = a5;
1959 at20 = a6;
1960 at24 = a7;
1961 at36 = a8;
1962 at30 = a9;
1963 at28 = a10;
1964 }
1965
AddChar(char ch)1966 void CGameMenuItemZEditBitmap::AddChar(char ch)
1967 {
1968 int i = strlen(at20);
1969 if (i + 1 < at24)
1970 {
1971 at20[i] = ch;
1972 at20[i + 1] = 0;
1973 }
1974 }
1975
BackChar(void)1976 void CGameMenuItemZEditBitmap::BackChar(void)
1977 {
1978 int i = strlen(at20);
1979 if (i > 0)
1980 at20[i - 1] = 0;
1981 }
1982
Draw(void)1983 void CGameMenuItemZEditBitmap::Draw(void)
1984 {
1985 int height, width;
1986 gMenuTextMgr.GetFontInfo(m_nFont, NULL, &width, &height);
1987 int shade = bEnable ? 32 : 48;
1988 int pal = bEnable ? 0 : 5;
1989 if (pMenu->IsFocusItem(this))
1990 {
1991 shade = 32-((int)totalclock&63);
1992 char buffer[32];
1993 snprintf(buffer, sizeof(buffer), "DIFFICULTY: %s", zDiffStrings[restoreGameDifficulty[at28]]);
1994 gMenuTextMgr.DrawText(buffer, m_nFont, 20, 50, 32, 0, true);
1995 }
1996 at2c->at24 = -1;
1997 if (bScan)
1998 shade = -128;
1999 if (m_pzText)
2000 gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
2001 int x = m_nX+m_nWidth-1-(at24+1)*width;
2002 if (at20 && *at20)
2003 {
2004 int width;
2005 gMenuTextMgr.GetFontInfo(m_nFont, at20, &width, NULL);
2006 int shade2;
2007 if (at36)
2008 {
2009 if (bScan)
2010 shade2 = -128;
2011 else
2012 shade2 = shade;
2013 }
2014 else
2015 {
2016 if (bScan)
2017 shade2 = shade;
2018 else
2019 shade2 = 32;
2020 }
2021 gMenuTextMgr.DrawText(at20, m_nFont, x, m_nY, shade2, 0, false);
2022 x += width;
2023 }
2024 if (bScan && ((int)totalclock & 32))
2025 gMenuTextMgr.DrawText("_", m_nFont, x, m_nY, shade, pal, false);
2026
2027 int mx = m_nX<<16;
2028 int my = m_nY<<16;
2029 int mw = m_nWidth<<16;
2030 int mh = height<<16;
2031
2032 if (!gGameMenuMgr.m_bScanning && bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
2033 {
2034 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
2035 {
2036 pMenu->SetFocusItem(this);
2037 }
2038
2039 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
2040 {
2041 pMenu->SetFocusItem(this);
2042
2043 CGameMenuEvent event = { kMenuEventEnter, 0 };
2044
2045 gGameMenuMgr.m_mousecaught = 1;
2046
2047 if (Event(event))
2048 gGameMenuMgr.PostPop();
2049 }
2050 }
2051 }
2052
Event(CGameMenuEvent & event)2053 bool CGameMenuItemZEditBitmap::Event(CGameMenuEvent &event)
2054 {
2055 static char buffer[256];
2056 // Hack
2057 if (event.at2 == sc_kpad_2 || event.at2 == sc_kpad_4 || event.at2 == sc_kpad_6 || event.at2 == sc_kpad_8)
2058 event.at0 = kMenuEventKey;
2059 switch (event.at0)
2060 {
2061 case kMenuEventEscape:
2062 if (bScan)
2063 {
2064 strncpy(at20, buffer, at24);
2065 at20[at24-1] = 0;
2066 bScan = 0;
2067 gGameMenuMgr.m_bScanning = false;
2068 gSaveGameActive = false;
2069 return false;
2070 }
2071 gSaveGameActive = true;
2072 return true;
2073 case kMenuEventEnter:
2074 if (!at35 || bScan)
2075 {
2076 if (at30)
2077 at30(this, &event);
2078 if (bScan)
2079 {
2080 bScan = 0;
2081 gGameMenuMgr.m_bScanning = false;
2082 }
2083 gSaveGameActive = false;
2084 KB_ClearKeyDown(sc_Enter);
2085 KB_ClearKeyDown(sc_kpad_Enter);
2086 return false;
2087 }
2088 strncpy(buffer, at20, at24);
2089 if (at37)
2090 at20[0] = 0;
2091 buffer[at24-1] = 0;
2092 bScan = 1;
2093 gGameMenuMgr.m_bScanning = true;
2094 return false;
2095 case kMenuEventBackSpace:
2096 if (bScan)
2097 BackChar();
2098 return false;
2099 case kMenuEventKey:
2100 case kMenuEventSpace:
2101 {
2102 char key;
2103 if (bScan && event.at2 < 128)
2104 {
2105 if (keystatus[sc_LeftShift] || keystatus[sc_RightShift])
2106 key = g_keyAsciiTableShift[event.at2];
2107 else
2108 key = g_keyAsciiTable[event.at2];
2109 if (at30 && (isalnum(key) || ispunct(key) || isspace(key)))
2110 {
2111 AddChar(key);
2112 return false;
2113 }
2114 }
2115 return CGameMenuItem::Event(event);
2116 }
2117 case kMenuEventUp:
2118 if (bScan)
2119 return false;
2120 return CGameMenuItem::Event(event);
2121 case kMenuEventDown:
2122 if (bScan)
2123 return false;
2124 return CGameMenuItem::Event(event);
2125 }
2126 return CGameMenuItem::Event(event);
2127 }
2128
CGameMenuItemQAV()2129 CGameMenuItemQAV::CGameMenuItemQAV()
2130 {
2131 at20 = NULL;
2132 at24 = NULL;
2133 at28 = 0;
2134 bEnable = 0;
2135 }
2136
CGameMenuItemQAV(const char * a1,int a2,int a3,int a4,const char * a5,bool widescreen,bool clearbackground)2137 CGameMenuItemQAV::CGameMenuItemQAV(const char *a1, int a2, int a3, int a4, const char *a5, bool widescreen, bool clearbackground)
2138 {
2139 m_nWidth = 0;
2140 m_pzText = a1;
2141 m_nFont = a2;
2142 m_nY = a4;
2143 at20 = a5;
2144 m_nX = a3;
2145 bEnable = 0;
2146 bWideScreen = widescreen;
2147 bClearBackground = clearbackground;
2148 }
2149
Draw(void)2150 void CGameMenuItemQAV::Draw(void)
2151 {
2152 if (bClearBackground)
2153 videoClearScreen(0);
2154 if (at24)
2155 {
2156 ClockTicks backFC = gFrameClock;
2157 gFrameClock = totalclock;
2158 int nTicks = (int)totalclock - at30;
2159 at30 = (int)totalclock;
2160 at2c -= nTicks;
2161 if (at2c <= 0 || at2c > at28->at10)
2162 {
2163 at2c = at28->at10;
2164 }
2165 at28->Play(at28->at10 - at2c - nTicks, at28->at10 - at2c, -1, NULL);
2166 int wx1, wy1, wx2, wy2;
2167 wx1 = windowxy1.x;
2168 wy1 = windowxy1.y;
2169 wx2 = windowxy2.x;
2170 wy2 = windowxy2.y;
2171 windowxy1.x = 0;
2172 windowxy1.y = 0;
2173 windowxy2.x = xdim-1;
2174 windowxy2.y = ydim-1;
2175 if (bWideScreen)
2176 {
2177 int xdim43 = scale(ydim, 4, 3);
2178 int nCount = (xdim+xdim43-1)/xdim43;
2179 int backX = at28->x;
2180 for (int i = 0; i < nCount; i++)
2181 {
2182 at28->Draw(at28->at10 - at2c, 10+kQavOrientationLeft, 0, 0);
2183 at28->x += 320;
2184 }
2185 at28->x = backX;
2186 }
2187 else
2188 at28->Draw(at28->at10 - at2c, 10, 0, 0);
2189
2190 windowxy1.x = wx1;
2191 windowxy1.y = wy1;
2192 windowxy2.x = wx2;
2193 windowxy2.y = wy2;
2194 gFrameClock = backFC;
2195 }
2196
2197 if (bEnable && !gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED)
2198 {
2199 pMenu->SetFocusItem(this);
2200
2201 CGameMenuEvent event = { kMenuEventEnter, 0 };
2202
2203 gGameMenuMgr.m_mousecaught = 1;
2204
2205 if (Event(event))
2206 gGameMenuMgr.PostPop();
2207 }
2208 }
2209
Event(CGameMenuEvent & event)2210 bool CGameMenuItemQAV::Event(CGameMenuEvent &event)
2211 {
2212 switch (event.at0)
2213 {
2214 case kMenuEventLeft:
2215 case kMenuEventBackSpace:
2216 pMenu->FocusPrevItem();
2217 return false;
2218 case kMenuEventRight:
2219 case kMenuEventEnter:
2220 case kMenuEventSpace:
2221 pMenu->FocusNextItem();
2222 return false;
2223 case kMenuEventInit:
2224 if (at20)
2225 {
2226 if (!at28)
2227 {
2228 at24 = gSysRes.Lookup(at20, "QAV");
2229 if (!at24)
2230 ThrowError("Could not load QAV %s\n", at20);
2231 at28 = (QAV*)gSysRes.Lock(at24);
2232 at28->nSprite = -1;
2233 at28->x = m_nX;
2234 at28->y = m_nY;
2235 at28->Preload();
2236 at2c = at28->at10;
2237 at30 = (int)totalclock;
2238 return false;
2239 }
2240 gSysRes.Lock(at24);
2241 }
2242 return false;
2243 case kMenuEventDeInit:
2244 if (at20 && at28)
2245 {
2246 gSysRes.Unlock(at24);
2247 if (at24->lockCount == 0)
2248 at28 = NULL;
2249 }
2250 return false;
2251 }
2252 return CGameMenuItem::Event(event);
2253 }
2254
Reset(void)2255 void CGameMenuItemQAV::Reset(void)
2256 {
2257 at2c = at28->at10;
2258 at30 = (int)totalclock;
2259 }
2260
CGameMenuItemZCycleSelect()2261 CGameMenuItemZCycleSelect::CGameMenuItemZCycleSelect()
2262 {
2263 m_pzText = NULL;
2264 m_nFont = 3;
2265 m_nX = 0;
2266 m_nY = 0;
2267 m_nRows = 0;
2268 m_nTopDelta = 0;
2269 m_nFocus = 0;
2270 m_nItems = 0;
2271 m_pzStrings = NULL;
2272 m_pReturn = NULL;
2273 }
2274
CGameMenuItemZCycleSelect(const char * pzText,int nFont,int nX,int nY,int nWidth,int nRows,int nItems,const char ** pzStrings,int * pReturn,void (* pCallback)(CGameMenuItemZCycleSelect *))2275 CGameMenuItemZCycleSelect::CGameMenuItemZCycleSelect(const char *pzText, int nFont, int nX, int nY, int nWidth, int nRows, int nItems, const char **pzStrings, int *pReturn, void(*pCallback)(CGameMenuItemZCycleSelect *))
2276 {
2277 m_nTopDelta = 0;
2278 m_nFocus = 0;
2279 m_pzText = pzText;
2280 m_nFont = nFont;
2281 m_nX = nX;
2282 m_nY = nY;
2283 m_nWidth = nWidth;
2284 m_nRows = nRows;
2285 m_pCallback = pCallback;
2286 m_nItems = nItems;
2287 m_pzStrings = pzStrings;
2288 m_pReturn = pReturn;
2289 }
2290
Draw(void)2291 void CGameMenuItemZCycleSelect::Draw(void)
2292 {
2293 int height;
2294 int shade;
2295 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
2296 int y = m_nY;
2297 int k = m_nFocus - m_nTopDelta;
2298 int nNewFocus = m_nFocus;
2299 bool bClick = false;
2300 for (int i = 0; i < m_nRows; i++, y += height, k++)
2301 {
2302 if (k == m_nFocus)
2303 {
2304 shade = 32;
2305 if (pMenu->IsFocusItem(this))
2306 shade = 32-((int)totalclock&63);
2307 viewDrawText(3, m_pzStrings[k], m_nX, y, shade, 0, 0, false);
2308 }
2309 else
2310 {
2311 viewDrawText(3, m_pzStrings[k], m_nX, y, 24, 0, 0, false);
2312 }
2313 int mx = m_nX<<16;
2314 int my = y<<16;
2315 int mw = m_nWidth<<16;
2316 int mh = height<<16;
2317 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
2318 {
2319 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
2320 {
2321 nNewFocus = k;
2322 }
2323
2324 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
2325 {
2326 nNewFocus = k;
2327 bClick = true;
2328 }
2329 }
2330 }
2331 m_nTopDelta += nNewFocus-m_nFocus;
2332 m_nFocus = nNewFocus;
2333 if (bClick)
2334 {
2335 CGameMenuEvent event = { kMenuEventEnter, 0 };
2336
2337 gGameMenuMgr.m_mousecaught = 1;
2338
2339 if (Event(event))
2340 gGameMenuMgr.PostPop();
2341 }
2342 }
2343
Event(CGameMenuEvent & event)2344 bool CGameMenuItemZCycleSelect::Event(CGameMenuEvent &event)
2345 {
2346 switch (event.at0)
2347 {
2348 case kMenuEventUp:
2349 if (event.at2 == sc_Tab || m_nFocus == 0)
2350 {
2351 pMenu->FocusPrevItem();
2352 return false;
2353 }
2354 m_nFocus--;
2355 if (m_nTopDelta > 0)
2356 m_nTopDelta--;
2357 return false;
2358 case kMenuEventDown:
2359 if (event.at2 == sc_Tab || m_nFocus == m_nItems-1)
2360 {
2361 pMenu->FocusNextItem();
2362 return false;
2363 }
2364 m_nFocus++;
2365 if (m_nTopDelta+1 < m_nRows)
2366 m_nTopDelta++;
2367 return false;
2368 case kMenuEventEnter:
2369 if (m_pCallback)
2370 m_pCallback(this);
2371 *m_pReturn = m_nFocus;
2372 return true;
2373 case kMenuEventScrollUp:
2374 if (m_nFocus-m_nTopDelta > 0)
2375 {
2376 m_nTopDelta++;
2377 if (m_nTopDelta>0)
2378 {
2379 m_nFocus--;
2380 m_nTopDelta--;
2381 }
2382 }
2383 return false;
2384 case kMenuEventScrollDown:
2385 if (m_nFocus-m_nTopDelta+m_nRows < m_nItems)
2386 {
2387 m_nTopDelta--;
2388 if (m_nTopDelta+1 < m_nRows)
2389 {
2390 m_nFocus++;
2391 m_nTopDelta++;
2392 }
2393 }
2394 return false;
2395 }
2396 return CGameMenuItem::Event(event);
2397 }
2398
MouseEvent(CGameMenuEvent & event)2399 bool CGameMenuItemZCycleSelect::MouseEvent(CGameMenuEvent &event)
2400 {
2401 event.at0 = kMenuEventNone;
2402 if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELUP_MOUSE))
2403 {
2404 gGameMenuMgr.m_mouselastactivity = (int)totalclock;
2405 MOUSE_ClearButton(WHEELUP_MOUSE);
2406 event.at0 = kMenuEventScrollUp;
2407 }
2408 else if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELDOWN_MOUSE))
2409 {
2410 gGameMenuMgr.m_mouselastactivity = (int)totalclock;
2411 MOUSE_ClearButton(WHEELDOWN_MOUSE);
2412 event.at0 = kMenuEventScrollDown;
2413 }
2414 else
2415 return CGameMenuItem::MouseEvent(event);
2416 return event.at0 != kMenuEventNone;
2417 }
2418
CGameMenuItemZCycle()2419 CGameMenuItemZCycle::CGameMenuItemZCycle()
2420 {
2421 m_pzText = NULL;
2422 m_nFocus = 0;
2423 m_nItems = 0;
2424 m_pCallback = NULL;
2425 m_pCallbackSelect = NULL;
2426 m_pMenuSelect = NULL;
2427 m_pItemSelectTitle = NULL;
2428 m_pItemSelect = NULL;
2429 m_nMenuSelectReturn = -1;
2430 }
2431
CGameMenuItemZCycle(const char * a1,int a2,int a3,int a4,int a5,int a6,void (* a7)(CGameMenuItemZCycle *),const char ** a8,int a9,int a10,bool bMenu,void (* pCallbackSelect)(CGameMenuItemZCycleSelect *))2432 CGameMenuItemZCycle::CGameMenuItemZCycle(const char *a1, int a2, int a3, int a4, int a5, int a6, void(*a7)(CGameMenuItemZCycle *), const char **a8, int a9, int a10, bool bMenu, void(*pCallbackSelect)(CGameMenuItemZCycleSelect*))
2433 {
2434 m_pzText = a1;
2435 m_nFont = a2;
2436 m_nX = a3;
2437 m_nY = a4;
2438 m_nFocus = 0;
2439 m_nWidth = a5;
2440 m_nAlign = a6;
2441 m_pCallback = a7;
2442 m_pCallbackSelect = pCallbackSelect;
2443 m_nItems = 0;
2444 m_bMenu = bMenu;
2445 m_pMenuSelect = NULL;
2446 m_pItemSelectTitle = NULL;
2447 m_pItemSelect = NULL;
2448 m_nMenuSelectReturn = -1;
2449 SetTextArray(a8, a9, a10);
2450 }
2451
~CGameMenuItemZCycle()2452 CGameMenuItemZCycle::~CGameMenuItemZCycle()
2453 {
2454 m_pzText = NULL;
2455 m_nFocus = 0;
2456 m_nItems = 0;
2457 m_pCallback = NULL;
2458 m_pCallbackSelect = NULL;
2459 m_pMenuSelect = NULL;
2460 m_pItemSelectTitle = NULL;
2461 m_pItemSelect = NULL;
2462 m_nMenuSelectReturn = -1;
2463 memset(m_pzStrings, 0, sizeof(m_pzStrings));
2464 }
2465
Draw(void)2466 void CGameMenuItemZCycle::Draw(void)
2467 {
2468 int width = 0, height = 0;
2469 int shade = bEnable ? 32 : 48;
2470 int pal = bEnable ? 0 : 5;
2471 if (pMenu->IsFocusItem(this))
2472 shade = 32-((int)totalclock&63);
2473 int x = m_nX;
2474 int y = m_nY;
2475
2476 if (m_nMenuSelectReturn != -1)
2477 {
2478 m_nFocus = m_nMenuSelectReturn;
2479 if (m_pCallback)
2480 m_pCallback(this);
2481 m_nMenuSelectReturn = -1;
2482 }
2483
2484 if (m_pzText)
2485 {
2486 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, &height);
2487 switch (m_nAlign)
2488 {
2489 case 1:
2490 x = m_nX+m_nWidth/2-width/2;
2491 break;
2492 case 2:
2493 x = m_nX+m_nWidth-1-width;
2494 break;
2495 case 0:
2496 default:
2497 break;
2498 }
2499 gMenuTextMgr.DrawText(m_pzText, m_nFont, x, y, shade, pal, false);
2500 }
2501 const char *pzText;
2502 if (!m_nItems)
2503 pzText = "????";
2504 else
2505 pzText = m_pzStrings[m_nFocus];
2506 dassert(pzText != NULL);
2507 gMenuTextMgr.GetFontInfo(m_nFont, pzText, &width, NULL);
2508 gMenuTextMgr.DrawText(pzText, m_nFont, m_nX + m_nWidth - 1 - width, y, shade, pal, false);
2509 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, x<<16, y<<16, m_nWidth<<16, height<<16)))
2510 {
2511 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, x<<16, y<<16, m_nWidth<<16, height<<16)))
2512 {
2513 pMenu->SetFocusItem(this);
2514 }
2515
2516 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, x<<16, y<<16, m_nWidth<<16, height<<16))
2517 {
2518 pMenu->SetFocusItem(this);
2519
2520 CGameMenuEvent event = { kMenuEventEnter, 0 };
2521
2522 gGameMenuMgr.m_mousecaught = 1;
2523
2524 if (Event(event))
2525 gGameMenuMgr.PostPop();
2526 }
2527 }
2528 }
2529
Event(CGameMenuEvent & event)2530 bool CGameMenuItemZCycle::Event(CGameMenuEvent &event)
2531 {
2532 switch (event.at0)
2533 {
2534 case kMenuEventEnter:
2535 if (m_bMenu)
2536 {
2537 if (m_pMenuSelect)
2538 {
2539 delete m_pMenuSelect;
2540 m_pMenuSelect = NULL;
2541 }
2542 if (m_pItemSelectTitle)
2543 {
2544 delete m_pItemSelectTitle;
2545 m_pItemSelectTitle = NULL;
2546 }
2547 if (m_pItemSelect)
2548 {
2549 delete m_pItemSelect;
2550 m_pItemSelect = NULL;
2551 }
2552 m_pMenuSelect = new CGameMenu();
2553 dassert(m_pMenuSelect != NULL);
2554 strncpy(m_zTitle, m_pzText, kMaxTitleLength);
2555 int l = strlen(m_zTitle);
2556 if (l > 0 && m_zTitle[l-1] == ':')
2557 l--;
2558 m_zTitle[l] = 0;
2559 m_pItemSelectTitle = new CGameMenuItemTitle(m_zTitle, 1, 160, 20, 2038);
2560 dassert(m_pItemSelectTitle != NULL);
2561 m_pItemSelect = new CGameMenuItemZCycleSelect("", 3, 100, 40, 100, 16, m_nItems, m_pzStrings, &m_nMenuSelectReturn, m_pCallbackSelect);
2562 dassert(m_pItemSelect != NULL);
2563 m_pMenuSelect->Add(m_pItemSelectTitle, false);
2564 m_pMenuSelect->Add(m_pItemSelect, true);
2565 m_pMenuSelect->Add(&itemBloodQAV, false);
2566 gGameMenuMgr.Push(m_pMenuSelect, -1);
2567 return false;
2568 }
2569 fallthrough__;
2570 case kMenuEventRight:
2571 case kMenuEventSpace:
2572 Next();
2573 if (m_pCallback)
2574 m_pCallback(this);
2575 return false;
2576 case kMenuEventLeft:
2577 Prev();
2578 if (m_pCallback)
2579 m_pCallback(this);
2580 return false;
2581 case kMenuEventDeInit:
2582 if (m_pMenuSelect)
2583 {
2584 delete m_pMenuSelect;
2585 m_pMenuSelect = NULL;
2586 }
2587 if (m_pItemSelectTitle)
2588 {
2589 delete m_pItemSelectTitle;
2590 m_pItemSelectTitle = NULL;
2591 }
2592 if (m_pItemSelect)
2593 {
2594 delete m_pItemSelect;
2595 m_pItemSelect = NULL;
2596 }
2597 return false;
2598 }
2599 return CGameMenuItem::Event(event);
2600 }
2601
Add(const char * pItem,bool active)2602 void CGameMenuItemZCycle::Add(const char *pItem, bool active)
2603 {
2604 dassert(pItem != NULL);
2605 dassert(m_nItems < kMaxGameCycleItems);
2606 m_pzStrings[m_nItems] = pItem;
2607 if (active)
2608 m_nFocus = m_nItems;
2609 m_nItems++;
2610 }
2611
Next(void)2612 void CGameMenuItemZCycle::Next(void)
2613 {
2614 if (m_nItems > 0)
2615 {
2616 m_nFocus++;
2617 if (m_nFocus >= m_nItems)
2618 m_nFocus = 0;
2619 }
2620 }
2621
Prev(void)2622 void CGameMenuItemZCycle::Prev(void)
2623 {
2624 if (m_nItems > 0)
2625 {
2626 m_nFocus--;
2627 if (m_nFocus < 0)
2628 m_nFocus += m_nItems;
2629 }
2630 }
2631
Clear(void)2632 void CGameMenuItemZCycle::Clear(void)
2633 {
2634 m_nItems = m_nFocus = 0;
2635 memset(m_pzStrings, 0, sizeof(m_pzStrings));
2636 }
2637
SetTextArray(const char ** pTextArray,int nTextPtrCount,int nIndex)2638 void CGameMenuItemZCycle::SetTextArray(const char **pTextArray, int nTextPtrCount, int nIndex)
2639 {
2640 Clear();
2641 dassert(nTextPtrCount <= kMaxGameCycleItems);
2642 for (int i = 0; i < nTextPtrCount; i++)
2643 Add(pTextArray[i], false);
2644 SetTextIndex(nIndex);
2645 }
2646
SetTextIndex(int nIndex)2647 void CGameMenuItemZCycle::SetTextIndex(int nIndex)
2648 {
2649 m_nFocus = ClipRange(nIndex, 0, m_nItems);
2650 }
2651
CGameMenuItemYesNoQuit()2652 CGameMenuItemYesNoQuit::CGameMenuItemYesNoQuit()
2653 {
2654 m_pzText = NULL;
2655 m_nRestart = 0;
2656 }
2657
CGameMenuItemYesNoQuit(const char * a1,int a2,int a3,int a4,int a5,int a6,int a7)2658 CGameMenuItemYesNoQuit::CGameMenuItemYesNoQuit(const char *a1, int a2, int a3, int a4, int a5, int a6, int a7)
2659 {
2660 m_pzText = a1;
2661 m_nFont = a2;
2662 m_nX = a3;
2663 m_nY = a4;
2664 m_nWidth = a5;
2665 at20 = a6;
2666 m_nRestart = a7;
2667 }
2668
Draw(void)2669 void CGameMenuItemYesNoQuit::Draw(void)
2670 {
2671 if (!m_pzText) return;
2672 int shade = 32;
2673 if (pMenu->IsFocusItem(this))
2674 shade = 32-((int)totalclock&63);
2675 int width;
2676 int x = m_nX;
2677 switch (at20)
2678 {
2679 case 1:
2680 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
2681 x = m_nX+m_nWidth/2-width/2;
2682 break;
2683 case 2:
2684 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
2685 x = m_nX+m_nWidth-1-width;
2686 break;
2687 case 0:
2688 default:
2689 break;
2690 }
2691 gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, 0, true);
2692
2693 if (bEnable && !gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED)
2694 {
2695 pMenu->SetFocusItem(this);
2696
2697 CGameMenuEvent event = { kMenuEventEnter, 0 };
2698
2699 gGameMenuMgr.m_mousecaught = 1;
2700
2701 if (Event(event))
2702 gGameMenuMgr.PostPop();
2703 }
2704 }
2705
2706 extern void Restart(CGameMenuItemChain *pItem);
2707 extern void Quit(CGameMenuItemChain *pItem);
2708
Event(CGameMenuEvent & event)2709 bool CGameMenuItemYesNoQuit::Event(CGameMenuEvent &event)
2710 {
2711 switch (event.at0)
2712 {
2713 case kMenuEventKey:
2714 if (event.at2 == sc_Y)
2715 {
2716 if (m_nRestart)
2717 Restart(NULL);
2718 else
2719 Quit(NULL);
2720 }
2721 else if (event.at2 == sc_N)
2722 gGameMenuMgr.Pop();
2723 return false;
2724 case kMenuEventEnter:
2725 if (m_nRestart)
2726 Restart(NULL);
2727 else
2728 Quit(NULL);
2729 return false;
2730 }
2731 return CGameMenuItem::Event(event);
2732 }
2733
CGameMenuItemPicCycle()2734 CGameMenuItemPicCycle::CGameMenuItemPicCycle()
2735 {
2736 m_pzText = NULL;
2737 at24 = 0;
2738 m_nItems = 0;
2739 atb0 = 0;
2740 at2c = 0;
2741 atb4 = 0;
2742 }
2743
CGameMenuItemPicCycle(int a1,int a2,void (* a3)(CGameMenuItemPicCycle *),int * a4,int a5,int a6)2744 CGameMenuItemPicCycle::CGameMenuItemPicCycle(int a1, int a2, void(*a3)(CGameMenuItemPicCycle *), int *a4, int a5, int a6)
2745 {
2746 m_nWidth = 0;
2747 at24 = 0;
2748 m_nItems = 0;
2749 m_nX = a1;
2750 m_nY = a2;
2751 atb0 = a3;
2752 atb4 = 0;
2753 SetPicArray(a4, a5, a6);
2754 }
2755
Draw(void)2756 void CGameMenuItemPicCycle::Draw(void)
2757 {
2758 videoSetViewableArea(0, 0, xdim - 1, ydim - 1);
2759 if (atb4)
2760 rotatesprite(0, 0, 65536, 0, atb4, 0, 0, 82, 0, 0, xdim - 1, ydim - 1);
2761 if (at30[at24])
2762 rotatesprite(0, 0, 65536, 0, at30[at24], 0, 0, 82, 0, 0, xdim - 1, ydim - 1);
2763 }
2764
Event(CGameMenuEvent & event)2765 bool CGameMenuItemPicCycle::Event(CGameMenuEvent &event)
2766 {
2767 switch (event.at0)
2768 {
2769 case kMenuEventRight:
2770 case kMenuEventEnter:
2771 case kMenuEventSpace:
2772 Next();
2773 if (atb0)
2774 atb0(this);
2775 return false;
2776 case kMenuEventLeft:
2777 Prev();
2778 if (atb0)
2779 atb0(this);
2780 return false;
2781 }
2782 return CGameMenuItem::Event(event);
2783 }
2784
Add(int nItem,bool active)2785 void CGameMenuItemPicCycle::Add(int nItem, bool active)
2786 {
2787 dassert(m_nItems < kMaxPicCycleItems);
2788 at30[m_nItems] = nItem;
2789 if (active)
2790 at24 = m_nItems;
2791 m_nItems++;
2792 }
2793
Next(void)2794 void CGameMenuItemPicCycle::Next(void)
2795 {
2796 if (m_nItems > 0)
2797 {
2798 at24++;
2799 if (at24 >= m_nItems)
2800 at24 = 0;
2801 }
2802 }
2803
Prev(void)2804 void CGameMenuItemPicCycle::Prev(void)
2805 {
2806 if (m_nItems > 0)
2807 {
2808 at24--;
2809 if (at24 < 0)
2810 at24 += m_nItems;
2811 }
2812 }
2813
Clear(void)2814 void CGameMenuItemPicCycle::Clear(void)
2815 {
2816 m_nItems = at24 = 0;
2817 memset(at30, 0, sizeof(at30));
2818 at2c = 0;
2819 }
2820
SetPicArray(int * pArray,int nTileCount,int nIndex)2821 void CGameMenuItemPicCycle::SetPicArray(int *pArray, int nTileCount, int nIndex)
2822 {
2823 Clear();
2824 at2c = 0;
2825 dassert(nTileCount <= kMaxPicCycleItems);
2826 for (int i = 0; i < nTileCount; i++)
2827 Add(pArray[i], false);
2828 SetPicIndex(nIndex);
2829 }
2830
SetPicIndex(int nIndex)2831 void CGameMenuItemPicCycle::SetPicIndex(int nIndex)
2832 {
2833 at24 = ClipRange(nIndex, 0, m_nItems);
2834 }
2835
CGameMenuItemPassword()2836 CGameMenuItemPassword::CGameMenuItemPassword()
2837 {
2838 at37 = 0;
2839 m_pzText = NULL;
2840 at36 = 0;
2841 at32 = 0;
2842 at5b = 0;
2843 }
2844
CGameMenuItemPassword(const char * a1,int a2,int a3,int a4)2845 CGameMenuItemPassword::CGameMenuItemPassword(const char *a1, int a2, int a3, int a4)
2846 {
2847 at37 = 0;
2848 m_nWidth = 0;
2849 at36 = 0;
2850 at32 = 0;
2851 at5b = 0;
2852 m_pzText = a1;
2853 m_nFont = a2;
2854 m_nX = a3;
2855 m_nY = a4;
2856 }
2857
2858 const char *kCheckPasswordMsg = "ENTER PASSWORD: ";
2859 const char *kOldPasswordMsg = "ENTER OLD PASSWORD: ";
2860 const char *kNewPasswordMsg = "ENTER NEW PASSWORD: ";
2861 const char *kInvalidPasswordMsg = "INVALID PASSWORD.";
2862
Draw(void)2863 void CGameMenuItemPassword::Draw(void)
2864 {
2865 bool focus = pMenu->IsFocusItem(this);
2866 int shade = 32;
2867 int shadef = 32-((int)totalclock&63);
2868 int width;
2869 switch (at37)
2870 {
2871 case 1:
2872 case 2:
2873 case 3:
2874 switch (at37)
2875 {
2876 case 1:
2877 strcpy(at3b, kCheckPasswordMsg);
2878 break;
2879 case 2:
2880 strcpy(at3b, kOldPasswordMsg);
2881 break;
2882 case 3:
2883 strcpy(at3b, kNewPasswordMsg);
2884 break;
2885 }
2886 for (int i = 0; i < at32; i++)
2887 strcat(at3b, "*");
2888 strcat(at3b, "_");
2889 gMenuTextMgr.GetFontInfo(m_nFont, at3b, &width, NULL);
2890 gMenuTextMgr.DrawText(at3b, m_nFont, m_nX-width/2, m_nY+20, shadef, 0, false);
2891 shadef = 32;
2892 break;
2893 case 4:
2894 if (((int)totalclock - at5b) & 32)
2895 {
2896 gMenuTextMgr.GetFontInfo(m_nFont, kInvalidPasswordMsg, &width, NULL);
2897 gMenuTextMgr.DrawText(kInvalidPasswordMsg, m_nFont, m_nX - width / 2, m_nY + 20, shade, 0, false);
2898 }
2899 if (at5b && totalclock-at5b > 256)
2900 {
2901 at5b = 0;
2902 at37 = 0;
2903 }
2904 break;
2905 }
2906 gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
2907 gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX-width/2, m_nY, focus ? shadef : shade, 0, false);
2908 }
2909
Event(CGameMenuEvent & event)2910 bool CGameMenuItemPassword::Event(CGameMenuEvent &event)
2911 {
2912 switch (at37)
2913 {
2914 case 0:
2915 case 4:
2916 if (event.at0 == kMenuEventEnter)
2917 {
2918 at29[0] = 0;
2919 if (strcmp(at20, ""))
2920 at37 = 2;
2921 else
2922 at37 = 3;
2923 return false;
2924 }
2925 return CGameMenuItem::Event(event);
2926 case 1:
2927 case 2:
2928 case 3:
2929 switch (event.at0)
2930 {
2931 case kMenuEventEnter:
2932 switch (at37)
2933 {
2934 case 1:
2935 at36 = strcmp(at20,at29) == 0;
2936 if (at36)
2937 at37 = 0;
2938 else
2939 at37 = 4;
2940 if (!at36)
2941 {
2942 at5b = (int)totalclock;
2943 pMenu->FocusPrevItem();
2944 }
2945 else
2946 {
2947 at5f->at20 = 0;
2948 at5f->Draw();
2949 gbAdultContent = false;
2950 // NUKE-TODO:
2951 //CONFIG_WriteAdultMode();
2952 pMenu->FocusPrevItem();
2953 }
2954 return false;
2955 case 2:
2956 at36 = strcmp(at20,at29) == 0;
2957 if (at36)
2958 at37 = 0;
2959 else
2960 at37 = 4;
2961 if (at36)
2962 {
2963 strcpy(at20, "");
2964 strcpy(gzAdultPassword, "");
2965 // NUKE-TODO:
2966 //CONFIG_WriteAdultMode();
2967 at37 = 0;
2968 }
2969 else
2970 at5b = (int)totalclock;
2971 return false;
2972 case 3:
2973 strcpy(at20, at29);
2974 strcpy(at20, gzAdultPassword);
2975 strcpy(gzAdultPassword, "");
2976 // NUKE-TODO:
2977 //CONFIG_WriteAdultMode();
2978 at37 = 0;
2979 return false;
2980 }
2981 break;
2982 case kMenuEventEscape:
2983 at37 = 0;
2984 Draw();
2985 return false;
2986 case kMenuEventKey:
2987 if (at32 < 8)
2988 {
2989 char key = Btoupper(g_keyAsciiTable[event.at2]);
2990 if (isalnum(key) || ispunct(key) || isspace(key))
2991 {
2992 at29[at32++] = key;
2993 at29[at32] = 0;
2994 }
2995 }
2996 return false;
2997 case kMenuEventBackSpace:
2998 if (at32 > 0)
2999 at29[--at32] = 0;
3000 return false;
3001 case kMenuEventLeft:
3002 case kMenuEventRight:
3003 case kMenuEventSpace:
3004 return false;
3005 }
3006 }
3007 return CGameMenuItem::Event(event);
3008 }
3009
CGameMenuFileSelect(const char * _pzText,int _nFont,int _x,int _y,int _nWidth,const char * _startdir,const char * _pattern,char * _destination,void (* _onFileSelectedEventHandler)(),const char _doPop)3010 CGameMenuFileSelect::CGameMenuFileSelect(const char* _pzText, int _nFont, int _x, int _y, int _nWidth, const char* _startdir, const char* _pattern, char* _destination, void(*_onFileSelectedEventHandler)(), const char _doPop)
3011 {
3012 m_pzText = _pzText;
3013 m_nFont = _nFont;
3014 m_nX = _x;
3015 m_nY = _y;
3016 m_nWidth = _nWidth;
3017 startdir = _startdir;
3018 pattern = _pattern;
3019 destination = _destination;
3020 onFileSelectedEventHandler = _onFileSelectedEventHandler;
3021 doPop = _doPop;
3022 }
3023
xdim_from_320_16(int32_t x)3024 static int32_t xdim_from_320_16(int32_t x)
3025 {
3026 const int32_t screenwidth = scale(240<<16, xdim, ydim);
3027 return scale(x + (screenwidth>>1) - (160<<16), xdim, screenwidth);
3028 }
ydim_from_200_16(int32_t y)3029 static int32_t ydim_from_200_16(int32_t y)
3030 {
3031 y = mulscale16(y + rotatesprite_y_offset - (200<<15), rotatesprite_yxaspect) + (200<<15);
3032 return scale(y, ydim, 200<<16);
3033 }
3034
Menu_BlackRectangle(int32_t x,int32_t y,int32_t width,int32_t height,int32_t orientation)3035 static void Menu_BlackRectangle(int32_t x, int32_t y, int32_t width, int32_t height, int32_t orientation)
3036 {
3037 const int shadow_pal = 5;
3038 const int32_t xscale = divscale16(width, tilesiz[0].x<<16), yscale = divscale16(height, tilesiz[0].y<<16);
3039
3040 rotatesprite_(x, y, max(xscale, yscale), 0, 0, 127, shadow_pal, (orientation&(1|32))|2|8|16, 0, 0, xdim_from_320_16(x), ydim_from_200_16(y), xdim_from_320_16(x + width), ydim_from_200_16(y + height));
3041 }
3042
3043 static char tempbuf[1024];
3044 #define USERMAPENTRYLENGTH 25
3045
Menu_Run_AbbreviateNameIntoBuffer(const char * name,int32_t entrylength)3046 static void Menu_Run_AbbreviateNameIntoBuffer(const char* name, int32_t entrylength)
3047 {
3048 int32_t len = Bstrlen(name);
3049 Bstrncpy(tempbuf, name, ARRAY_SIZE(tempbuf));
3050 if (len > entrylength)
3051 {
3052 len = entrylength-3;
3053 tempbuf[len] = 0;
3054 while (len < entrylength)
3055 tempbuf[len++] = '.';
3056 }
3057 tempbuf[len] = 0;
3058 }
3059
Draw(void)3060 void CGameMenuFileSelect::Draw(void)
3061 {
3062 int height, width;
3063 vec2_t format[2] = { 40, 45, 164, 45 };
3064
3065 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
3066
3067 // black translucent background underneath file lists
3068 Menu_BlackRectangle((m_nX<<16) + (36<<16), (m_nY<<16) + (42<<16), 248<<16, 123<<16, 1|32);
3069
3070 // path
3071 Bsnprintf(tempbuf, sizeof(tempbuf), "Path: %s", destination);
3072 gMenuTextMgr.DrawText(tempbuf, m_nFont, m_nX+40, m_nY+32, 0, 0, 0);
3073
3074 int const maxRows = (162 - 40) / height;
3075 bool bClick = false;
3076
3077 for (int i = 0; i < 2; ++i)
3078 {
3079 if (findhigh[i])
3080 {
3081 BUILDVFS_FIND_REC *dir;
3082 int32_t y = 0;
3083
3084 int32_t rows = 0;
3085 for (dir = findhigh[i]->usera; dir; dir = dir->next, rows++)
3086 {
3087 }
3088 y = format[i].y;
3089
3090 int32_t row = 0;
3091
3092 for (dir = findhigh[i]->usera; dir; dir = dir->next, row++)
3093 {
3094 bool const bSelected = dir == findhigh[i] && currentList == i;
3095
3096 // pal = dir->source==BUILDVFS_SOURCE_ZIP ? 8 : 2
3097
3098 Menu_Run_AbbreviateNameIntoBuffer(dir->name, USERMAPENTRYLENGTH);
3099
3100 const int32_t thisx = format[i].x;
3101 const int32_t thisr = row - nTopDelta[i];
3102 const int32_t thisy = y + thisr * height;
3103
3104 if (0 <= thisr && thisr < maxRows)
3105 {
3106 gMenuTextMgr.GetFontInfo(m_nFont, tempbuf, &width, &height);
3107 viewDrawText(m_nFont, tempbuf, thisx, thisy, bSelected ? 32-((int)totalclock&63) : 32, 0, 0, 0);
3108 int mx = thisx<<16;
3109 int my = thisy<<16;
3110 int mw = width<<16;
3111 int mh = height<<16;
3112 if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
3113 {
3114 if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
3115 {
3116 findhigh[i] = dir;
3117 currentList = i;
3118 }
3119
3120 if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
3121 {
3122 findhigh[i] = dir;
3123 currentList = i;
3124 gGameMenuMgr.m_mousecaught = 1;
3125 bClick = true;
3126 }
3127 }
3128 }
3129 }
3130 }
3131 }
3132 if (bClick)
3133 {
3134 gGameMenuMgr.m_mousecaught = 1;
3135
3136 if (Select())
3137 gGameMenuMgr.PostPop();
3138 }
3139 }
3140
klistbookends(BUILDVFS_FIND_REC * start)3141 void klistbookends(BUILDVFS_FIND_REC *start)
3142 {
3143 auto end = start;
3144
3145 if (!start)
3146 return;
3147
3148 while (start->prev)
3149 start = start->prev;
3150
3151 while (end->next)
3152 end = end->next;
3153
3154 int i = 0;
3155
3156 for (auto n = start; n; n = n->next)
3157 {
3158 n->type = i; // overload this...
3159 n->usera = start;
3160 n->userb = end;
3161 i++;
3162 }
3163 }
3164
Event(CGameMenuEvent & event)3165 bool CGameMenuFileSelect::Event(CGameMenuEvent &event)
3166 {
3167 switch (event.at0)
3168 {
3169 case kMenuEventInit:
3170 FileSelectInit();
3171 break;
3172 case kMenuEventDeInit:
3173 fnlist_clearnames(&fnlist);
3174 break;
3175 case kMenuEventEscape:
3176 destination[0] = 0;
3177 return true;
3178 case kMenuEventEnter:
3179 return Select();
3180 case kMenuEventKey:
3181 switch (event.at2)
3182 {
3183 case sc_Home:
3184 findhigh[currentList] = findhigh[currentList]->usera;
3185 break;
3186 case sc_End:
3187 findhigh[currentList] = findhigh[currentList]->userb;
3188 break;
3189 }
3190 MovementVerify();
3191 return false;
3192 case kMenuEventUp:
3193 if (findhigh[currentList] != NULL)
3194 {
3195 if (findhigh[currentList]->prev)
3196 findhigh[currentList] = findhigh[currentList]->prev;
3197 else
3198 findhigh[currentList] = findhigh[currentList]->userb;
3199 }
3200 MovementVerify();
3201 return false;
3202 case kMenuEventDown:
3203 if (findhigh[currentList] != NULL)
3204 {
3205 if (findhigh[currentList]->next)
3206 findhigh[currentList] = findhigh[currentList]->next;
3207 else
3208 findhigh[currentList] = findhigh[currentList]->usera;
3209 }
3210 MovementVerify();
3211 return false;
3212 case kMenuEventLeft:
3213 case kMenuEventRight:
3214 if ((currentList ? fnlist.numdirs : fnlist.numfiles) > 0)
3215 currentList = !currentList;
3216 MovementVerify();
3217 return false;
3218 case kMenuEventScrollUp:
3219 if (findhigh[currentList] != NULL)
3220 {
3221 if (findhigh[currentList]->prev)
3222 {
3223 findhigh[currentList] = findhigh[currentList]->prev;
3224 nTopDelta[currentList]--;
3225 }
3226 }
3227 MovementVerify();
3228 return false;
3229 case kMenuEventScrollDown:
3230 if (findhigh[currentList] != NULL)
3231 {
3232 if (findhigh[currentList]->next)
3233 {
3234 findhigh[currentList] = findhigh[currentList]->next;
3235 nTopDelta[currentList]++;
3236 }
3237 }
3238 MovementVerify();
3239 return false;
3240 default:
3241 break;
3242 }
3243 return CGameMenuItem::Event(event);
3244 }
3245
Select(void)3246 bool CGameMenuFileSelect::Select(void)
3247 {
3248 if (!findhigh[currentList])
3249 return false;
3250
3251 char name[BMAX_PATH];
3252 Bstrcpy(name, findhigh[currentList]->name);
3253 if (!Bstrcmp(name, ".."))
3254 {
3255 SetDestinationToParentDir();
3256 }
3257 else
3258 {
3259 RemoveFilenameFromDestination();
3260 Bstrcat(destination, name);
3261 }
3262
3263 if (currentList == 0)
3264 {
3265 Bstrcat(destination, "/");
3266 Bcorrectfilename(destination, 1);
3267
3268 FileSelectInit();
3269 return false;
3270 }
3271
3272 if (onFileSelectedEventHandler)
3273 onFileSelectedEventHandler();
3274
3275 if (!doPop)
3276 return false;
3277
3278 return true;
3279 }
3280
FileSelectInit(void)3281 void CGameMenuFileSelect::FileSelectInit(void)
3282 {
3283 fnlist_clearnames(&fnlist);
3284
3285 if (destination[0] == 0)
3286 {
3287 BDIR * usermaps = Bopendir(startdir);
3288 if (usermaps)
3289 {
3290 Bclosedir(usermaps);
3291 Bstrcpy(destination, startdir);
3292 }
3293 else
3294 Bstrcpy(destination, "./");
3295 }
3296 Bcorrectfilename(destination, 1);
3297
3298 fnlist_getnames(&fnlist, destination, pattern, 0, 0);
3299 findhigh[0] = fnlist.finddirs;
3300 findhigh[1] = fnlist.findfiles;
3301
3302 for (int i = 0; i < 2; ++i)
3303 {
3304 nTopDelta[i] = 0;
3305 klistbookends(findhigh[i]);
3306 }
3307
3308 currentList = 0;
3309 if (findhigh[1])
3310 currentList = 1;
3311
3312 KB_FlushKeyboardQueue();
3313 KB_FlushKeyboardQueueScans();
3314 }
3315
MovementVerify(void)3316 void CGameMenuFileSelect::MovementVerify(void)
3317 {
3318 int height;
3319 if (!findhigh[currentList])
3320 return;
3321 gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
3322 int32_t rows = 0;
3323 for (auto dir = findhigh[currentList]->usera; dir; dir = dir->next, rows++)
3324 {
3325 }
3326 int const maxRows = (162 - 40) / height;
3327 int item = findhigh[currentList]->type - nTopDelta[currentList];
3328 if (item < 0)
3329 nTopDelta[currentList] += item;
3330 else if (item >= maxRows)
3331 nTopDelta[currentList] += item - maxRows + 1;
3332 if (nTopDelta[currentList] > rows - maxRows)
3333 nTopDelta[currentList] = rows - maxRows;
3334 if (nTopDelta[currentList] < 0)
3335 nTopDelta[currentList] = 0;
3336 }
3337
MouseEvent(CGameMenuEvent & event)3338 bool CGameMenuFileSelect::MouseEvent(CGameMenuEvent &event)
3339 {
3340 event.at0 = kMenuEventNone;
3341 if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELUP_MOUSE))
3342 {
3343 gGameMenuMgr.m_mouselastactivity = (int)totalclock;
3344 MOUSE_ClearButton(WHEELUP_MOUSE);
3345 event.at0 = kMenuEventScrollUp;
3346 }
3347 else if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELDOWN_MOUSE))
3348 {
3349 gGameMenuMgr.m_mouselastactivity = (int)totalclock;
3350 MOUSE_ClearButton(WHEELDOWN_MOUSE);
3351 event.at0 = kMenuEventScrollDown;
3352 }
3353 else
3354 return CGameMenuItem::MouseEvent(event);
3355 return event.at0 != kMenuEventNone;
3356 }
3357
RemoveFilenameFromDestination(void)3358 void CGameMenuFileSelect::RemoveFilenameFromDestination(void)
3359 {
3360 int lastSlashIndex = -1;
3361 int i = 0;
3362 while (destination[i] != 0)
3363 {
3364 if (destination[i] == '/')
3365 lastSlashIndex = i;
3366 i++;
3367 }
3368
3369 char newDestination[BMAX_PATH];
3370 for (i = 0; i <= lastSlashIndex; i++)
3371 newDestination[i] = destination[i];
3372 newDestination[i] = 0;
3373
3374 Bstrcpy(destination, newDestination);
3375 }
3376
SetDestinationToParentDir(void)3377 void CGameMenuFileSelect::SetDestinationToParentDir(void)
3378 {
3379 int lastSlashIndex = -1;
3380 int previousSlashIndex = -1;
3381 int i = 0;
3382 while (destination[i] != 0)
3383 {
3384 if (destination[i] == '/')
3385 {
3386 if (lastSlashIndex != -1)
3387 {
3388 previousSlashIndex = lastSlashIndex;
3389 lastSlashIndex = i;
3390 }
3391 else
3392 {
3393 lastSlashIndex = i;
3394 }
3395 }
3396 i++;
3397 }
3398
3399 char newDestination[BMAX_PATH];
3400 for (i = 0; i <= previousSlashIndex; i++)
3401 newDestination[i] = destination[i];
3402 newDestination[i] = 0;
3403
3404 Bstrcpy(destination, newDestination);
3405 }
3406