raze/source/blood/src/gamemenu.cpp

3003 lines
No EOL
78 KiB
C++

//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "build.h"
#include "compat.h"
#include "mouse.h"
#include "common_game.h"
#include "blood.h"
#include "config.h"
#include "gamemenu.h"
#include "globals.h"
#include "inifile.h"
#include "levels.h"
#include "menu.h"
#include "qav.h"
#include "resource.h"
#include "view.h"
CMenuTextMgr gMenuTextMgr;
CGameMenuMgr gGameMenuMgr;
extern CGameMenuItemPicCycle itemSorryPicCycle;
extern CGameMenuItemQAV itemBloodQAV;
CMenuTextMgr::CMenuTextMgr()
{
at0 = -1;
}
static char buffer[21][45];
void CMenuTextMgr::DrawText(const char *pString, int nFont, int x, int y, int nShade, int nPalette, bool shadow )
{
viewDrawText(nFont, pString, x, y, nShade, nPalette, 0, shadow);
}
void CMenuTextMgr::GetFontInfo(int nFont, const char *pString, int *pXSize, int *pYSize)
{
if (nFont < 0 || nFont >= 5)
return;
viewGetFontInfo(nFont, pString, pXSize, pYSize);
}
bool CGameMenuMgr::m_bInitialized = false;
bool CGameMenuMgr::m_bActive = false;
bool CGameMenuMgr::m_bFirstPush = true;
CGameMenuMgr::CGameMenuMgr()
{
dassert(!m_bInitialized);
m_bInitialized = true;
Clear();
}
CGameMenuMgr::~CGameMenuMgr()
{
m_bInitialized = false;
Clear();
}
void CGameMenuMgr::InitializeMenu(void)
{
if (pActiveMenu)
{
CGameMenuEvent event;
event.at0 = kMenuEventInit;
event.at2 = 0;
pActiveMenu->Event(event);
}
}
void CGameMenuMgr::DeInitializeMenu(void)
{
if (pActiveMenu)
{
CGameMenuEvent event;
event.at0 = kMenuEventDeInit;
event.at2 = 0;
pActiveMenu->Event(event);
}
}
bool CGameMenuMgr::Push(CGameMenu *pMenu, int nItem)
{
if (nMenuPointer == 0)
{
mouseReadAbs(&m_prevmousepos, &g_mouseAbs);
m_mouselastactivity = -M_MOUSETIMEOUT;
m_mousewake_watchpoint = 0;
mouseLockToWindow(0);
if (m_bFirstPush)
m_bFirstPush = false;
else
mouseMoveToCenter();
}
dassert(pMenu != NULL);
if (nMenuPointer == 8)
return false;
pActiveMenu = pMenuStack[nMenuPointer] = pMenu;
nMenuPointer++;
if (nItem >= 0)
pMenu->SetFocusItem(nItem);
m_bActive = true;
gInputMode = INPUT_MODE_1;
InitializeMenu();
m_menuchange_watchpoint = 1;
m_mousecaught = 1;
return true;
}
void CGameMenuMgr::Pop(void)
{
if (nMenuPointer > 0)
{
DeInitializeMenu();
nMenuPointer--;
if (nMenuPointer == 0)
Deactivate();
else
pActiveMenu = pMenuStack[nMenuPointer-1];
m_menuchange_watchpoint = 1;
}
m_mousecaught = 1;
}
void CGameMenuMgr::PostPop(void)
{
m_postPop = true;
}
void CGameMenuMgr::Draw(void)
{
if (pActiveMenu)
{
pActiveMenu->Draw();
viewUpdatePages();
}
if (m_postPop)
{
Pop();
m_postPop = false;
}
int32_t mousestatus = mouseReadAbs(&m_mousepos, &g_mouseAbs);
if (mousestatus && g_mouseClickState == MOUSE_PRESSED)
m_mousedownpos = m_mousepos;
int16_t mousetile = 1043; // red arrow
if (tilesiz[mousetile].x > 0 && mousestatus)
{
if (!MOUSEACTIVECONDITION)
m_mousewake_watchpoint = 1;
if (MOUSEACTIVECONDITIONAL(mouseAdvanceClickState()) || m_mousepos.x != m_prevmousepos.x || m_mousepos.y != m_prevmousepos.y)
{
m_prevmousepos = m_mousepos;
m_mouselastactivity = totalclock.Ticks();
}
else
m_mousewake_watchpoint = 0;
m_mousecaught = 0;
}
else
{
m_mouselastactivity = -M_MOUSETIMEOUT;
m_mousewake_watchpoint = 0;
}
// Display the mouse cursor, except on touch devices.
if (MOUSEACTIVECONDITION && !m_bFirstPush)
{
vec2_t cursorpos = { m_mousepos.x + (7 << 16), m_mousepos.y + (6 << 16) };
if ((unsigned) mousetile < MAXTILES)
{
int32_t scale = 65536;
int16_t rotate = 768;
uint32_t stat = 2|4|8;
int8_t alpha = MOUSEALPHA; //CURSORALPHA;
rotatesprite_fs_alpha(cursorpos.x, cursorpos.y, scale, rotate, mousetile, 0, 0, stat, alpha);
}
}
else
g_mouseClickState = MOUSE_IDLE;
}
void CGameMenuMgr::Clear(void)
{
pActiveMenu = NULL;
memset(pMenuStack, 0, sizeof(pMenuStack));
nMenuPointer = 0;
m_postPop = false;
}
void CGameMenuMgr::Process(void)
{
if (!pActiveMenu)
return;
if (m_menuchange_watchpoint > 0)
m_menuchange_watchpoint++;
CGameMenuEvent event;
event.at0 = 0;
event.at2 = 0;
char key;
if (!pActiveMenu->MouseEvent(event) && (key = keyGetScan()) != 0 )
{
keyFlushScans();
keyFlushChars();
event.at2 = key;
switch (key)
{
case sc_Escape:
event.at0 = kMenuEventEscape;
break;
case sc_Tab:
if (keystatus[sc_LeftShift] || keystatus[sc_RightShift])
event.at0 = kMenuEventUp;
else
event.at0 = kMenuEventDown;
break;
case sc_UpArrow:
case sc_kpad_8:
event.at0 = kMenuEventUp;
gGameMenuMgr.m_mouselastactivity = -M_MOUSETIMEOUT;
break;
case sc_DownArrow:
case sc_kpad_2:
event.at0 = kMenuEventDown;
gGameMenuMgr.m_mouselastactivity = -M_MOUSETIMEOUT;
break;
case sc_Enter:
case sc_kpad_Enter:
event.at0 = kMenuEventEnter;
break;
case sc_Space:
event.at0 = kMenuEventSpace;
break;
case sc_LeftArrow:
case sc_kpad_4:
event.at0 = kMenuEventLeft;
break;
case sc_RightArrow:
case sc_kpad_6:
event.at0 = kMenuEventRight;
break;
case sc_Delete:
case sc_kpad_Period:
event.at0 = kMenuEventDelete;
break;
case sc_BackSpace:
event.at0 = kMenuEventBackSpace;
break;
default:
event.at0 = kMenuEventKey;
break;
}
}
if (pActiveMenu->Event(event))
Pop();
if (m_menuchange_watchpoint >= 3)
m_menuchange_watchpoint = 0;
}
void CGameMenuMgr::Deactivate(void)
{
Clear();
keyFlushScans();
keyFlushChars();
m_bActive = false;
mouseLockToWindow(1);
gInputMode = INPUT_MODE_0;
}
bool CGameMenuMgr::MouseOutsideBounds(vec2_t const * const pos, const int32_t x, const int32_t y, const int32_t width, const int32_t height)
{
return pos->x < x || pos->x >= x + width || pos->y < y || pos->y >= y + height;
}
CGameMenu::CGameMenu()
{
m_nItems = 0;
m_nFocus = at8 = -1;
atc = 0;
}
CGameMenu::CGameMenu(int unk)
{
m_nItems = 0;
m_nFocus = at8 = -1;
atc = unk;
}
CGameMenu::~CGameMenu()
{
if (!atc)
return;
for (int i = 0; i < m_nItems; i++)
{
if (pItemList[i] != &itemBloodQAV && pItemList[i] != &itemSorryPicCycle)
delete pItemList[i];
}
}
void CGameMenu::InitializeItems(CGameMenuEvent &event)
{
for (int i = 0; i < m_nItems; i++)
{
pItemList[i]->Event(event);
}
}
void CGameMenu::Draw(void)
{
for (int i = 0; i < m_nItems; i++)
{
if (pItemList[i]->pPreDrawCallback)
pItemList[i]->pPreDrawCallback(pItemList[i]);
if (i == m_nFocus || (i != m_nFocus && !pItemList[i]->bNoDraw))
pItemList[i]->Draw();
}
}
bool CGameMenu::Event(CGameMenuEvent &event)
{
if (m_nItems <= 0)
return true;
switch (event.at0)
{
case kMenuEventInit:
case kMenuEventDeInit:
if (at8 >= 0)
m_nFocus = at8;
InitializeItems(event);
return false;
}
if (m_nFocus < 0)
return true;
return pItemList[m_nFocus]->Event(event);
}
void CGameMenu::Add(CGameMenuItem *pItem, bool active)
{
dassert(pItem != NULL);
dassert(m_nItems < kMaxGameMenuItems);
pItemList[m_nItems] = pItem;
pItem->pMenu = this;
if (active)
m_nFocus = at8 = m_nItems;
m_nItems++;
}
void CGameMenu::SetFocusItem(int nItem)
{
dassert(nItem >= 0 && nItem < m_nItems && nItem < kMaxGameMenuItems);
if (CanSelectItem(nItem))
m_nFocus = at8 = nItem;
}
void CGameMenu::SetFocusItem(CGameMenuItem *pItem)
{
for (int i = 0; i < m_nItems; i++)
if (pItemList[i] == pItem)
{
SetFocusItem(i);
break;
}
}
bool CGameMenu::CanSelectItem(int nItem)
{
dassert(nItem >= 0 && nItem < m_nItems && nItem < kMaxGameMenuItems);
return pItemList[nItem]->bCanSelect && pItemList[nItem]->bEnable;
}
void CGameMenu::FocusPrevItem(void)
{
dassert(m_nFocus >= -1 && m_nFocus < m_nItems && m_nFocus < kMaxGameMenuItems);
int t = m_nFocus;
do
{
m_nFocus--;
if (m_nFocus < 0)
m_nFocus += m_nItems;
if (CanSelectItem(m_nFocus))
break;
} while(t != m_nFocus);
}
void CGameMenu::FocusNextItem(void)
{
dassert(m_nFocus >= -1 && m_nFocus < m_nItems && m_nFocus < kMaxGameMenuItems);
int t = m_nFocus;
do
{
m_nFocus++;
if (m_nFocus >= m_nItems)
m_nFocus = 0;
if (CanSelectItem(m_nFocus))
break;
} while(t != m_nFocus);
}
bool CGameMenu::IsFocusItem(CGameMenuItem *pItem)
{
if (m_nFocus < 0)
return false;
dassert(m_nFocus >= 0 && m_nFocus < m_nItems && m_nFocus < kMaxGameMenuItems);
return pItemList[m_nFocus] == pItem;
}
bool CGameMenu::MouseEvent(CGameMenuEvent &event)
{
if (m_nItems <= 0 || m_nFocus < 0)
return true;
return pItemList[m_nFocus]->MouseEvent(event);
}
CGameMenuItem::CGameMenuItem()
{
m_pzText = NULL;
m_nX = m_nY = m_nWidth = 0;
bCanSelect = 1;
bEnable = 1;
m_nFont = -1;
pMenu = NULL;
bNoDraw = 0;
pPreDrawCallback = NULL;
}
CGameMenuItem::~CGameMenuItem()
{
}
bool CGameMenuItem::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventEscape:
return true;
case kMenuEventUp:
pMenu->FocusPrevItem();
break;
case kMenuEventDown:
pMenu->FocusNextItem();
break;
}
return false;
}
bool CGameMenuItem::MouseEvent(CGameMenuEvent &event)
{
event.at0 = kMenuEventNone;
if (MOUSEINACTIVECONDITIONAL(MOUSE_GetButtons()&LEFT_MOUSE))
{
event.at0 = kMenuEventEnter;
MOUSE_ClearButton(LEFT_MOUSE);
}
else if (MOUSE_GetButtons()&RIGHT_MOUSE)
{
event.at0 = kMenuEventEscape;
MOUSE_ClearButton(RIGHT_MOUSE);
}
#if 0
else if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELUP_MOUSE)))
{
MOUSE_ClearButton(WHEELUP_MOUSE);
event.bAutoAim = kMenuEventScrollLeft;
}
else if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELDOWN_MOUSE)))
{
MOUSE_ClearButton(WHEELDOWN_MOUSE);
event.bAutoAim = kMenuEventScrollRight;
}
#endif
else if (MOUSE_GetButtons()&WHEELUP_MOUSE)
{
MOUSE_ClearButton(WHEELUP_MOUSE);
event.at0 = kMenuEventUp;
}
else if (MOUSE_GetButtons()&WHEELDOWN_MOUSE)
{
MOUSE_ClearButton(WHEELDOWN_MOUSE);
event.at0 = kMenuEventDown;
}
return event.at0 != kMenuEventNone;
}
CGameMenuItemText::CGameMenuItemText()
{
m_pzText = 0;
bEnable = 0;
}
CGameMenuItemText::CGameMenuItemText(const char *a1, int a2, int a3, int a4, int a5)
{
m_nWidth = 0;
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
at20 = a5;
bEnable = 0;
}
void CGameMenuItemText::Draw(void)
{
if (m_pzText)
{
int width;
int x = m_nX;
switch (at20)
{
case 1:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX-width/2;
break;
case 2:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX-width;
break;
}
gMenuTextMgr.DrawText(m_pzText,m_nFont, x, m_nY, -128, 0, false);
}
}
CGameMenuItemTitle::CGameMenuItemTitle()
{
m_pzText = 0;
bEnable = 0;
}
CGameMenuItemTitle::CGameMenuItemTitle(const char *a1, int a2, int a3, int a4, int a5)
{
m_nWidth = 0;
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
at20 = a5;
bEnable = 0;
}
void CGameMenuItemTitle::Draw(void)
{
if (m_pzText)
{
int height;
gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
if (at20 >= 0)
rotatesprite(320<<15, m_nY<<16, 65536, 0, at20, -128, 0, 78, 0, 0, xdim-1, ydim-1);
viewDrawText(m_nFont, m_pzText, m_nX, m_nY-height/2, -128, 0, 1, false);
}
}
CGameMenuItemZBool::CGameMenuItemZBool()
{
at20 = false;
m_pzText = 0;
at21 = "On";
at25 = "Off";
}
CGameMenuItemZBool::CGameMenuItemZBool(const char *a1, int a2, int a3, int a4, int a5, bool a6, void(*a7)(CGameMenuItemZBool *), const char *a8, const char *a9)
{
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nWidth = a5;
at20 = a6;
at29 = a7;
if (!a8)
at21 = "On";
else
at21 = a8;
if (!a9)
at25 = "Off";
else
at25 = a9;
}
void CGameMenuItemZBool::Draw(void)
{
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
if (m_pzText)
gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
const char *value = at20 ? at21 : at25;
int width, height;
gMenuTextMgr.GetFontInfo(m_nFont, value, &width, &height);
gMenuTextMgr.DrawText(value, m_nFont, m_nWidth-1+m_nX-width, m_nY, shade, pal, false);
int mx = m_nX<<16;
int my = m_nY<<16;
int mw = m_nWidth<<16;
int mh = height<<16;
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
{
pMenu->SetFocusItem(this);
}
if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
{
pMenu->SetFocusItem(this);
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
}
bool CGameMenuItemZBool::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventEnter:
case kMenuEventSpace:
at20 = !at20;
if (at29)
at29(this);
return false;
}
return CGameMenuItem::Event(event);
}
CGameMenuItemChain::CGameMenuItemChain()
{
m_pzText = NULL;
at24 = NULL;
at28 = -1;
at2c = NULL;
at30 = 0;
}
CGameMenuItemChain::CGameMenuItemChain(const char *a1, int a2, int a3, int a4, int a5, int a6, CGameMenu *a7, int a8, void(*a9)(CGameMenuItemChain *), int a10)
{
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nWidth = a5;
at20 = a6;
at24 = a7;
at28 = a8;
at2c = a9;
at30 = a10;
}
void CGameMenuItemChain::Draw(void)
{
if (!m_pzText) return;
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
int width, height;
int x = m_nX;
int y = m_nY;
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, &height);
switch (at20)
{
case 1:
x = m_nX+m_nWidth/2-width/2;
break;
case 2:
x = m_nX+m_nWidth-1-width;
break;
case 0:
default:
break;
}
gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, pal, true);
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, x<<16, y<<16, width<<16, height<<16)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, x<<16, y<<16, width<<16, height<<16)))
{
pMenu->SetFocusItem(this);
}
if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, x<<16, y<<16, width<<16, height<<16))
{
pMenu->SetFocusItem(this);
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
}
bool CGameMenuItemChain::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventEnter:
if (at2c)
at2c(this);
if (at24)
gGameMenuMgr.Push(at24, at28);
return false;
}
return CGameMenuItem::Event(event);
}
CGameMenuItem7EA1C::CGameMenuItem7EA1C()
{
m_pzText = NULL;
at24 = NULL;
at28 = -1;
at2c = NULL;
at30 = 0;
at34 = NULL;
at38[0] = 0;
at48[0] = 0;
}
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)
{
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nWidth = a5;
at20 = a8;
at28 = a9;
at2c = a10;
at30 = a11;
strncpy(at38, a6, 15);
strncpy(at48, a7, 15);
}
void CGameMenuItem7EA1C::Draw(void)
{
if (!m_pzText) return;
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
int width;
int x = m_nX;
switch (at20)
{
case 1:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX+m_nWidth/2-width/2;
break;
case 2:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX+m_nWidth-1-width;
break;
case 0:
default:
break;
}
gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, pal, true);
}
void CGameMenuItem7EA1C::Setup(void)
{
if (!at34 || !at24)
return;
if (!at34->SectionExists(at48))
return;
const char *title = at34->GetKeyString(at48, "Title", at48);
at24->Add(new CGameMenuItemTitle(title, 1, 160, 20, 2038), false);
at24->Add(&itemSorryPicCycle, true);
int y = 40;
for (int i = 0; i < 21; i++)
{
sprintf(buffer[i], "Line%d", i+1);
if (!at34->KeyExists(at48, buffer[i]))
break;
const char *line = at34->GetKeyString(at48, buffer[i], NULL);
if (line)
{
if (*line == 0)
{
y += 10;
continue;
}
at24->Add(new CGameMenuItemText(line, 1, 160, y, 1), false);
y += 20;
}
}
at24->Add(&itemBloodQAV, false);
}
bool CGameMenuItem7EA1C::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventEnter:
{
if (at2c)
at2c(this);
if (at24)
delete at24;
at24 = new CGameMenu(1);
DICTNODE *pRes = gGuiRes.Lookup(at38, "MNU");
if (pRes)
{
at34 = new IniFile(gGuiRes.Load(pRes));
Setup();
}
if (at24)
gGameMenuMgr.Push(at24, at28);
return false;
}
case kMenuEventDeInit:
if (at34)
{
delete at34;
at34 = NULL;
}
if (at24)
{
delete at24;
at24 = NULL;
}
return false;
}
return CGameMenuItem::Event(event);
}
CGameMenuItem7EE34::CGameMenuItem7EE34()
{
m_pzText = NULL;
at28 = NULL;
at20 = -1;
at2c = NULL;
}
CGameMenuItem7EE34::CGameMenuItem7EE34(const char *a1, int a2, int a3, int a4, int a5, int a6)
{
m_pzText = NULL;
at28 = NULL;
at20 = -1;
at2c = NULL;
m_nFont = a2;
m_nX = a3;
m_pzText = a1;
m_nY = a4;
m_nWidth = a5;
at24 = a6;
}
void CGameMenuItem7EE34::Draw(void)
{
if (!m_pzText) return;
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
int width;
int x = m_nX;
switch (at24)
{
case 1:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX+m_nWidth/2-width/2;
break;
case 2:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX+m_nWidth-1-width;
break;
case 0:
default:
break;
}
gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, pal, true);
}
extern void SetVideoModeOld(CGameMenuItemChain *pItem);
void CGameMenuItem7EE34::Setup(void)
{
if (!at28)
return;
at28->Add(new CGameMenuItemTitle("Video Mode", 1, 160, 20, 2038), false);
if (!at2c)
{
at2c = new CGameMenu(1);
at2c->Add(new CGameMenuItemTitle(" Mode Change ", 1, 160, 20, 2038), false);
at2c->Add(&itemSorryPicCycle, true);
CGameMenuItem *pItem1 = new CGameMenuItemText("VIDEO MODE WAS SET", 1, 160, 90, 1);
CGameMenuItem *pItem2 = new CGameMenuItemText("NOT ALL MODES Work correctly", 1, 160, 110, 1);
CGameMenuItem *pItem3 = new CGameMenuItemText("Press ESC to exit", 3, 160, 140, 1);
at2c->Add(pItem1, false);
pItem1->bEnable = 0;
at2c->Add(pItem2, false);
pItem2->bEnable = 0;
at2c->Add(pItem3, true);
pItem3->bEnable = 1;
at2c->Add(&itemBloodQAV, false);
}
sprintf(buffer[0], "640 x 480 (default)");
int y = 40;
at28->Add(new CGameMenuItemChain(buffer[0], 3, 0, y, 320, 1, at2c, -1, SetVideoModeOld, validmodecnt), true);
y += 20;
for (int i = 0; i < validmodecnt && i < 20; i++)
{
sprintf(buffer[i+1], "%d x %d", validmode[i].xdim, validmode[i].ydim);
at28->Add(new CGameMenuItemChain(buffer[i+1], 3, 0, y, 320, 1, at2c, -1, SetVideoModeOld, i), false);
if (validmodecnt > 10)
y += 7;
else
y += 15;
}
at28->Add(&itemBloodQAV, false);
}
bool CGameMenuItem7EE34::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventEnter:
if (at28)
delete at28;
at28 = new CGameMenu(1);
Setup();
if (at28)
gGameMenuMgr.Push(at28, at20);
return false;
case kMenuEventDeInit:
if (at28)
{
delete at28;
at28 = 0;
}
return false;
}
return CGameMenuItem::Event(event);
}
CGameMenuItemChain7F2F0::CGameMenuItemChain7F2F0()
{
at34 = -1;
}
CGameMenuItemChain7F2F0::CGameMenuItemChain7F2F0(char *a1, int a2, int a3, int a4, int a5, int a6, CGameMenu *a7, int a8, void(*a9)(CGameMenuItemChain *), int a10) :
CGameMenuItemChain(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
{
at34 = a10;
}
bool CGameMenuItemChain7F2F0::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventEnter:
if (at34 > -1)
gGameOptions.nEpisode = at34;
return CGameMenuItemChain::Event(event);
}
return CGameMenuItem::Event(event);
}
CGameMenuItemBitmap::CGameMenuItemBitmap()
{
m_pzText = NULL;
}
CGameMenuItemBitmap::CGameMenuItemBitmap(const char *a1, int a2, int a3, int a4, int a5)
{
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
at20 = a5;
}
void CGameMenuItemBitmap::Draw(void)
{
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (bEnable && pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
int x = m_nX;
int y = m_nY;
if (m_pzText)
{
int height;
gMenuTextMgr.DrawText(m_pzText, m_nFont, x, y, shade, pal, false);
gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
y += height + 2;
}
rotatesprite(x<<15,y<<15, 65536, 0, at20, 0, 0, 82, 0, 0, xdim-1,ydim-1);
}
bool CGameMenuItemBitmap::Event(CGameMenuEvent &event)
{
if (bEnable && pMenu->IsFocusItem(this))
pMenu->FocusNextItem();
return CGameMenuItem::Event(event);
}
CGameMenuItemBitmapLS::CGameMenuItemBitmapLS()
{
m_pzText = NULL;
}
CGameMenuItemBitmapLS::CGameMenuItemBitmapLS(const char *a1, int a2, int a3, int a4, int a5)
{
at24 = -1;
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
at28 = a5;
}
void CGameMenuItemBitmapLS::Draw(void)
{
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (bEnable && pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
int x = m_nX;
int y = m_nY;
if (m_pzText)
{
int height;
gMenuTextMgr.DrawText(m_pzText, m_nFont, x, y, shade, pal, false);
gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
y += height + 2;
}
char stat;
int16_t ang;
int picnum;
if (at24 == -1)
{
stat = 66;
ang = 0;
picnum = at28;
}
else
{
ang = 512;
stat = 70;
picnum = at24;
}
rotatesprite(200<<15,215<<15,32768, ang, picnum, 0, 0, stat, 0, 0, xdim-1, ydim-1);
}
bool CGameMenuItemBitmapLS::Event(CGameMenuEvent &event)
{
if (bEnable && pMenu->IsFocusItem(this))
pMenu->FocusNextItem();
return CGameMenuItem::Event(event);
}
CGameMenuItemKeyList::CGameMenuItemKeyList()
{
m_pzText = NULL;
m_nFont = 3;
m_nX = 0;
m_nY = 0;
nRows = 0;
nTopDelta = 0;
nFocus = 0;
nGameFuncs = 0;
bScan = false;
}
CGameMenuItemKeyList::CGameMenuItemKeyList(const char *a1, int a2, int a3, int a4, int a5, int a6, int a7, void(*a8)(CGameMenuItemKeyList *))
{
nTopDelta = 0;
nFocus = 0;
bScan = false;
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nWidth = a5;
nRows = a6;
pCallback = a8;
nGameFuncs = a7;
}
void CGameMenuItemKeyList::Scan(void)
{
KB_FlushKeyboardQueue();
KB_FlushKeyboardQueueScans();
KB_ClearKeysDown();
KB_LastScan = 0;
bScan = true;
}
extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
void CGameMenuItemKeyList::Draw(void)
{
char buffer[40], buffer2[40];
int width, height;
int shade;
gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
int y = m_nY;
int k = nFocus - nTopDelta;
int nNewFocus = nFocus;
bool bClick = false;
for (int i = 0; i < nRows; i++, y += height, k++)
{
char key1, key2;
key1 = KeyboardKeys[k][0];
key2 = KeyboardKeys[k][1];
const char *sKey1 = key1 == sc_Tilde ? "Tilde" : KB_ScanCodeToString(key1);
const char *sKey2 = key2 == sc_Tilde ? "Tilde" : KB_ScanCodeToString(key2);
sprintf(buffer, "%s", CONFIG_FunctionNumToName(k));
if (key2 == 0 || key2 == 0xff)
{
if (key1 == 0 || key1 == 0xff)
sprintf(buffer2, "????");
else
sprintf(buffer2, "%s", sKey1);
}
else
sprintf(buffer2, "%s or %s", sKey1, sKey2);
if (k == nFocus)
{
shade = 32;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
viewDrawText(3, buffer, m_nX, y, shade, 0, 0, false);
const char *sVal;
if (bScan && (gGameClock & 32))
sVal = "____";
else
sVal = buffer2;
gMenuTextMgr.GetFontInfo(m_nFont, sVal, &width, 0);
viewDrawText(m_nFont, sVal, m_nX+m_nWidth-1-width, y, shade, 0, 0, false);
}
else
{
viewDrawText(3, buffer, m_nX, y, 24, 0, 0, false);
gMenuTextMgr.GetFontInfo(m_nFont, buffer2, &width, 0);
viewDrawText(m_nFont, buffer2, m_nX+m_nWidth-1-width, y, 24, 0, 0, false);
}
int mx = m_nX<<16;
int my = y<<16;
int mw = m_nWidth<<16;
int mh = height<<16;
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
{
nNewFocus = k;
}
if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
{
nNewFocus = k;
bClick = true;
}
}
}
nTopDelta += nNewFocus-nFocus;
nFocus = nNewFocus;
if (bClick)
{
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
bool CGameMenuItemKeyList::Event(CGameMenuEvent &event)
{
if (bScan)
{
if (KB_LastScan && KB_LastScan != sc_Pause)
{
if (KB_KeyWaiting())
KB_GetCh();
char key1, key2;
extern uint8_t KeyboardKeys[NUMGAMEFUNCTIONS][2];
key1 = KeyboardKeys[nFocus][0];
key2 = KeyboardKeys[nFocus][1];
if (key1 > 0 && key2 != KB_LastScan)
key2 = key1;
key1 = KB_LastScan;
if (key1 == key2)
key2 = 0;
uint8_t oldKey[2];
oldKey[0] = KeyboardKeys[nFocus][0];
oldKey[1] = KeyboardKeys[nFocus][1];
KeyboardKeys[nFocus][0] = key1;
KeyboardKeys[nFocus][1] = key2;
CONFIG_MapKey(nFocus, key1, oldKey[0], key2, oldKey[1]);
KB_FlushKeyboardQueue();
KB_FlushKeyboardQueueScans();
KB_ClearKeysDown();
keyFlushScans();
keyFlushChars();
bScan = 0;
}
return false;
}
switch (event.at0)
{
case kMenuEventUp:
if (event.at2 == sc_Tab || nFocus == 0)
{
pMenu->FocusPrevItem();
return false;
}
nFocus--;
if (nTopDelta > 0)
nTopDelta--;
return false;
case kMenuEventDown:
if (event.at2 == sc_Tab || nFocus == nGameFuncs-1)
{
pMenu->FocusNextItem();
return false;
}
nFocus++;
if (nTopDelta+1 < nRows)
nTopDelta++;
return false;
case kMenuEventEnter:
if (pCallback)
pCallback(this);
Scan();
return false;
case kMenuEventDelete:
if (keystatus[sc_LeftControl] || keystatus[sc_RightControl])
{
uint8_t oldKey[2];
oldKey[0] = KeyboardKeys[nFocus][0];
oldKey[1] = KeyboardKeys[nFocus][1];
KeyboardKeys[nFocus][0] = 0;
KeyboardKeys[nFocus][1] = 0;
CONFIG_MapKey(nFocus, 0, oldKey[0], 0, oldKey[1]);
}
return false;
case kMenuEventScrollUp:
if (nFocus-nTopDelta > 0)
{
nTopDelta++;
if (nTopDelta>0)
{
nFocus--;
nTopDelta--;
}
}
return false;
case kMenuEventScrollDown:
if (nFocus-nTopDelta+nRows < nGameFuncs)
{
nTopDelta--;
if (nTopDelta+1 < nRows)
{
nFocus++;
nTopDelta++;
}
}
return false;
}
return CGameMenuItem::Event(event);
}
bool CGameMenuItemKeyList::MouseEvent(CGameMenuEvent &event)
{
event.at0 = kMenuEventNone;
if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELUP_MOUSE))
{
gGameMenuMgr.m_mouselastactivity = totalclock.Ticks();
MOUSE_ClearButton(WHEELUP_MOUSE);
event.at0 = kMenuEventScrollUp;
}
else if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELDOWN_MOUSE))
{
gGameMenuMgr.m_mouselastactivity = totalclock.Ticks();
MOUSE_ClearButton(WHEELDOWN_MOUSE);
event.at0 = kMenuEventScrollDown;
}
else
return CGameMenuItem::MouseEvent(event);
return event.at0 != kMenuEventNone;
}
CGameMenuItemSlider::CGameMenuItemSlider()
{
m_pzText = NULL;
m_nFont = -1;
m_nX = 0;
m_nY = 0;
nValue = 0;
nRangeLow = 0;
nStep = 0;
pCallback = NULL;
pValue = NULL;
nSliderTile = 2204;
nCursorTile = 2028;
nShowValue = kMenuSliderNone;
}
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)
{
m_pzText = _pzText;
m_nFont = _nFont;
m_nX = _nX;
m_nY = _nY;
m_nWidth = _nWidth;
nRangeLow = _nRangeLow;
nRangeHigh = _nRangeHigh;
nStep = _nStep;
nValue = ClipRange(_nValue, nRangeLow, nRangeHigh);
pCallback = _pCallback;
nSliderTile = 2204;
nCursorTile = 2028;
if (_nSliderTile >= 0)
nSliderTile = _nSliderTile;
if (_nCursorTile >= 0)
nCursorTile = _nCursorTile;
nShowValue = _nShowValue;
}
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)
{
m_pzText = _pzText;
m_nFont = _nFont;
m_nX = _nX;
m_nY = _nY;
m_nWidth = _nWidth;
nRangeLow = _nRangeLow;
nRangeHigh = _nRangeHigh;
nStep = _nStep;
dassert(pnValue != NULL);
pValue = pnValue;
nValue = ClipRange(*pnValue, nRangeLow, nRangeHigh);
pCallback = _pCallback;
nSliderTile = 2204;
nCursorTile = 2028;
if (_nSliderTile >= 0)
nSliderTile = _nSliderTile;
if (_nCursorTile >= 0)
nCursorTile = _nCursorTile;
nShowValue = _nShowValue;
}
void CGameMenuItemSlider::Draw(void)
{
char buffer[16];
int height;
nValue = pValue ? *pValue : nValue;
gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
int shade = bEnable ? 32 : 48;
int shade2 = bEnable ? 0 : 16;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
if (m_pzText)
gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
int sliderX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x/2;
rotatesprite(sliderX<<16, (m_nY+height/2)<<16, 65536, 0, nSliderTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
int nRange = nRangeHigh - nRangeLow;
dassert(nRange > 0);
int value = nValue - nRangeLow;
int width = tilesiz[nSliderTile].x-8;
int cursorX = sliderX + ksgn(nStep)*(value * width / nRange - width / 2);
rotatesprite(cursorX<<16, (m_nY+height/2)<<16, 65536, 0, nCursorTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
buffer[0] = 0;
switch (nShowValue)
{
case kMenuSliderNone:
break;
case kMenuSliderValue:
sprintf(buffer, "%i ", nValue);
break;
case kMenuSliderPercent:
sprintf(buffer, "%i%% ", roundscale(value, 100, nRange));
break;
case kMenuSliderQ16:
snprintf(buffer, 16, "%.3f ", nValue/65536.f);
break;
}
int valueWidth;
gMenuTextMgr.GetFontInfo(m_nFont, buffer, &valueWidth, NULL);
int valueX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x-valueWidth;
gMenuTextMgr.DrawText(buffer, m_nFont, valueX, m_nY, 32, 0, false);
int mx = m_nX;
int my = m_nY;
int mw = m_nWidth;
int mh = height;
if (height < tilesiz[nSliderTile].y)
{
my -= (tilesiz[nSliderTile].y-height)/2;
height = tilesiz[nSliderTile].y;
}
mx <<= 16;
my <<= 16;
mw <<= 16;
mh <<= 16;
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
{
pMenu->SetFocusItem(this);
}
if (!gGameMenuMgr.m_mousecaught && (g_mouseClickState == MOUSE_PRESSED || g_mouseClickState == MOUSE_HELD))
{
pMenu->SetFocusItem(this);
int sliderx = m_nX+m_nWidth-1-tilesiz[nSliderTile].x;
int sliderwidth = tilesiz[nSliderTile].x;
int regionwidth = sliderwidth-8;
int regionx = sliderx+(sliderwidth-regionwidth)/2;
sliderx <<= 16;
sliderwidth <<= 16;
regionwidth <<= 16;
regionx <<= 16;
// region between the x-midline of the slidepoint at the extremes slides proportionally
if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, regionx, my, regionwidth, mh))
{
int dx = (gGameMenuMgr.m_mousepos.x - (regionx+regionwidth/2))*ksgn(nStep);
nValue = nRangeLow + roundscale(dx+regionwidth/2, nRange, regionwidth);
nValue = ClipRange(nValue, nRangeLow, nRangeHigh);
if (pCallback)
pCallback(this);
gGameMenuMgr.m_mousecaught = 1;
}
// region outside the x-midlines clamps to the extremes
else if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, sliderx, my, sliderwidth, mh))
{
if ((gGameMenuMgr.m_mousepos.x-(regionx+regionwidth/2))*ksgn(nStep) > 0)
nValue = nRangeHigh;
else
nValue = nRangeLow;
if (pCallback)
pCallback(this);
gGameMenuMgr.m_mousecaught = 1;
}
}
}
}
bool CGameMenuItemSlider::Event(CGameMenuEvent &event)
{
nValue = pValue ? *pValue : nValue;
switch (event.at0)
{
case kMenuEventUp:
pMenu->FocusPrevItem();
return false;
case kMenuEventDown:
pMenu->FocusNextItem();
return false;
case kMenuEventLeft:
if (nStep > 0)
nValue = DecBy(nValue, nStep);
else
nValue = IncBy(nValue, -nStep);
nValue = ClipRange(nValue, nRangeLow, nRangeHigh);
if (pCallback)
pCallback(this);
return false;
case kMenuEventRight:
if (nStep >= 0)
nValue = IncBy(nValue, nStep);
else
nValue = DecBy(nValue, -nStep);
nValue = ClipRange(nValue, nRangeLow, nRangeHigh);
if (pCallback)
pCallback(this);
return false;
case kMenuEventEnter:
if (pCallback)
pCallback(this);
return false;
}
return CGameMenuItem::Event(event);
}
bool CGameMenuItemSlider::MouseEvent(CGameMenuEvent &event)
{
event.at0 = kMenuEventNone;
if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELUP_MOUSE)))
{
MOUSE_ClearButton(WHEELUP_MOUSE);
event.at0 = kMenuEventLeft;
}
else if (MOUSEINACTIVECONDITIONAL((MOUSE_GetButtons()&LEFT_MOUSE) && (MOUSE_GetButtons()&WHEELDOWN_MOUSE)))
{
MOUSE_ClearButton(WHEELDOWN_MOUSE);
event.at0 = kMenuEventRight;
}
else if (MOUSE_GetButtons()&RIGHT_MOUSE)
{
MOUSE_ClearButton(RIGHT_MOUSE);
event.at0 = kMenuEventEscape;
}
else if (MOUSE_GetButtons()&WHEELUP_MOUSE)
{
MOUSE_ClearButton(WHEELUP_MOUSE);
MOUSE_ClearButton(LEFT_MOUSE);
event.at0 = kMenuEventUp;
}
else if (MOUSE_GetButtons()&WHEELDOWN_MOUSE)
{
MOUSE_ClearButton(WHEELDOWN_MOUSE);
MOUSE_ClearButton(LEFT_MOUSE);
event.at0 = kMenuEventDown;
}
return event.at0 != kMenuEventNone;
}
CGameMenuItemSliderFloat::CGameMenuItemSliderFloat()
{
m_pzText = NULL;
m_nFont = -1;
m_nX = 0;
m_nY = 0;
fValue = 0;
fRangeLow = 0;
fStep = 0;
pCallback = NULL;
pValue = NULL;
nSliderTile = 2204;
nCursorTile = 2028;
nShowValue = kMenuSliderNone;
}
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)
{
m_pzText = _pzText;
m_nFont = _nFont;
m_nX = _nX;
m_nY = _nY;
m_nWidth = _nWidth;
fRangeLow = _fRangeLow;
fRangeHigh = _fRangeHigh;
fStep = _fStep;
fValue = ClipRangeF(_fValue, fRangeLow, fRangeHigh);
pCallback = _pCallback;
nSliderTile = 2204;
nCursorTile = 2028;
if (_nSliderTile >= 0)
nSliderTile = _nSliderTile;
if (_nCursorTile >= 0)
nCursorTile = _nCursorTile;
nShowValue = _nShowValue;
}
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)
{
m_pzText = _pzText;
m_nFont = _nFont;
m_nX = _nX;
m_nY = _nY;
m_nWidth = _nWidth;
fRangeLow = _fRangeLow;
fRangeHigh = _fRangeHigh;
fStep = _fStep;
dassert(pnValue != NULL);
pValue = pnValue;
fValue = ClipRangeF(*pnValue, fRangeLow, fRangeHigh);
pCallback = _pCallback;
nSliderTile = 2204;
nCursorTile = 2028;
if (_nSliderTile >= 0)
nSliderTile = _nSliderTile;
if (_nCursorTile >= 0)
nCursorTile = _nCursorTile;
nShowValue = _nShowValue;
}
void CGameMenuItemSliderFloat::Draw(void)
{
char buffer[16];
int height;
fValue = pValue ? *pValue : fValue;
gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
int shade = bEnable ? 32 : 48;
int shade2 = bEnable ? 0 : 16;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
if (m_pzText)
gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
int sliderX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x/2;
rotatesprite(sliderX<<16, (m_nY+height/2)<<16, 65536, 0, nSliderTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
float fRange = fRangeHigh - fRangeLow;
dassert(fRange > 0);
float value = fValue - fRangeLow;
int width = tilesiz[nSliderTile].x-8;
int cursorX = sliderX + (int)(ksgnf(fStep)*(value * width / fRange - width / 2));
rotatesprite(cursorX<<16, (m_nY+height/2)<<16, 65536, 0, nCursorTile, shade2, pal, 10, 0, 0, xdim-1, ydim-1);
buffer[0] = 0;
switch (nShowValue)
{
case kMenuSliderNone:
break;
case kMenuSliderValue:
snprintf(buffer, 16, "%.3f ", fValue);
break;
case kMenuSliderPercent:
snprintf(buffer, 16, "%.3f%% ", value*100.f/fRange);
break;
}
int valueWidth;
gMenuTextMgr.GetFontInfo(m_nFont, buffer, &valueWidth, NULL);
int valueX = m_nX+m_nWidth-1-tilesiz[nSliderTile].x-valueWidth;
gMenuTextMgr.DrawText(buffer, m_nFont, valueX, m_nY, 32, 0, false);
int mx = m_nX;
int my = m_nY;
int mw = m_nWidth;
int mh = height;
if (height < tilesiz[nSliderTile].y)
{
my -= (tilesiz[nSliderTile].y-height)/2;
height = tilesiz[nSliderTile].y;
}
mx <<= 16;
my <<= 16;
mw <<= 16;
mh <<= 16;
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
{
pMenu->SetFocusItem(this);
}
if (!gGameMenuMgr.m_mousecaught && (g_mouseClickState == MOUSE_PRESSED || g_mouseClickState == MOUSE_HELD))
{
pMenu->SetFocusItem(this);
int sliderx = m_nX+m_nWidth-1-tilesiz[nSliderTile].x;
int sliderwidth = tilesiz[nSliderTile].x;
int regionwidth = sliderwidth-8;
int regionx = sliderx+(sliderwidth-regionwidth)/2;
sliderx <<= 16;
sliderwidth <<= 16;
regionwidth <<= 16;
regionx <<= 16;
// region between the x-midline of the slidepoint at the extremes slides proportionally
if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, regionx, my, regionwidth, mh))
{
int dx = (gGameMenuMgr.m_mousepos.x - (regionx+regionwidth/2))*ksgnf(fStep);
fValue = fRangeLow + (dx+regionwidth/2) * fRange / regionwidth;
fValue = ClipRangeF(fValue, fRangeLow, fRangeHigh);
if (pCallback)
pCallback(this);
gGameMenuMgr.m_mousecaught = 1;
}
// region outside the x-midlines clamps to the extremes
else if (!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, sliderx, my, sliderwidth, mh))
{
if ((gGameMenuMgr.m_mousepos.x-(regionx+regionwidth/2))*ksgnf(fStep) > 0)
fValue = fRangeHigh;
else
fValue = fRangeLow;
if (pCallback)
pCallback(this);
gGameMenuMgr.m_mousecaught = 1;
}
}
}
}
bool CGameMenuItemSliderFloat::Event(CGameMenuEvent &event)
{
fValue = pValue ? *pValue : fValue;
switch (event.at0)
{
case kMenuEventUp:
pMenu->FocusPrevItem();
return false;
case kMenuEventDown:
pMenu->FocusNextItem();
return false;
case kMenuEventLeft:
if (fStep > 0)
fValue -= fStep;
else
fValue += fStep;
fValue = ClipRangeF(fValue, fRangeLow, fRangeHigh);
if (pCallback)
pCallback(this);
return false;
case kMenuEventRight:
if (fStep >= 0)
fValue += fStep;
else
fValue -= fStep;
fValue = ClipRangeF(fValue, fRangeLow, fRangeHigh);
if (pCallback)
pCallback(this);
return false;
case kMenuEventEnter:
if (pCallback)
pCallback(this);
return false;
}
return CGameMenuItem::Event(event);
}
CGameMenuItemZEdit::CGameMenuItemZEdit()
{
m_pzText = NULL;
m_nFont = -1;
m_nX = 0;
m_nY = 0;
at20 = NULL;
at24 = 0;
at32 = 0;
at2c = 0;
at30 = 0;
at28 = 0;
at31 = 1;
}
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)
{
at30 = 0;
at31 = 1;
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nWidth = a5;
at20 = a6;
at24 = a7;
at32 = a8;
at2c = a9;
at28 = a10;
}
void CGameMenuItemZEdit::AddChar(char ch)
{
int i = strlen(at20);
if (i + 1 < at24)
{
at20[i] = ch;
at20[i + 1] = 0;
}
}
void CGameMenuItemZEdit::BackChar(void)
{
int i = strlen(at20);
if (i > 0)
at20[i - 1] = 0;
}
void CGameMenuItemZEdit::Draw(void)
{
int height, width, textWidth = 0;
gMenuTextMgr.GetFontInfo(m_nFont, NULL, &width, &height);
if (at20)
gMenuTextMgr.GetFontInfo(m_nFont, at20, &textWidth, NULL);
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
if (at30)
shade = -128;
if (m_pzText)
gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
int x = m_nX+m_nWidth-1-textWidth;//(at24+1)*width;
if (at20 && *at20)
{
int width;
gMenuTextMgr.GetFontInfo(m_nFont, at20, &width, NULL);
int shade2;
if (at32)
{
if (at30)
shade2 = -128;
else
shade2 = shade;
}
else
{
if (at30)
shade2 = shade;
else
shade2 = 32;
}
gMenuTextMgr.DrawText(at20, m_nFont, x, m_nY, shade2, pal, false);
x += width;
}
if (at30 && (gGameClock & 32))
gMenuTextMgr.DrawText("_", m_nFont, x, m_nY, shade, 0, false);
int mx = m_nX<<16;
int my = m_nY<<16;
int mw = m_nWidth<<16;
int mh = height<<16;
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
{
pMenu->SetFocusItem(this);
}
if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
{
pMenu->SetFocusItem(this);
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
}
bool CGameMenuItemZEdit::Event(CGameMenuEvent &event)
{
static char buffer[256];
// Hack
if (event.at2 == sc_kpad_2 || event.at2 == sc_kpad_4 || event.at2 == sc_kpad_6 || event.at2 == sc_kpad_8)
event.at0 = kMenuEventKey;
switch (event.at0)
{
case kMenuEventEscape:
if (at30)
{
strncpy(at20, buffer, at24);
at20[at24-1] = 0;
at30 = 0;
return false;
}
return true;
case kMenuEventEnter:
if (!at31)
{
if (at2c)
at2c(this, &event);
return false;
}
if (at30)
{
if (at2c)
at2c(this, &event);
at30 = 0;
return false;
}
strncpy(buffer, at20, at24);
buffer[at24-1] = 0;
at30 = 1;
return false;
case kMenuEventBackSpace:
if (at30)
BackChar();
return false;
case kMenuEventKey:
case kMenuEventSpace:
{
char key;
if (event.at2 < 128)
{
if (keystatus[sc_LeftShift] || keystatus[sc_RightShift])
key = g_keyAsciiTableShift[event.at2];
else
key = g_keyAsciiTable[event.at2];
if (at30 && (isalnum(key) || ispunct(key) || isspace(key)))
{
AddChar(key);
return false;
}
}
return CGameMenuItem::Event(event);
}
case kMenuEventUp:
if (at30)
return false;
return CGameMenuItem::Event(event);
case kMenuEventDown:
if (at30)
return false;
return CGameMenuItem::Event(event);
}
return CGameMenuItem::Event(event);
}
CGameMenuItemZEditBitmap::CGameMenuItemZEditBitmap()
{
m_pzText = NULL;
m_nFont = -1;
m_nX = 0;
m_nY = 0;
at20 = NULL;
at24 = 0;
at36 = 0;
at30 = NULL;
at2c = NULL;
at34 = 0;
at28 = 0;
at37 = 0;
at35 = 1;
}
CGameMenuItemZEditBitmap::CGameMenuItemZEditBitmap(char *a1, int a2, int a3, int a4, int a5, char *a6, int a7, char a8, void(*a9)(CGameMenuItemZEditBitmap *, CGameMenuEvent *), int a10)
{
at2c = NULL;
at34 = 0;
at35 = 1;
at37 = 0;
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nWidth = a5;
at20 = a6;
at24 = a7;
at36 = a8;
at30 = a9;
at28 = a10;
}
void CGameMenuItemZEditBitmap::AddChar(char ch)
{
int i = strlen(at20);
if (i + 1 < at24)
{
at20[i] = ch;
at20[i + 1] = 0;
}
}
void CGameMenuItemZEditBitmap::BackChar(void)
{
int i = strlen(at20);
if (i > 0)
at20[i - 1] = 0;
}
void CGameMenuItemZEditBitmap::Draw(void)
{
int height, width;
gMenuTextMgr.GetFontInfo(m_nFont, NULL, &width, &height);
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
at2c->at24 = -1;
if (at34)
shade = -128;
if (m_pzText)
gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX, m_nY, shade, pal, false);
int x = m_nX+m_nWidth-1-(at24+1)*width;
if (at20 && *at20)
{
int width;
gMenuTextMgr.GetFontInfo(m_nFont, at20, &width, NULL);
int shade2;
if (at36)
{
if (at34)
shade2 = -128;
else
shade2 = shade;
}
else
{
if (at34)
shade2 = shade;
else
shade2 = 32;
}
gMenuTextMgr.DrawText(at20, m_nFont, x, m_nY, shade2, 0, false);
x += width;
}
if (at34 && (gGameClock & 32))
gMenuTextMgr.DrawText("_", m_nFont, x, m_nY, shade, pal, false);
int mx = m_nX<<16;
int my = m_nY<<16;
int mw = m_nWidth<<16;
int mh = height<<16;
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
{
pMenu->SetFocusItem(this);
}
if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
{
pMenu->SetFocusItem(this);
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
}
bool CGameMenuItemZEditBitmap::Event(CGameMenuEvent &event)
{
static char buffer[256];
// Hack
if (event.at2 == sc_kpad_2 || event.at2 == sc_kpad_4 || event.at2 == sc_kpad_6 || event.at2 == sc_kpad_8)
event.at0 = kMenuEventKey;
switch (event.at0)
{
case kMenuEventEscape:
if (at34)
{
strncpy(at20, buffer, at24);
at20[at24-1] = 0;
at34 = 0;
gSaveGameActive = false;
return false;
}
gSaveGameActive = true;
return true;
case kMenuEventEnter:
if (!at35)
{
if (at30)
at30(this, &event);
gSaveGameActive = false;
return false;
}
if (at34)
{
if (at30)
at30(this, &event);
at34 = 0;
gSaveGameActive = false;
return false;
}
strncpy(buffer, at20, at24);
if (at37)
at20[0] = 0;
buffer[at24-1] = 0;
at34 = 1;
return false;
case kMenuEventBackSpace:
if (at34)
BackChar();
return false;
case kMenuEventKey:
case kMenuEventSpace:
{
char key;
if (event.at2 < 128)
{
if (keystatus[sc_LeftShift] || keystatus[sc_RightShift])
key = g_keyAsciiTableShift[event.at2];
else
key = g_keyAsciiTable[event.at2];
if (at30 && (isalnum(key) || ispunct(key) || isspace(key)))
{
AddChar(key);
return false;
}
}
return CGameMenuItem::Event(event);
}
case kMenuEventUp:
if (at34)
return false;
return CGameMenuItem::Event(event);
case kMenuEventDown:
if (at34)
return false;
return CGameMenuItem::Event(event);
}
return CGameMenuItem::Event(event);
}
CGameMenuItemQAV::CGameMenuItemQAV()
{
at20 = NULL;
at24 = NULL;
at28 = 0;
bEnable = 0;
}
CGameMenuItemQAV::CGameMenuItemQAV(const char *a1, int a2, int a3, int a4, const char *a5, bool widescreen, bool clearbackground)
{
m_nWidth = 0;
m_pzText = a1;
m_nFont = a2;
m_nY = a4;
at20 = a5;
m_nX = a3;
bEnable = 0;
bWideScreen = widescreen;
bClearBackground = clearbackground;
}
void CGameMenuItemQAV::Draw(void)
{
if (bClearBackground)
videoClearScreen(0);
if (at24)
{
int backFC = gFrameClock;
gFrameClock = gGameClock;
int nTicks = totalclock.Ticks() - at30;
at30 = totalclock.Ticks();
at2c -= nTicks;
if (at2c <= 0 || at2c > at28->at10)
{
at2c = at28->at10;
}
at28->Play(at28->at10 - at2c - nTicks, at28->at10 - at2c, -1, NULL);
int wx1, wy1, wx2, wy2;
wx1 = windowxy1.x;
wy1 = windowxy1.y;
wx2 = windowxy2.x;
wy2 = windowxy2.y;
windowxy1.x = 0;
windowxy1.y = 0;
windowxy2.x = xdim-1;
windowxy2.y = ydim-1;
if (bWideScreen)
{
int xdim43 = scale(ydim, 4, 3);
int nCount = (xdim+xdim43-1)/xdim43;
int backX = at28->x;
for (int i = 0; i < nCount; i++)
{
at28->Draw(at28->at10 - at2c, 10+kQavOrientationLeft, 0, 0);
at28->x += 320;
}
at28->x = backX;
}
else
at28->Draw(at28->at10 - at2c, 10, 0, 0);
windowxy1.x = wx1;
windowxy1.y = wy1;
windowxy2.x = wx2;
windowxy2.y = wy2;
gFrameClock = backFC;
}
if (bEnable && !gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED)
{
pMenu->SetFocusItem(this);
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
bool CGameMenuItemQAV::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventLeft:
case kMenuEventBackSpace:
pMenu->FocusPrevItem();
return false;
case kMenuEventRight:
case kMenuEventEnter:
case kMenuEventSpace:
pMenu->FocusNextItem();
return false;
case kMenuEventInit:
if (at20)
{
if (!at28)
{
at24 = gSysRes.Lookup(at20, "QAV");
if (!at24)
ThrowError("Could not load QAV %s\n", at20);
at28 = (QAV*)gSysRes.Lock(at24);
at28->nSprite = -1;
at28->x = m_nX;
at28->y = m_nY;
at28->Preload();
at2c = at28->at10;
at30 = totalclock.Ticks();
return false;
}
gSysRes.Lock(at24);
}
return false;
case kMenuEventDeInit:
if (at20 && at28)
{
gSysRes.Unlock(at24);
if (at24->lockCount == 0)
at28 = NULL;
}
return false;
}
return CGameMenuItem::Event(event);
}
void CGameMenuItemQAV::Reset(void)
{
at2c = at28->at10;
at30 = totalclock.Ticks();
}
CGameMenuItemZCycleSelect::CGameMenuItemZCycleSelect()
{
m_pzText = NULL;
m_nFont = 3;
m_nX = 0;
m_nY = 0;
m_nRows = 0;
m_nTopDelta = 0;
m_nFocus = 0;
m_nItems = 0;
m_pzStrings = NULL;
m_pReturn = NULL;
}
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 *))
{
m_nTopDelta = 0;
m_nFocus = 0;
m_pzText = pzText;
m_nFont = nFont;
m_nX = nX;
m_nY = nY;
m_nWidth = nWidth;
m_nRows = nRows;
m_pCallback = pCallback;
m_nItems = nItems;
m_pzStrings = pzStrings;
m_pReturn = pReturn;
}
void CGameMenuItemZCycleSelect::Draw(void)
{
int height;
int shade;
gMenuTextMgr.GetFontInfo(m_nFont, NULL, NULL, &height);
int y = m_nY;
int k = m_nFocus - m_nTopDelta;
int nNewFocus = m_nFocus;
bool bClick = false;
for (int i = 0; i < m_nRows; i++, y += height, k++)
{
if (k == m_nFocus)
{
shade = 32;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
viewDrawText(3, m_pzStrings[k], m_nX, y, shade, 0, 0, false);
}
else
{
viewDrawText(3, m_pzStrings[k], m_nX, y, 24, 0, 0, false);
}
int mx = m_nX<<16;
int my = y<<16;
int mw = m_nWidth<<16;
int mh = height<<16;
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, mx, my, mw, mh)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, mx, my, mw, mh)))
{
nNewFocus = k;
}
if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, mx, my, mw, mh))
{
nNewFocus = k;
bClick = true;
}
}
}
m_nTopDelta += nNewFocus-m_nFocus;
m_nFocus = nNewFocus;
if (bClick)
{
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
bool CGameMenuItemZCycleSelect::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventUp:
if (event.at2 == sc_Tab || m_nFocus == 0)
{
pMenu->FocusPrevItem();
return false;
}
m_nFocus--;
if (m_nTopDelta > 0)
m_nTopDelta--;
return false;
case kMenuEventDown:
if (event.at2 == sc_Tab || m_nFocus == m_nItems-1)
{
pMenu->FocusNextItem();
return false;
}
m_nFocus++;
if (m_nTopDelta+1 < m_nRows)
m_nTopDelta++;
return false;
case kMenuEventEnter:
if (m_pCallback)
m_pCallback(this);
*m_pReturn = m_nFocus;
return true;
case kMenuEventScrollUp:
if (m_nFocus-m_nTopDelta > 0)
{
m_nTopDelta++;
if (m_nTopDelta>0)
{
m_nFocus--;
m_nTopDelta--;
}
}
return false;
case kMenuEventScrollDown:
if (m_nFocus-m_nTopDelta+m_nRows < m_nItems)
{
m_nTopDelta--;
if (m_nTopDelta+1 < m_nRows)
{
m_nFocus++;
m_nTopDelta++;
}
}
return false;
}
return CGameMenuItem::Event(event);
}
bool CGameMenuItemZCycleSelect::MouseEvent(CGameMenuEvent &event)
{
event.at0 = kMenuEventNone;
if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELUP_MOUSE))
{
gGameMenuMgr.m_mouselastactivity = totalclock.Ticks();
MOUSE_ClearButton(WHEELUP_MOUSE);
event.at0 = kMenuEventScrollUp;
}
else if (MOUSEACTIVECONDITIONAL(MOUSE_GetButtons()&WHEELDOWN_MOUSE))
{
gGameMenuMgr.m_mouselastactivity = totalclock.Ticks();
MOUSE_ClearButton(WHEELDOWN_MOUSE);
event.at0 = kMenuEventScrollDown;
}
else
return CGameMenuItem::MouseEvent(event);
return event.at0 != kMenuEventNone;
}
CGameMenuItemZCycle::CGameMenuItemZCycle()
{
m_pzText = NULL;
m_nFocus = 0;
m_nItems = 0;
m_pCallback = NULL;
m_pCallbackSelect = NULL;
m_pMenuSelect = NULL;
m_pItemSelectTitle = NULL;
m_pItemSelect = NULL;
m_nMenuSelectReturn = -1;
}
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*))
{
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nFocus = 0;
m_nWidth = a5;
m_nAlign = a6;
m_pCallback = a7;
m_pCallbackSelect = pCallbackSelect;
m_nItems = 0;
m_bMenu = bMenu;
m_pMenuSelect = NULL;
m_pItemSelectTitle = NULL;
m_pItemSelect = NULL;
m_nMenuSelectReturn = -1;
SetTextArray(a8, a9, a10);
}
CGameMenuItemZCycle::~CGameMenuItemZCycle()
{
m_pzText = NULL;
m_nFocus = 0;
m_nItems = 0;
m_pCallback = NULL;
m_pCallbackSelect = NULL;
m_pMenuSelect = NULL;
m_pItemSelectTitle = NULL;
m_pItemSelect = NULL;
m_nMenuSelectReturn = -1;
memset(m_pzStrings, 0, sizeof(m_pzStrings));
}
void CGameMenuItemZCycle::Draw(void)
{
int width = 0, height = 0;
int shade = bEnable ? 32 : 48;
int pal = bEnable ? 0 : 5;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
int x = m_nX;
int y = m_nY;
if (m_nMenuSelectReturn != -1)
{
m_nFocus = m_nMenuSelectReturn;
if (m_pCallback)
m_pCallback(this);
m_nMenuSelectReturn = -1;
}
if (m_pzText)
{
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, &height);
switch (m_nAlign)
{
case 1:
x = m_nX+m_nWidth/2-width/2;
break;
case 2:
x = m_nX+m_nWidth-1-width;
break;
case 0:
default:
break;
}
gMenuTextMgr.DrawText(m_pzText, m_nFont, x, y, shade, pal, false);
}
const char *pzText;
if (!m_nItems)
pzText = "????";
else
pzText = m_pzStrings[m_nFocus];
dassert(pzText != NULL);
gMenuTextMgr.GetFontInfo(m_nFont, pzText, &width, NULL);
gMenuTextMgr.DrawText(pzText, m_nFont, m_nX + m_nWidth - 1 - width, y, shade, pal, false);
if (bEnable && MOUSEACTIVECONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousepos, x<<16, y<<16, m_nWidth<<16, height<<16)))
{
if (MOUSEWATCHPOINTCONDITIONAL(!gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_prevmousepos, x<<16, y<<16, m_nWidth<<16, height<<16)))
{
pMenu->SetFocusItem(this);
}
if (!gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED && !gGameMenuMgr.MouseOutsideBounds(&gGameMenuMgr.m_mousedownpos, x<<16, y<<16, m_nWidth<<16, height<<16))
{
pMenu->SetFocusItem(this);
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
}
bool CGameMenuItemZCycle::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventEnter:
if (m_bMenu)
{
if (m_pMenuSelect)
{
delete m_pMenuSelect;
m_pMenuSelect = NULL;
}
if (m_pItemSelectTitle)
{
delete m_pItemSelectTitle;
m_pItemSelectTitle = NULL;
}
if (m_pItemSelect)
{
delete m_pItemSelect;
m_pItemSelect = NULL;
}
m_pMenuSelect = new CGameMenu();
dassert(m_pMenuSelect != NULL);
strncpy(m_zTitle, m_pzText, kMaxTitleLength);
int l = strlen(m_zTitle);
if (l > 0 && m_zTitle[l-1] == ':')
l--;
m_zTitle[l] = 0;
m_pItemSelectTitle = new CGameMenuItemTitle(m_zTitle, 1, 160, 20, 2038);
dassert(m_pItemSelectTitle != NULL);
m_pItemSelect = new CGameMenuItemZCycleSelect("", 3, 100, 40, 100, 16, m_nItems, m_pzStrings, &m_nMenuSelectReturn, m_pCallbackSelect);
dassert(m_pItemSelect != NULL);
m_pMenuSelect->Add(m_pItemSelectTitle, false);
m_pMenuSelect->Add(m_pItemSelect, true);
m_pMenuSelect->Add(&itemBloodQAV, false);
gGameMenuMgr.Push(m_pMenuSelect, -1);
return false;
}
fallthrough__;
case kMenuEventRight:
case kMenuEventSpace:
Next();
if (m_pCallback)
m_pCallback(this);
return false;
case kMenuEventLeft:
Prev();
if (m_pCallback)
m_pCallback(this);
return false;
case kMenuEventDeInit:
if (m_pMenuSelect)
{
delete m_pMenuSelect;
m_pMenuSelect = NULL;
}
if (m_pItemSelectTitle)
{
delete m_pItemSelectTitle;
m_pItemSelectTitle = NULL;
}
if (m_pItemSelect)
{
delete m_pItemSelect;
m_pItemSelect = NULL;
}
return false;
}
return CGameMenuItem::Event(event);
}
void CGameMenuItemZCycle::Add(const char *pItem, bool active)
{
dassert(pItem != NULL);
dassert(m_nItems < kMaxGameCycleItems);
m_pzStrings[m_nItems] = pItem;
if (active)
m_nFocus = m_nItems;
m_nItems++;
}
void CGameMenuItemZCycle::Next(void)
{
if (m_nItems > 0)
{
m_nFocus++;
if (m_nFocus >= m_nItems)
m_nFocus = 0;
}
}
void CGameMenuItemZCycle::Prev(void)
{
if (m_nItems > 0)
{
m_nFocus--;
if (m_nFocus < 0)
m_nFocus += m_nItems;
}
}
void CGameMenuItemZCycle::Clear(void)
{
m_nItems = m_nFocus = 0;
memset(m_pzStrings, 0, sizeof(m_pzStrings));
}
void CGameMenuItemZCycle::SetTextArray(const char **pTextArray, int nTextPtrCount, int nIndex)
{
Clear();
dassert(nTextPtrCount <= kMaxGameCycleItems);
for (int i = 0; i < nTextPtrCount; i++)
Add(pTextArray[i], false);
SetTextIndex(nIndex);
}
void CGameMenuItemZCycle::SetTextIndex(int nIndex)
{
m_nFocus = ClipRange(nIndex, 0, m_nItems);
}
CGameMenuItemYesNoQuit::CGameMenuItemYesNoQuit()
{
m_pzText = NULL;
m_nRestart = 0;
}
CGameMenuItemYesNoQuit::CGameMenuItemYesNoQuit(const char *a1, int a2, int a3, int a4, int a5, int a6, int a7)
{
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
m_nWidth = a5;
at20 = a6;
m_nRestart = a7;
}
void CGameMenuItemYesNoQuit::Draw(void)
{
if (!m_pzText) return;
int shade = 32;
if (pMenu->IsFocusItem(this))
shade = 32-(totalclock.Ticks() &63);
int width;
int x = m_nX;
switch (at20)
{
case 1:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX+m_nWidth/2-width/2;
break;
case 2:
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
x = m_nX+m_nWidth-1-width;
break;
case 0:
default:
break;
}
gMenuTextMgr.DrawText(m_pzText, m_nFont, x, m_nY, shade, 0, true);
if (bEnable && !gGameMenuMgr.m_mousecaught && g_mouseClickState == MOUSE_RELEASED)
{
pMenu->SetFocusItem(this);
CGameMenuEvent event = { kMenuEventEnter, 0 };
gGameMenuMgr.m_mousecaught = 1;
if (Event(event))
gGameMenuMgr.PostPop();
}
}
extern void Restart(CGameMenuItemChain *pItem);
extern void Quit(CGameMenuItemChain *pItem);
bool CGameMenuItemYesNoQuit::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventKey:
if (event.at2 == sc_Y)
{
if (m_nRestart)
Restart(NULL);
else
Quit(NULL);
}
else if (event.at2 == sc_N)
gGameMenuMgr.Pop();
return false;
case kMenuEventEnter:
if (m_nRestart)
Restart(NULL);
else
Quit(NULL);
return false;
}
return CGameMenuItem::Event(event);
}
CGameMenuItemPicCycle::CGameMenuItemPicCycle()
{
m_pzText = NULL;
at24 = 0;
m_nItems = 0;
atb0 = 0;
at2c = 0;
atb4 = 0;
}
CGameMenuItemPicCycle::CGameMenuItemPicCycle(int a1, int a2, void(*a3)(CGameMenuItemPicCycle *), int *a4, int a5, int a6)
{
m_nWidth = 0;
at24 = 0;
m_nItems = 0;
m_nX = a1;
m_nY = a2;
atb0 = a3;
atb4 = 0;
SetPicArray(a4, a5, a6);
}
void CGameMenuItemPicCycle::Draw(void)
{
videoSetViewableArea(0, 0, xdim - 1, ydim - 1);
if (atb4)
rotatesprite(0, 0, 65536, 0, atb4, 0, 0, 82, 0, 0, xdim - 1, ydim - 1);
if (at30[at24])
rotatesprite(0, 0, 65536, 0, at30[at24], 0, 0, 82, 0, 0, xdim - 1, ydim - 1);
}
bool CGameMenuItemPicCycle::Event(CGameMenuEvent &event)
{
switch (event.at0)
{
case kMenuEventRight:
case kMenuEventEnter:
case kMenuEventSpace:
Next();
if (atb0)
atb0(this);
return false;
case kMenuEventLeft:
Prev();
if (atb0)
atb0(this);
return false;
}
return CGameMenuItem::Event(event);
}
void CGameMenuItemPicCycle::Add(int nItem, bool active)
{
dassert(m_nItems < kMaxPicCycleItems);
at30[m_nItems] = nItem;
if (active)
at24 = m_nItems;
m_nItems++;
}
void CGameMenuItemPicCycle::Next(void)
{
if (m_nItems > 0)
{
at24++;
if (at24 >= m_nItems)
at24 = 0;
}
}
void CGameMenuItemPicCycle::Prev(void)
{
if (m_nItems > 0)
{
at24--;
if (at24 < 0)
at24 += m_nItems;
}
}
void CGameMenuItemPicCycle::Clear(void)
{
m_nItems = at24 = 0;
memset(at30, 0, sizeof(at30));
at2c = 0;
}
void CGameMenuItemPicCycle::SetPicArray(int *pArray, int nTileCount, int nIndex)
{
Clear();
at2c = 0;
dassert(nTileCount <= kMaxPicCycleItems);
for (int i = 0; i < nTileCount; i++)
Add(pArray[i], false);
SetPicIndex(nIndex);
}
void CGameMenuItemPicCycle::SetPicIndex(int nIndex)
{
at24 = ClipRange(nIndex, 0, m_nItems);
}
CGameMenuItemPassword::CGameMenuItemPassword()
{
at37 = 0;
m_pzText = NULL;
at36 = 0;
at32 = 0;
at5b = 0;
}
CGameMenuItemPassword::CGameMenuItemPassword(const char *a1, int a2, int a3, int a4)
{
at37 = 0;
m_nWidth = 0;
at36 = 0;
at32 = 0;
at5b = 0;
m_pzText = a1;
m_nFont = a2;
m_nX = a3;
m_nY = a4;
}
const char *kCheckPasswordMsg = "ENTER PASSWORD: ";
const char *kOldPasswordMsg = "ENTER OLD PASSWORD: ";
const char *kNewPasswordMsg = "ENTER NEW PASSWORD: ";
const char *kInvalidPasswordMsg = "INVALID PASSWORD.";
void CGameMenuItemPassword::Draw(void)
{
bool focus = pMenu->IsFocusItem(this);
int shade = 32;
int shadef = 32-(totalclock.Ticks() &63);
int width;
switch (at37)
{
case 1:
case 2:
case 3:
switch (at37)
{
case 1:
strcpy(at3b, kCheckPasswordMsg);
break;
case 2:
strcpy(at3b, kOldPasswordMsg);
break;
case 3:
strcpy(at3b, kNewPasswordMsg);
break;
}
for (int i = 0; i < at32; i++)
strcat(at3b, "*");
strcat(at3b, "_");
gMenuTextMgr.GetFontInfo(m_nFont, at3b, &width, NULL);
gMenuTextMgr.DrawText(at3b, m_nFont, m_nX-width/2, m_nY+20, shadef, 0, false);
shadef = 32;
break;
case 4:
if ((totalclock.Ticks() - at5b) & 32)
{
gMenuTextMgr.GetFontInfo(m_nFont, kInvalidPasswordMsg, &width, NULL);
gMenuTextMgr.DrawText(kInvalidPasswordMsg, m_nFont, m_nX - width / 2, m_nY + 20, shade, 0, false);
}
if (at5b && totalclock.Ticks() -at5b > 256)
{
at5b = 0;
at37 = 0;
}
break;
}
gMenuTextMgr.GetFontInfo(m_nFont, m_pzText, &width, NULL);
gMenuTextMgr.DrawText(m_pzText, m_nFont, m_nX-width/2, m_nY, focus ? shadef : shade, 0, false);
}
bool CGameMenuItemPassword::Event(CGameMenuEvent &event)
{
switch (at37)
{
case 0:
case 4:
if (event.at0 == kMenuEventEnter)
{
at29[0] = 0;
if (strcmp(at20, ""))
at37 = 2;
else
at37 = 3;
return false;
}
return CGameMenuItem::Event(event);
case 1:
case 2:
case 3:
switch (event.at0)
{
case kMenuEventEnter:
switch (at37)
{
case 1:
at36 = strcmp(at20,at29) == 0;
if (at36)
at37 = 0;
else
at37 = 4;
if (!at36)
{
at5b = totalclock.Ticks();
pMenu->FocusPrevItem();
}
else
{
at5f->at20 = 0;
at5f->Draw();
gbAdultContent = false;
// NUKE-TODO:
//CONFIG_WriteAdultMode();
pMenu->FocusPrevItem();
}
return false;
case 2:
at36 = strcmp(at20,at29) == 0;
if (at36)
at37 = 0;
else
at37 = 4;
if (at36)
{
strcpy(at20, "");
strcpy(gzAdultPassword, "");
// NUKE-TODO:
//CONFIG_WriteAdultMode();
at37 = 0;
}
else
at5b = totalclock.Ticks();
return false;
case 3:
strcpy(at20, at29);
strcpy(at20, gzAdultPassword);
strcpy(gzAdultPassword, "");
// NUKE-TODO:
//CONFIG_WriteAdultMode();
at37 = 0;
return false;
}
break;
case kMenuEventEscape:
at37 = 0;
Draw();
return false;
case kMenuEventKey:
if (at32 < 8)
{
char key = Btoupper(g_keyAsciiTable[event.at2]);
if (isalnum(key) || ispunct(key) || isspace(key))
{
at29[at32++] = key;
at29[at32] = 0;
}
}
return false;
case kMenuEventBackSpace:
if (at32 > 0)
at29[--at32] = 0;
return false;
case kMenuEventLeft:
case kMenuEventRight:
case kMenuEventSpace:
return false;
}
}
return CGameMenuItem::Event(event);
}