Merge remote-tracking branch 'gzdoom/master' into qzdoom

# Conflicts:
#	src/v_video.cpp
This commit is contained in:
Magnus Norddahl 2017-02-19 03:49:13 +01:00
commit 42a7dbe33a
41 changed files with 2100 additions and 2498 deletions

View file

@ -922,15 +922,12 @@ set( FASTMATH_PCH_SOURCES
intermission/intermission.cpp
intermission/intermission_parse.cpp
menu/joystickmenu.cpp
menu/listmenu.cpp
menu/loadsavemenu.cpp
menu/menu.cpp
menu/menudef.cpp
menu/menuinput.cpp
menu/messagebox.cpp
menu/optionmenu.cpp
menu/playermenu.cpp
menu/readthis.cpp
menu/videomenu.cpp
oplsynth/fmopl.cpp
oplsynth/mlopl.cpp

View file

@ -207,7 +207,7 @@ DEFINE_ACTION_FUNCTION(_CVar, SetInt)
{
// Only menus are allowed to change CVARs.
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
if (!(self->GetFlags() & CVAR_MOD) && DMenu::CurrentMenu == nullptr) return 0;
if (!(self->GetFlags() & CVAR_MOD) && CurrentMenu == nullptr) return 0;
PARAM_INT(val);
UCVarValue v;
v.Int = val;
@ -219,7 +219,7 @@ DEFINE_ACTION_FUNCTION(_CVar, SetFloat)
{
// Only menus are allowed to change CVARs.
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
if (!(self->GetFlags() & CVAR_MOD) && DMenu::CurrentMenu == nullptr) return 0;
if (!(self->GetFlags() & CVAR_MOD) && CurrentMenu == nullptr) return 0;
PARAM_FLOAT(val);
UCVarValue v;
v.Float = (float)val;
@ -231,7 +231,7 @@ DEFINE_ACTION_FUNCTION(_CVar, SetString)
{
// Only menus are allowed to change CVARs.
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
if (!(self->GetFlags() & CVAR_MOD) && DMenu::CurrentMenu == nullptr) return 0;
if (!(self->GetFlags() & CVAR_MOD) && CurrentMenu == nullptr) return 0;
PARAM_STRING(val);
UCVarValue v;
v.String = val.GetChars();

View file

@ -666,7 +666,7 @@ void C_DoCommand (const char *cmd, int keynum)
// This is only accessible to the special menu item to run CCMDs.
DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand)
{
if (DMenu::CurrentMenu == nullptr) return 0;
if (CurrentMenu == nullptr) return 0;
PARAM_PROLOGUE;
PARAM_STRING(cmd);
C_DoCommand(cmd);

View file

@ -95,23 +95,6 @@ char *copystring (const char *s)
return b;
}
//============================================================================
//
// ncopystring
//
// If the string has no content, returns NULL. Otherwise, returns a copy.
//
//============================================================================
char *ncopystring (const char *string)
{
if (string == NULL || string[0] == 0)
{
return NULL;
}
return copystring (string);
}
//==========================================================================
//
// ReplaceString

View file

@ -38,7 +38,6 @@ int ParseHex(const char *str, FScriptPosition *sc = nullptr);
bool IsNum (const char *str); // [RH] added
char *copystring(const char *s);
char *ncopystring(const char *s);
void ReplaceString (char **ptr, const char *str);
bool CheckWildcards (const char *pattern, const char *text);

View file

@ -73,7 +73,7 @@ EXTERN_CVAR (Int, autosavecount)
#define SIMULATEERRORS 0
extern BYTE *demo_p; // [RH] Special "ticcmds" get recorded in demos
extern char savedescription[SAVESTRINGSIZE];
extern FString savedescription;
extern FString savegamefile;
extern short consistancy[MAXPLAYERS][BACKUPTICS];
@ -2418,8 +2418,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
savegamefile = s;
delete[] s;
s = ReadString (stream);
memset (savedescription, 0, sizeof(savedescription));
strncpy (savedescription, s, sizeof(savedescription));
savedescription = s;
if (player != consoleplayer)
{
// Paths sent over the network will be valid for the system that sent

View file

@ -226,7 +226,7 @@ int mousex;
int mousey;
FString savegamefile;
char savedescription[SAVESTRINGSIZE];
FString savedescription;
// [RH] Name of screenshot file to generate (usually NULL)
FString shotfile;
@ -1081,7 +1081,7 @@ void G_Ticker ()
G_DoSaveGame (true, savegamefile, savedescription);
gameaction = ga_nothing;
savegamefile = "";
savedescription[0] = '\0';
savedescription = "";
break;
case ga_autosave:
G_DoAutoSave ();
@ -2068,8 +2068,7 @@ void G_SaveGame (const char *filename, const char *description)
else
{
savegamefile = filename;
strncpy (savedescription, description, sizeof(savedescription)-1);
savedescription[sizeof(savedescription)-1] = '\0';
savedescription = description;
sendsave = true;
}
}
@ -2119,7 +2118,7 @@ extern void P_CalcHeight (player_t *);
void G_DoAutoSave ()
{
char description[SAVESTRINGSIZE];
FString description;
FString file;
// Keep up to four autosaves at a time
UCVarValue num;
@ -2147,10 +2146,7 @@ void G_DoAutoSave ()
}
readableTime = myasctime ();
strcpy (description, "Autosave ");
strncpy (description+9, readableTime+4, 12);
description[9+12] = 0;
description.Format("Autosave %.12s", readableTime + 4);
G_DoSaveGame (false, file, description);
}
@ -2310,7 +2306,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
WriteZip(filename, savegame_filenames, savegame_content);
savegameManager.NotifyNewSave (filename.GetChars(), description, okForQuicksave);
savegameManager.NotifyNewSave (filename, description, okForQuicksave);
// delete the JSON buffers we created just above. Everything else will
// either still be needed or taken care of automatically.

View file

@ -1462,6 +1462,7 @@ void G_InitLevelLocals ()
level.LevelName = level.info->LookupLevelName();
level.NextMap = info->NextMap;
level.NextSecretMap = info->NextSecretMap;
level.F1Pic = info->F1Pic;
compatflags.Callback();
compatflags2.Callback();
@ -1910,6 +1911,7 @@ DEFINE_FIELD(FLevelLocals, LevelName)
DEFINE_FIELD(FLevelLocals, MapName)
DEFINE_FIELD(FLevelLocals, NextMap)
DEFINE_FIELD(FLevelLocals, NextSecretMap)
DEFINE_FIELD(FLevelLocals, F1Pic)
DEFINE_FIELD(FLevelLocals, maptype)
DEFINE_FIELD(FLevelLocals, Music)
DEFINE_FIELD(FLevelLocals, musicorder)

View file

@ -25,6 +25,7 @@ struct FLevelLocals
FString MapName; // the lump name (E1M1, MAP01, etc)
FString NextMap; // go here when using the regular exit
FString NextSecretMap; // map to go to when used secret exit
FString F1Pic;
EMapType maptype;
TStaticArray<vertex_t> vertexes;

View file

@ -1970,6 +1970,7 @@ static void ClearMapinfo()
DefaultSkill = -1;
DeinitIntermissions();
level.info = NULL;
level.F1Pic = "";
}
//==========================================================================

View file

@ -51,6 +51,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, infoPages)
const char *GameNames[17] =

View file

@ -186,12 +186,12 @@ void UpdateJoystickMenu(IJoystickConfig *selected)
{
opt->mSelectedItem = opt->mItems.Size() - 1;
}
opt->CalcIndent();
//opt->CalcIndent();
// If the joystick config menu is open, close it if the device it's open for is gone.
if (DMenu::CurrentMenu != nullptr && (DMenu::CurrentMenu->IsKindOf("JoystickConfigMenu")))
if (CurrentMenu != nullptr && (CurrentMenu->IsKindOf("JoystickConfigMenu")))
{
auto p = DMenu::CurrentMenu->PointerVar<IJoystickConfig>("mJoy");
auto p = CurrentMenu->PointerVar<IJoystickConfig>("mJoy");
if (p != nullptr)
{
unsigned i;
@ -204,7 +204,7 @@ void UpdateJoystickMenu(IJoystickConfig *selected)
}
if (i == Joysticks.Size())
{
DMenu::CurrentMenu->Close();
CurrentMenu->Close();
}
}
}

View file

@ -1,281 +0,0 @@
/*
** listmenu.cpp
** A simple menu consisting of a list of items
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "v_video.h"
#include "v_font.h"
#include "cmdlib.h"
#include "gstrings.h"
#include "g_level.h"
#include "gi.h"
#include "d_gui.h"
#include "d_event.h"
#include "menu/menu.h"
IMPLEMENT_CLASS(DListMenu, false, false)
IMPLEMENT_POINTERS_START(DListMenu)
IMPLEMENT_POINTER(mFocusControl)
IMPLEMENT_POINTERS_END
//=============================================================================
//
//
//
//=============================================================================
DListMenu::DListMenu(DMenu *parent, DListMenuDescriptor *desc)
: DMenu(parent)
{
mDesc = NULL;
if (desc != NULL) Init(parent, desc);
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu::Init(DMenu *parent, DListMenuDescriptor *desc)
{
mParentMenu = parent;
GC::WriteBarrier(this, parent);
mDesc = desc;
if (desc->mCenter)
{
int center = 160;
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
int xpos = mDesc->mItems[i]->GetX();
int width = mDesc->mItems[i]->GetWidth();
int curx = mDesc->mSelectOfsX;
if (width > 0 && mDesc->mItems[i]->Selectable())
{
int left = 160 - (width - curx) / 2 - curx;
if (left < center) center = left;
}
}
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
int width = mDesc->mItems[i]->GetWidth();
if (width > 0)
{
mDesc->mItems[i]->SetX(center);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
DMenuItemBase *DListMenu::GetItem(FName name)
{
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
FName nm = mDesc->mItems[i]->GetAction(NULL);
if (nm == name) return mDesc->mItems[i];
}
return NULL;
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu::Responder (event_t *ev)
{
if (ev->type == EV_GUI_Event)
{
if (ev->subtype == EV_GUI_KeyDown)
{
int ch = tolower (ev->data1);
for(unsigned i = mDesc->mSelectedItem + 1; i < mDesc->mItems.Size(); i++)
{
if (mDesc->mItems[i]->CheckHotkey(ch))
{
mDesc->mSelectedItem = i;
S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
}
}
for(int i = 0; i < mDesc->mSelectedItem; i++)
{
if (mDesc->mItems[i]->CheckHotkey(ch))
{
mDesc->mSelectedItem = i;
S_Sound(CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
}
}
}
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu::MenuEvent (int mkey, bool fromcontroller)
{
int oldSelect = mDesc->mSelectedItem;
int startedAt = mDesc->mSelectedItem;
if (startedAt < 0) startedAt = 0;
switch (mkey)
{
case MKEY_Up:
do
{
if (--mDesc->mSelectedItem < 0) mDesc->mSelectedItem = mDesc->mItems.Size()-1;
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
if (mDesc->mSelectedItem == startedAt) mDesc->mSelectedItem = oldSelect;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
case MKEY_Down:
do
{
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size()) mDesc->mSelectedItem = 0;
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
if (mDesc->mSelectedItem == startedAt) mDesc->mSelectedItem = oldSelect;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
return true;
case MKEY_Enter:
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate())
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
}
return true;
default:
return Super::MenuEvent(mkey, fromcontroller);
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu::MouseEvent(int type, int x, int y)
{
int sel = -1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
if (mFocusControl != NULL)
{
mFocusControl->MouseEvent(type, x, y);
return true;
}
else
{
if ((mDesc->mWLeft <= 0 || x > mDesc->mWLeft) &&
(mDesc->mWRight <= 0 || x < mDesc->mWRight))
{
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
if (mDesc->mItems[i]->CheckCoordinate(x, y))
{
if ((int)i != mDesc->mSelectedItem)
{
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
mDesc->mSelectedItem = i;
mDesc->mItems[i]->MouseEvent(type, x, y);
return true;
}
}
}
}
mDesc->mSelectedItem = -1;
return Super::MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu::Ticker ()
{
Super::Ticker();
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
mDesc->mItems[i]->Ticker();
}
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu::Drawer ()
{
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
if (mDesc->mItems[i]->mEnabled) mDesc->mItems[i]->Drawer(mDesc->mSelectedItem == (int)i);
}
if (mDesc->mSelectedItem >= 0 && mDesc->mSelectedItem < (int)mDesc->mItems.Size())
mDesc->mItems[mDesc->mSelectedItem]->DrawSelector(mDesc->mSelectOfsX, mDesc->mSelectOfsY, mDesc->mSelector);
Super::Drawer();
}
//=============================================================================
//
// base class for menu items
//
//=============================================================================
IMPLEMENT_CLASS(DMenuItemBase, false, false)

File diff suppressed because it is too large Load diff

View file

@ -63,24 +63,23 @@
CVAR (Float, mouse_sensitivity, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, show_messages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, show_obituaries, true, CVAR_ARCHIVE)
CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR (Float, snd_menuvolume, 0.6f, CVAR_ARCHIVE)
CVAR(Int, m_use_mouse, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Int, m_show_backbutton, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
DMenu *DMenu::CurrentMenu;
DEFINE_ACTION_FUNCTION(DMenu, GetCurrentMenu)
{
ACTION_RETURN_OBJECT(DMenu::CurrentMenu);
ACTION_RETURN_OBJECT(CurrentMenu);
}
int DMenu::MenuTime;
DEFINE_ACTION_FUNCTION(DMenu, MenuTime)
{
ACTION_RETURN_INT(DMenu::MenuTime);
ACTION_RETURN_INT(MenuTime);
}
FGameStartup GameStartupInfo;
@ -92,6 +91,8 @@ bool MenuButtonOrigin[NUM_MKEYS];
int BackbuttonTime;
float BackbuttonAlpha;
static bool MenuEnabled = true;
DMenu *CurrentMenu;
int MenuTime;
void M_InitVideoModes();
extern PClass *DefaultListMenuClass;
@ -140,7 +141,7 @@ void M_MarkMenus()
{
GC::Mark(pair->Value);
}
GC::Mark(DMenu::CurrentMenu);
GC::Mark(CurrentMenu);
}
//============================================================================
//
@ -237,7 +238,7 @@ bool DMenu::MenuEvent (int mkey, bool fromcontroller)
{
Close();
S_Sound (CHAN_VOICE | CHAN_UI,
DMenu::CurrentMenu != nullptr? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE);
CurrentMenu != nullptr? "menu/backup" : "menu/clear", snd_menuvolume, ATTN_NONE);
return true;
}
}
@ -272,13 +273,13 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller)
void DMenu::Close ()
{
if (DMenu::CurrentMenu == nullptr) return; // double closing can happen in the save menu.
assert(DMenu::CurrentMenu == this);
DMenu::CurrentMenu = mParentMenu;
if (CurrentMenu == nullptr) return; // double closing can happen in the save menu.
assert(CurrentMenu == this);
CurrentMenu = mParentMenu;
Destroy();
if (DMenu::CurrentMenu != nullptr)
if (CurrentMenu != nullptr)
{
GC::WriteBarrier(DMenu::CurrentMenu);
GC::WriteBarrier(CurrentMenu);
}
else
{
@ -401,7 +402,7 @@ void DMenu::CallTicker()
void DMenu::Drawer ()
{
if (this == DMenu::CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse)
if (this == CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse)
{
FTexture *tex = TexMan(gameinfo.mBackButton);
int w = tex->GetScaledWidth() * CleanXfac;
@ -444,21 +445,6 @@ DEFINE_ACTION_FUNCTION(DMenu, Close)
return 0;
}
DEFINE_ACTION_FUNCTION(DMenu, GetItem)
{
PARAM_SELF_PROLOGUE(DMenu);
PARAM_NAME(name);
ACTION_RETURN_OBJECT(self->GetItem(name));
}
DEFINE_ACTION_FUNCTION(DOptionMenuDescriptor, GetItem)
{
PARAM_SELF_PROLOGUE(DOptionMenuDescriptor);
PARAM_NAME(name);
ACTION_RETURN_OBJECT(self->GetItem(name));
}
bool DMenu::DimAllowed()
{
return true;
@ -486,7 +472,7 @@ bool DMenu::TranslateKeyboardEvents()
void M_StartControlPanel (bool makeSound)
{
// intro might call this repeatedly
if (DMenu::CurrentMenu != nullptr)
if (CurrentMenu != nullptr)
return;
ResetButtonStates ();
@ -518,9 +504,9 @@ void M_StartControlPanel (bool makeSound)
void M_ActivateMenu(DMenu *menu)
{
if (menuactive == MENU_Off) menuactive = MENU_On;
if (DMenu::CurrentMenu != nullptr) DMenu::CurrentMenu->ReleaseCapture();
DMenu::CurrentMenu = menu;
GC::WriteBarrier(DMenu::CurrentMenu);
if (CurrentMenu != nullptr) CurrentMenu->ReleaseCapture();
CurrentMenu = menu;
GC::WriteBarrier(CurrentMenu);
}
DEFINE_ACTION_FUNCTION(DMenu, ActivateMenu)
@ -602,6 +588,11 @@ void M_SetMenu(FName menu, int param)
M_InitVideoModes();
break;
case NAME_Quitmenu:
// The separate menu class no longer exists but the name still needs support for existing mods.
C_DoCommand("menu_quit");
return;
}
// End of special checks
@ -629,10 +620,10 @@ void M_SetMenu(FName menu, int param)
if (cls == nullptr) cls = DefaultListMenuClass;
if (cls == nullptr) cls = PClass::FindClass("ListMenu");
DListMenu *newmenu = (DListMenu *)cls->CreateNew();
IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init)
DMenu *newmenu = (DMenu *)cls->CreateNew();
IFVIRTUALPTRNAME(newmenu, "ListMenu", Init)
{
VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld };
VMValue params[3] = { newmenu, CurrentMenu, ld };
GlobalVMStack.Call(func, params, 3, nullptr, 0);
}
M_ActivateMenu(newmenu);
@ -648,7 +639,7 @@ void M_SetMenu(FName menu, int param)
DMenu *newmenu = (DMenu*)cls->CreateNew();
IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init)
{
VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld };
VMValue params[3] = { newmenu, CurrentMenu, ld };
GlobalVMStack.Call(func, params, 3, nullptr, 0);
}
M_ActivateMenu(newmenu);
@ -663,7 +654,7 @@ void M_SetMenu(FName menu, int param)
if (menuclass->IsDescendantOf(RUNTIME_CLASS(DMenu)))
{
DMenu *newmenu = (DMenu*)menuclass->CreateNew();
newmenu->mParentMenu = DMenu::CurrentMenu;
newmenu->mParentMenu = CurrentMenu;
M_ActivateMenu(newmenu);
return;
}
@ -699,7 +690,7 @@ bool M_Responder (event_t *ev)
return false;
}
if (DMenu::CurrentMenu != nullptr && menuactive != MENU_Off)
if (CurrentMenu != nullptr && menuactive != MENU_Off)
{
// There are a few input sources we are interested in:
//
@ -734,9 +725,9 @@ bool M_Responder (event_t *ev)
}
// pass everything else on to the current menu
return DMenu::CurrentMenu->CallResponder(ev);
return CurrentMenu->CallResponder(ev);
}
else if (DMenu::CurrentMenu->TranslateKeyboardEvents())
else if (CurrentMenu->TranslateKeyboardEvents())
{
ch = ev->data1;
keyup = ev->subtype == EV_GUI_KeyUp;
@ -755,7 +746,7 @@ bool M_Responder (event_t *ev)
default:
if (!keyup)
{
return DMenu::CurrentMenu->CallResponder(ev);
return CurrentMenu->CallResponder(ev);
}
break;
}
@ -838,11 +829,11 @@ bool M_Responder (event_t *ev)
{
MenuButtonTickers[mkey] = KEY_REPEAT_DELAY;
}
DMenu::CurrentMenu->CallMenuEvent(mkey, fromcontroller);
CurrentMenu->CallMenuEvent(mkey, fromcontroller);
return true;
}
}
return DMenu::CurrentMenu->CallResponder(ev) || !keyup;
return CurrentMenu->CallResponder(ev) || !keyup;
}
else if (MenuEnabled)
{
@ -883,10 +874,10 @@ bool M_Responder (event_t *ev)
void M_Ticker (void)
{
DMenu::MenuTime++;
if (DMenu::CurrentMenu != nullptr && menuactive != MENU_Off)
MenuTime++;
if (CurrentMenu != nullptr && menuactive != MENU_Off)
{
DMenu::CurrentMenu->CallTicker();
CurrentMenu->CallTicker();
for (int i = 0; i < NUM_MKEYS; ++i)
{
@ -895,7 +886,7 @@ void M_Ticker (void)
if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0)
{
MenuButtonTickers[i] = KEY_REPEAT_RATE;
DMenu::CurrentMenu->CallMenuEvent(i, MenuButtonOrigin[i]);
CurrentMenu->CallMenuEvent(i, MenuButtonOrigin[i]);
}
}
}
@ -935,14 +926,14 @@ void M_Drawer (void)
}
if (DMenu::CurrentMenu != nullptr && menuactive != MENU_Off)
if (CurrentMenu != nullptr && menuactive != MENU_Off)
{
if (DMenu::CurrentMenu->DimAllowed())
if (CurrentMenu->DimAllowed())
{
screen->Dim(fade);
V_SetBorderNeedRefresh();
}
DMenu::CurrentMenu->CallDrawer();
CurrentMenu->CallDrawer();
}
}
@ -955,10 +946,10 @@ void M_Drawer (void)
void M_ClearMenus ()
{
M_DemoNoPlay = false;
if (DMenu::CurrentMenu != nullptr)
if (CurrentMenu != nullptr)
{
DMenu::CurrentMenu->Destroy();
DMenu::CurrentMenu = nullptr;
CurrentMenu->Destroy();
CurrentMenu = nullptr;
}
V_SetBorderNeedRefresh();
menuactive = MENU_Off;
@ -1196,11 +1187,11 @@ CCMD(reset2saved)
// This really should be in the script but we can't do scripted CCMDs yet.
CCMD(undocolorpic)
{
if (DMenu::CurrentMenu != NULL)
if (CurrentMenu != NULL)
{
IFVIRTUALPTR(DMenu::CurrentMenu, DMenu, ResetColor)
IFVIRTUALPTR(CurrentMenu, DMenu, ResetColor)
{
VMValue params[] = { (DObject*)DMenu::CurrentMenu };
VMValue params[] = { (DObject*)CurrentMenu };
GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr);
}
}
@ -1210,6 +1201,8 @@ CCMD(undocolorpic)
DEFINE_FIELD(DMenu, mParentMenu)
DEFINE_FIELD(DMenu, mMouseCapture);
DEFINE_FIELD(DMenu, mBackbuttonSelected);
DEFINE_FIELD(DMenuDescriptor, mMenuName)
DEFINE_FIELD(DMenuDescriptor, mNetgameMessage)
@ -1220,9 +1213,6 @@ DEFINE_FIELD(DMenuItemBase, mYpos)
DEFINE_FIELD(DMenuItemBase, mAction)
DEFINE_FIELD(DMenuItemBase, mEnabled)
DEFINE_FIELD(DListMenu, mDesc)
DEFINE_FIELD(DListMenu, mFocusControl)
DEFINE_FIELD(DListMenuDescriptor, mItems)
DEFINE_FIELD(DListMenuDescriptor, mSelectedItem)
DEFINE_FIELD(DListMenuDescriptor, mSelectOfsX)
@ -1322,50 +1312,6 @@ DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, con
return (DMenuItemBase*)p;
}
bool DMenuItemBase::CheckCoordinate(int x, int y)
{
IFVIRTUAL(DMenuItemBase, CheckCoordinate)
{
VMValue params[] = { (DObject*)this, x, y };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return false;
}
void DMenuItemBase::Ticker()
{
IFVIRTUAL(DMenuItemBase, Ticker)
{
VMValue params[] = { (DObject*)this };
GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr);
}
}
void DMenuItemBase::Drawer(bool selected)
{
IFVIRTUAL(DMenuItemBase, Drawer)
{
VMValue params[] = { (DObject*)this, selected };
GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr);
}
}
bool DMenuItemBase::Selectable()
{
IFVIRTUAL(DMenuItemBase, Selectable)
{
VMValue params[] = { (DObject*)this };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return false;
}
bool DMenuItemBase::Activate()
{
IFVIRTUAL(DMenuItemBase, Activate)
@ -1378,18 +1324,6 @@ bool DMenuItemBase::Activate()
}
return false;
}
FName DMenuItemBase::GetAction(int *pparam)
{
IFVIRTUAL(DMenuItemBase, GetAction)
{
VMValue params[] = { (DObject*)this };
int retval[2];
VMReturn ret[2]; ret[0].IntAt(&retval[0]); ret[1].IntAt(&retval[1]);
GlobalVMStack.Call(func, params, countof(params), ret, 2, nullptr);
return ENamedName(retval[0]);
}
return NAME_None;
}
bool DMenuItemBase::SetString(int i, const char *s)
{
@ -1447,112 +1381,4 @@ bool DMenuItemBase::GetValue(int i, int *pvalue)
return false;
}
void DMenuItemBase::Enable(bool on)
{
IFVIRTUAL(DMenuItemBase, Enable)
{
VMValue params[] = { (DObject*)this, on };
GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr);
}
}
bool DMenuItemBase::MenuEvent(int mkey, bool fromcontroller)
{
IFVIRTUAL(DMenuItemBase, MenuEvent)
{
VMValue params[] = { (DObject*)this, mkey, fromcontroller };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return false;
}
bool DMenuItemBase::MouseEvent(int type, int x, int y)
{
IFVIRTUAL(DMenuItemBase, MouseEvent)
{
VMValue params[] = { (DObject*)this, type, x, y };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return false;
}
bool DMenuItemBase::CheckHotkey(int c)
{
IFVIRTUAL(DMenuItemBase, CheckHotkey)
{
VMValue params[] = { (DObject*)this, c };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return false;
}
int DMenuItemBase::GetWidth()
{
IFVIRTUAL(DMenuItemBase, GetWidth)
{
VMValue params[] = { (DObject*)this };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return retval;
}
return false;
}
int DMenuItemBase::GetIndent()
{
IFVIRTUAL(DMenuItemBase, GetIndent)
{
VMValue params[] = { (DObject*)this };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return retval;
}
return false;
}
int DMenuItemBase::Draw(DOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
IFVIRTUAL(DMenuItemBase, Draw)
{
VMValue params[] = { (DObject*)this, desc, y, indent, selected };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return retval;
}
return false;
}
void DMenuItemBase::DrawSelector(int xofs, int yofs, FTextureID tex)
{
if (tex.isNull())
{
if ((DMenu::MenuTime % 8) < 6)
{
screen->DrawText(ConFont, OptionSettings.mFontColorSelection,
(mXpos + xofs - 160) * CleanXfac + screen->GetWidth() / 2,
(mYpos + yofs - 100) * CleanYfac + screen->GetHeight() / 2,
"\xd",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac,
TAG_DONE);
}
}
else
{
screen->DrawTexture(TexMan(tex), mXpos + xofs, mYpos + yofs, DTA_Clean, true, TAG_DONE);
}
}
IMPLEMENT_CLASS(DMenuItemBase, false, false)

View file

@ -58,46 +58,58 @@ extern FGameStartup GameStartupInfo;
struct FSaveGameNode
{
char Title[SAVESTRINGSIZE];
FString SaveTitle;
FString Filename;
bool bOldVersion;
bool bMissingWads;
bool bNoDelete;
FSaveGameNode() { bNoDelete = false; }
bool bOldVersion = false;
bool bMissingWads = false;
bool bNoDelete = false;
};
struct SavegameManager
struct FSavegameManager
{
private:
TArray<FSaveGameNode*> SaveGames;
FSaveGameNode NewSaveNode;
int LastSaved = -1;
int LastAccessed = -1;
int WindowSize = 0;
FSaveGameNode *quickSaveSlot = nullptr;
FileReader *currentSavePic = nullptr;
TArray<char> SavePicData;
FTexture *SavePic = nullptr;
FBrokenLines *SaveComment = nullptr;
void ClearSaveGames();
public:
int WindowSize = 0;
FSaveGameNode *quickSaveSlot = nullptr;
~FSavegameManager();
private:
int InsertSaveNode(FSaveGameNode *node);
int RemoveSaveSlot(int index);
public:
void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave);
void ClearSaveGames();
void ReadSaveStrings();
void NotifyNewSave(const char *file, const char *title, bool okForQuicksave);
void UnloadSaveData();
int RemoveSaveSlot(int index);
void LoadSavegame(int Selected);
void DoSave(int Selected, const char *savegamestring);
void DeleteEntry(int Selected);
void ExtractSaveData(int index);
void UnloadSaveData();
unsigned ExtractSaveData(int index);
void ClearSaveStuff();
bool DrawSavePic(int x, int y, int w, int h);
void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor);
void SetFileInfo(int Selected);
unsigned SavegameCount();
FSaveGameNode *GetSavegame(int i);
void InsertNewSaveNode();
bool RemoveNewSaveNode();
};
extern SavegameManager savegameManager;
extern FSavegameManager savegameManager;
class DMenu;
extern DMenu *CurrentMenu;
extern int MenuTime;
//=============================================================================
//
@ -241,9 +253,7 @@ class DMenu : public DObject
DECLARE_CLASS (DMenu, DObject)
HAS_OBJECT_POINTERS
protected:
bool mMouseCapture;
bool mBackbuttonSelected;
public:
enum
@ -258,10 +268,9 @@ public:
BACKBUTTON_TIME = 4*TICRATE
};
static DMenu *CurrentMenu;
static int MenuTime;
TObjPtr<DMenu> mParentMenu;
bool mMouseCapture;
bool mBackbuttonSelected;
DMenu(DMenu *parent = NULL);
virtual bool Responder (event_t *ev);
@ -277,8 +286,6 @@ public:
virtual bool CheckFocus(DMenuItemBase *fc) { return false; }
virtual void ReleaseFocus() {}
virtual DMenuItemBase *GetItem(FName name) { return nullptr; }
bool CallResponder(event_t *ev);
bool CallMenuEvent(int mkey, bool fromcontroller);
bool CallMouseEvent(int type, int x, int y);
@ -308,70 +315,15 @@ public:
FNameNoInit mAction;
bool mEnabled;
bool CheckCoordinate(int x, int y);
void Ticker();
void Drawer(bool selected);
bool Selectable();
bool Activate();
FName GetAction(int *pparam);
bool SetString(int i, const char *s);
bool GetString(int i, char *s, int len);
bool SetValue(int i, int value);
bool GetValue(int i, int *pvalue);
void Enable(bool on);
bool MenuEvent (int mkey, bool fromcontroller);
bool MouseEvent(int type, int x, int y);
bool CheckHotkey(int c);
int GetWidth();
int GetIndent();
int Draw(DOptionMenuDescriptor *desc, int y, int indent, bool selected);
void OffsetPositionY(int ydelta) { mYpos += ydelta; }
int GetY() { return mYpos; }
int GetX() { return mXpos; }
void SetX(int x) { mXpos = x; }
void DrawSelector(int xofs, int yofs, FTextureID tex);
};
//=============================================================================
//
// list menu class runs a menu described by a DListMenuDescriptor
//
//=============================================================================
class DListMenu : public DMenu
{
DECLARE_CLASS(DListMenu, DMenu)
HAS_OBJECT_POINTERS;
public:
DListMenuDescriptor *mDesc;
DMenuItemBase *mFocusControl;
DListMenu(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL);
virtual void Init(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL);
DMenuItemBase *GetItem(FName name);
bool Responder (event_t *ev);
bool MenuEvent (int mkey, bool fromcontroller);
bool MouseEvent(int type, int x, int y);
void Ticker ();
void Drawer ();
void SetFocus(DMenuItemBase *fc)
{
mFocusControl = fc;
}
bool CheckFocus(DMenuItemBase *fc)
{
return mFocusControl == fc;
}
void ReleaseFocus()
{
mFocusControl = NULL;
}
};
//=============================================================================
//
//
@ -396,41 +348,10 @@ extern FOptionMap OptionValues;
//=============================================================================
//
// Input some text
//
//
//=============================================================================
class DTextEnterMenu : public DMenu
{
DECLARE_ABSTRACT_CLASS(DTextEnterMenu, DMenu)
public:
FString mEnterString;
unsigned int mEnterSize;
unsigned int mEnterPos;
int mSizeMode; // 1: size is length in chars. 2: also check string width
bool mInputGridOkay;
int InputGridX;
int InputGridY;
// [TP]
bool AllowColors;
// [TP] Added allowcolors
DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors = false);
void Drawer ();
bool MenuEvent (int mkey, bool fromcontroller);
bool Responder(event_t *ev);
bool MouseEvent(int type, int x, int y);
FString GetText();
};
struct event_t;
void M_EnableMenu (bool on) ;
bool M_Responder (event_t *ev);

View file

@ -147,7 +147,7 @@ static void DeinitMenus()
}
MenuDescriptors.Clear();
OptionValues.Clear();
DMenu::CurrentMenu = nullptr;
CurrentMenu = nullptr;
savegameManager.ClearSaveGames();
}
@ -294,7 +294,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc)
{
sc.MustGetString();
PClass *cls = PClass::FindClass(sc.String);
if (cls == nullptr || !cls->IsDescendantOf(RUNTIME_CLASS(DListMenu)))
if (cls == nullptr || !cls->IsDescendantOf("ListMenu"))
{
sc.ScriptError("Unknown menu class '%s'", sc.String);
}
@ -868,7 +868,6 @@ static void ParseOptionMenu(FScanner &sc)
ParseOptionMenuBody(sc, desc);
ReplaceMenu(sc, desc);
if (desc->mIndent == 0) desc->CalcIndent();
}
@ -1340,7 +1339,7 @@ void M_StartupSkillMenu(FGameStartup *gs)
// Delete previous contents
for(unsigned i=0; i<ld->mItems.Size(); i++)
{
FName n = ld->mItems[i]->GetAction(nullptr);
FName n = ld->mItems[i]->mAction;
if (n == NAME_Startgame || n == NAME_StartgameConfirm)
{
ld->mItems.Resize(i);

View file

@ -1,396 +0,0 @@
/*
** menuinput.cpp
** The string input code
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "menu/menu.h"
#include "v_video.h"
#include "c_cvars.h"
#include "d_event.h"
#include "d_gui.h"
#include "v_font.h"
#include "v_palette.h"
#include "cmdlib.h"
// [TP] New #includes
#include "v_text.h"
IMPLEMENT_CLASS(DTextEnterMenu, true, false)
#define INPUTGRID_WIDTH 13
#define INPUTGRID_HEIGHT 5
// Heretic and Hexen do not, by default, come with glyphs for all of these
// characters. Oh well. Doom and Strife do.
static const char InputGridChars[INPUTGRID_WIDTH * INPUTGRID_HEIGHT] =
"ABCDEFGHIJKLM"
"NOPQRSTUVWXYZ"
"0123456789+-="
".,!?@'\":;[]()"
"<>^#$%&*/_ \b";
CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
DEFINE_FIELD(DTextEnterMenu, mInputGridOkay)
//=============================================================================
//
//
//
//=============================================================================
// [TP] Added allowcolors
DTextEnterMenu::DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors)
: DMenu(parent)
{
mEnterString = textbuffer;
mEnterSize = maxlen < 0 ? UINT_MAX : unsigned(maxlen);
mSizeMode = sizemode;
mInputGridOkay = showgrid || m_showinputgrid;
if (mEnterString.IsNotEmpty())
{
InputGridX = INPUTGRID_WIDTH - 1;
InputGridY = INPUTGRID_HEIGHT - 1;
}
else
{
// If we are naming a new save, don't start the cursor on "end".
InputGridX = 0;
InputGridY = 0;
}
AllowColors = allowcolors; // [TP]
}
//=============================================================================
//
//
//
//=============================================================================
FString DTextEnterMenu::GetText()
{
return mEnterString;
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
bool DTextEnterMenu::Responder(event_t *ev)
{
if (ev->type == EV_GUI_Event)
{
// Save game and player name string input
if (ev->subtype == EV_GUI_Char)
{
mInputGridOkay = false;
if (mEnterString.Len() < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString.AppendFormat("%c", (char)ev->data1);
}
return true;
}
char ch = (char)ev->data1;
if ((ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) && ch == '\b')
{
if (mEnterString.IsNotEmpty())
{
mEnterString.Truncate(mEnterString.Len() - 1);
}
}
else if (ev->subtype == EV_GUI_KeyDown)
{
if (ch == GK_ESCAPE)
{
DMenu *parent = mParentMenu;
Close();
parent->CallMenuEvent(MKEY_Abort, false);
return true;
}
else if (ch == '\r')
{
if (mEnterString.IsNotEmpty())
{
// [TP] If we allow color codes, colorize the string now.
if (AllowColors)
mEnterString = strbin1(mEnterString);
DMenu *parent = mParentMenu;
parent->CallMenuEvent(MKEY_Input, false);
Close();
return true;
}
}
}
if (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat)
{
return true;
}
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DTextEnterMenu::MouseEvent(int type, int x, int y)
{
const int cell_width = 18 * CleanXfac;
const int cell_height = 12 * CleanYfac;
const int screen_y = screen->GetHeight() - INPUTGRID_HEIGHT * cell_height;
const int screen_x = (screen->GetWidth() - INPUTGRID_WIDTH * cell_width) / 2;
if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y)
{
InputGridX = (x - screen_x) / cell_width;
InputGridY = (y - screen_y) / cell_height;
if (type == DMenu::MOUSE_Release)
{
if (CallMenuEvent(MKEY_Enter, true))
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
if (m_use_mouse == 2) InputGridX = InputGridY = -1;
return true;
}
}
}
else
{
InputGridX = InputGridY = -1;
}
return Super::MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller)
{
if (key == MKEY_Back)
{
mParentMenu->CallMenuEvent(MKEY_Abort, false);
return Super::MenuEvent(key, fromcontroller);
}
if (fromcontroller)
{
mInputGridOkay = true;
}
if (mInputGridOkay)
{
int ch;
if (InputGridX == -1 || InputGridY == -1)
{
InputGridX = InputGridY = 0;
}
switch (key)
{
case MKEY_Down:
InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Up:
InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Right:
InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Left:
InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Clear:
if (mEnterString.IsNotEmpty())
{
mEnterString.Truncate(mEnterString.Len() - 1);
}
return true;
case MKEY_Enter:
assert(unsigned(InputGridX) < INPUTGRID_WIDTH && unsigned(InputGridY) < INPUTGRID_HEIGHT);
if (mInputGridOkay)
{
ch = InputGridChars[InputGridX + InputGridY * INPUTGRID_WIDTH];
if (ch == 0) // end
{
if (mEnterString.IsNotEmpty())
{
DMenu *parent = mParentMenu;
Close();
parent->CallMenuEvent(MKEY_Input, false);
return true;
}
}
else if (ch == '\b') // bs
{
if (mEnterString.IsNotEmpty())
{
mEnterString.Truncate(mEnterString.Len() - 1);
}
}
else if (mEnterString.Len() < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString += char(ch);
}
}
return true;
default:
break; // Keep GCC quiet
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void DTextEnterMenu::Drawer ()
{
mParentMenu->CallDrawer();
if (mInputGridOkay)
{
const int cell_width = 18 * CleanXfac;
const int cell_height = 12 * CleanYfac;
const int top_padding = cell_height / 2 - SmallFont->GetHeight() * CleanYfac / 2;
// Darken the background behind the character grid.
// Unless we frame it with a border, I think it looks better to extend the
// background across the full width of the screen.
screen->Dim(0, 0.8f,
0 /*screen->GetWidth()/2 - 13 * cell_width / 2*/,
screen->GetHeight() - INPUTGRID_HEIGHT * cell_height,
screen->GetWidth() /*13 * cell_width*/,
INPUTGRID_HEIGHT * cell_height);
if (InputGridX >= 0 && InputGridY >= 0)
{
// Highlight the background behind the selected character.
screen->Dim(MAKERGB(255,248,220), 0.6f,
InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2,
InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight(),
cell_width, cell_height);
}
for (int y = 0; y < INPUTGRID_HEIGHT; ++y)
{
const int yy = y * cell_height - INPUTGRID_HEIGHT * cell_height + screen->GetHeight();
for (int x = 0; x < INPUTGRID_WIDTH; ++x)
{
int width;
const int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen->GetWidth() / 2;
const int ch = InputGridChars[y * INPUTGRID_WIDTH + x];
FTexture *pic = SmallFont->GetChar(ch, &width);
EColorRange color;
// The highlighted character is yellow; the rest are dark gray.
color = (x == InputGridX && y == InputGridY) ? CR_YELLOW : CR_DARKGRAY;
if (pic != NULL)
{
// Draw a normal character.
screen->DrawChar(SmallFont, color, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding, ch, DTA_CleanNoMove, true, TAG_DONE);
}
else if (ch == ' ')
{
FRemapTable *remap = SmallFont->GetColorTranslation(color);
// Draw the space as a box outline. We also draw it 50% wider than it really is.
const int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4;
const int x2 = x1 + width * 3 * CleanXfac / 2;
const int y1 = yy + top_padding;
const int y2 = y1 + SmallFont->GetHeight() * CleanYfac;
const int palentry = remap->Remap[remap->NumEntries * 2 / 3];
const uint32 palcolor = remap->Palette[remap->NumEntries * 2 / 3];
screen->Clear(x1, y1, x2, y1+CleanYfac, palentry, palcolor); // top
screen->Clear(x1, y2, x2, y2+CleanYfac, palentry, palcolor); // bottom
screen->Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palentry, palcolor); // left
screen->Clear(x2-CleanXfac, y1+CleanYfac, x2, y2, palentry, palcolor); // right
}
else if (ch == '\b' || ch == 0)
{
// Draw the backspace and end "characters".
const char *const str = ch == '\b' ? "BS" : "ED";
screen->DrawText(SmallFont, color,
xx + cell_width/2 - SmallFont->StringWidth(str)*CleanXfac/2,
yy + top_padding, str, DTA_CleanNoMove, true, TAG_DONE);
}
}
}
}
Super::Drawer();
}
DEFINE_ACTION_FUNCTION(DTextEnterMenu, Open)
{
PARAM_PROLOGUE;
PARAM_OBJECT(parent, DMenu);
PARAM_STRING(text);
PARAM_INT(maxlen);
PARAM_INT(sizemode);
PARAM_BOOL(fromcontroller);
auto m = new DTextEnterMenu(parent, text.GetChars(), maxlen, sizemode, fromcontroller, false);
M_ActivateMenu(m);
ACTION_RETURN_OBJECT(m);
}
DEFINE_ACTION_FUNCTION(DTextEnterMenu, GetText)
{
PARAM_SELF_PROLOGUE(DTextEnterMenu);
ACTION_RETURN_STRING(self->GetText());
}

View file

@ -46,52 +46,15 @@
#include "c_dispatch.h"
#include "g_game.h"
EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd]
class DMessageBoxMenu : public DMenu
typedef void(*hfunc)();
DEFINE_ACTION_FUNCTION(DMessageBoxMenu, CallHandler)
{
DECLARE_CLASS(DMessageBoxMenu, DMenu)
FBrokenLines *mMessage;
int mMessageMode;
int messageSelection;
int mMouseLeft, mMouseRight, mMouseY;
FName mAction;
public:
DMessageBoxMenu(DMenu *parent = NULL, const char *message = NULL, int messagemode = 0, bool playsound = false, FName action = NAME_None);
void OnDestroy() override;
void Init(DMenu *parent, const char *message, int messagemode, bool playsound = false);
void Drawer();
bool Responder(event_t *ev);
bool MenuEvent(int mkey, bool fromcontroller);
bool MouseEvent(int type, int x, int y);
void CloseSound();
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DMessageBoxMenu, false, false)
//=============================================================================
//
//
//
//=============================================================================
DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action)
: DMenu(parent)
{
mAction = action;
messageSelection = 0;
mMouseLeft = 140;
mMouseY = INT_MIN;
int mr1 = 170 + SmallFont->StringWidth(GStrings["TXT_YES"]);
int mr2 = 170 + SmallFont->StringWidth(GStrings["TXT_NO"]);
mMouseRight = MAX(mr1, mr2);
Init(parent, message, messagemode, playsound);
PARAM_PROLOGUE;
PARAM_POINTERTYPE(Handler, hfunc);
Handler();
return 0;
}
//=============================================================================
@ -100,325 +63,15 @@ DMessageBoxMenu::DMessageBoxMenu(DMenu *parent, const char *message, int message
//
//=============================================================================
void DMessageBoxMenu::Init(DMenu *parent, const char *message, int messagemode, bool playsound)
DMenu *CreateMessageBoxMenu(DMenu *parent, const char *message, int messagemode, bool playsound, FName action = NAME_None, hfunc handler = nullptr)
{
mParentMenu = parent;
if (message != NULL)
{
if (*message == '$') message = GStrings(message+1);
mMessage = V_BreakLines(SmallFont, 300, message);
}
else mMessage = NULL;
mMessageMode = messagemode;
if (playsound)
{
S_StopSound (CHAN_VOICE);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/prompt", snd_menuvolume, ATTN_NONE);
}
}
auto c = PClass::FindClass("MessageBoxMenu");
auto p = c->CreateNew();
VMValue params[] = { p, parent, FString(message), messagemode, playsound, action.GetIndex(), handler };
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::OnDestroy()
{
if (mMessage != NULL) V_FreeBrokenLines(mMessage);
mMessage = NULL;
Super::OnDestroy();
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::CloseSound()
{
S_Sound (CHAN_VOICE | CHAN_UI,
DMenu::CurrentMenu != NULL? "menu/backup" : "menu/dismiss", snd_menuvolume, ATTN_NONE);
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::HandleResult(bool res)
{
if (mParentMenu != NULL)
{
if (mMessageMode == 0)
{
if (mAction == NAME_None)
{
mParentMenu->CallMenuEvent(res? MKEY_MBYes : MKEY_MBNo, false);
Close();
}
else
{
Close();
if (res) M_SetMenu(mAction, -1);
}
CloseSound();
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void DMessageBoxMenu::Drawer ()
{
int i, y;
PalEntry fade = 0;
int fontheight = SmallFont->GetHeight();
//V_SetBorderNeedRefresh();
//ST_SetNeedRefresh();
y = 100;
if (mMessage != NULL)
{
for (i = 0; mMessage[i].Width >= 0; i++)
y -= SmallFont->GetHeight () / 2;
for (i = 0; mMessage[i].Width >= 0; i++)
{
screen->DrawText (SmallFont, CR_UNTRANSLATED, 160 - mMessage[i].Width/2, y, mMessage[i].Text,
DTA_Clean, true, TAG_DONE);
y += fontheight;
}
}
if (mMessageMode == 0)
{
y += fontheight;
mMouseY = y;
screen->DrawText(SmallFont,
messageSelection == 0? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
160, y, GStrings["TXT_YES"], DTA_Clean, true, TAG_DONE);
screen->DrawText(SmallFont,
messageSelection == 1? OptionSettings.mFontColorSelection : OptionSettings.mFontColor,
160, y + fontheight + 1, GStrings["TXT_NO"], DTA_Clean, true, TAG_DONE);
if (messageSelection >= 0)
{
if ((DMenu::MenuTime%8) < 6)
{
screen->DrawText(ConFont, OptionSettings.mFontColorSelection,
(150 - 160) * CleanXfac + screen->GetWidth() / 2,
(y + (fontheight + 1) * messageSelection - 100 + fontheight/2 - 5) * CleanYfac + screen->GetHeight() / 2,
"\xd",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac,
TAG_DONE);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DMessageBoxMenu::Responder(event_t *ev)
{
if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_KeyDown)
{
if (mMessageMode == 0)
{
int ch = tolower(ev->data1);
if (ch == 'n' || ch == ' ')
{
HandleResult(false);
return true;
}
else if (ch == 'y')
{
HandleResult(true);
return true;
}
}
else
{
Close();
return true;
}
return false;
}
else if (ev->type == EV_KeyDown)
{
Close();
return true;
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DMessageBoxMenu::MenuEvent(int mkey, bool fromcontroller)
{
if (mMessageMode == 0)
{
if (mkey == MKEY_Up || mkey == MKEY_Down)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
messageSelection = !messageSelection;
return true;
}
else if (mkey == MKEY_Enter)
{
// 0 is yes, 1 is no
HandleResult(!messageSelection);
return true;
}
else if (mkey == MKEY_Back)
{
HandleResult(false);
return true;
}
return false;
}
else
{
Close();
CloseSound();
return true;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DMessageBoxMenu::MouseEvent(int type, int x, int y)
{
if (mMessageMode == 1)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}
else
{
int sel = -1;
int fh = SmallFont->GetHeight() + 1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + 2 * fh)
{
sel = y >= mMouseY + fh;
}
if (sel != -1 && sel != messageSelection)
{
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
messageSelection = sel;
if (type == MOUSE_Release)
{
return MenuEvent(MKEY_Enter, true);
}
return true;
}
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DQuitMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DQuitMenu, DMessageBoxMenu)
public:
DQuitMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DQuitMenu, false, false)
//=============================================================================
//
//
//
//=============================================================================
DQuitMenu::DQuitMenu(bool playsound)
{
int messageindex = gametic % gameinfo.quitmessages.Size();
FString EndString;
const char *msg = gameinfo.quitmessages[messageindex];
if (msg[0] == '$')
{
if (msg[1] == '*')
{
EndString = GStrings(msg+2);
}
else
{
EndString.Format("%s\n\n%s", GStrings(msg+1), GStrings("DOSY"));
}
}
else EndString = gameinfo.quitmessages[messageindex];
Init(NULL, EndString, 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DQuitMenu::HandleResult(bool res)
{
if (res)
{
if (!netgame)
{
if (gameinfo.quitSound.IsNotEmpty())
{
S_Sound (CHAN_VOICE | CHAN_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE);
I_WaitVBL (105);
}
}
ST_Endoom();
}
else
{
Close();
CloseSound();
}
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenu*)p;
}
//=============================================================================
@ -430,70 +83,42 @@ void DQuitMenu::HandleResult(bool res)
CCMD (menu_quit)
{ // F10
M_StartControlPanel (true);
DMenu *newmenu = new DQuitMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
int messageindex = gametic % gameinfo.quitmessages.Size();
FString EndString;
const char *msg = gameinfo.quitmessages[messageindex];
if (msg[0] == '$')
{
if (msg[1] == '*')
{
EndString = GStrings(msg + 2);
}
else
{
EndString.Format("%s\n\n%s", GStrings(msg + 1), GStrings("DOSY"));
}
}
else EndString = gameinfo.quitmessages[messageindex];
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, EndString, 0, false, NAME_None, []()
{
if (!netgame)
{
if (gameinfo.quitSound.IsNotEmpty())
{
S_Sound(CHAN_VOICE | CHAN_UI, gameinfo.quitSound, snd_menuvolume, ATTN_NONE);
I_WaitVBL(105);
}
}
ST_Endoom();
});
M_ActivateMenu(newmenu);
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DEndGameMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DEndGameMenu, DMessageBoxMenu)
public:
DEndGameMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DEndGameMenu, false, false)
//=============================================================================
//
//
//
//=============================================================================
DEndGameMenu::DEndGameMenu(bool playsound)
{
Init(NULL, GStrings(netgame ? "NETEND" : "ENDGAME"), 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DEndGameMenu::HandleResult(bool res)
{
if (res)
{
M_ClearMenus ();
if (!netgame)
{
D_StartTitle ();
}
}
else
{
Close();
CloseSound();
}
}
//=============================================================================
//
//
@ -510,67 +135,18 @@ CCMD (menu_endgame)
//M_StartControlPanel (true);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
DMenu *newmenu = new DEndGameMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DQuickSaveMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DQuickSaveMenu, DMessageBoxMenu)
public:
DQuickSaveMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DQuickSaveMenu, false, false)
//=============================================================================
//
//
//
//=============================================================================
DQuickSaveMenu::DQuickSaveMenu(bool playsound)
{
FString tempstring;
tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->Title);
Init(NULL, tempstring, 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DQuickSaveMenu::HandleResult(bool res)
{
if (res)
FString tempstring = GStrings(netgame ? "NETEND" : "ENDGAME");
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
{
G_SaveGame (savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
M_ClearMenus();
}
else
{
Close();
CloseSound();
}
if (!netgame)
{
D_StartTitle();
}
});
M_ActivateMenu(newmenu);
}
//=============================================================================
@ -601,72 +177,23 @@ CCMD (quicksave)
// [mxd]. Just save the game, no questions asked.
if (!saveloadconfirmation)
{
G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title);
G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars());
return;
}
S_Sound(CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
DMenu *newmenu = new DQuickSaveMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
M_ActivateMenu(newmenu);
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
//
//=============================================================================
class DQuickLoadMenu : public DMessageBoxMenu
{
DECLARE_CLASS(DQuickLoadMenu, DMessageBoxMenu)
public:
DQuickLoadMenu(bool playsound = false);
virtual void HandleResult(bool res);
};
IMPLEMENT_CLASS(DQuickLoadMenu, false, false)
//=============================================================================
//
//
//
//=============================================================================
DQuickLoadMenu::DQuickLoadMenu(bool playsound)
{
FString tempstring;
tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars());
tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->Title);
Init(NULL, tempstring, 0, playsound);
}
//=============================================================================
//
//
//
//=============================================================================
void DQuickLoadMenu::HandleResult(bool res)
{
if (res)
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
{
G_LoadGame (savegameManager.quickSaveSlot->Filename.GetChars());
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars());
S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
M_ClearMenus();
}
else
{
Close();
CloseSound();
}
});
M_ActivateMenu(newmenu);
}
//=============================================================================
@ -699,10 +226,17 @@ CCMD (quickload)
G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars());
return;
}
FString tempstring;
tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->SaveTitle.GetChars());
M_StartControlPanel(true);
DMenu *newmenu = new DQuickLoadMenu(false);
newmenu->mParentMenu = DMenu::CurrentMenu;
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
{
G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars());
S_Sound(CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
M_ClearMenus();
});
M_ActivateMenu(newmenu);
}
@ -714,13 +248,13 @@ CCMD (quickload)
void M_StartMessage(const char *message, int messagemode, FName action)
{
if (DMenu::CurrentMenu == NULL)
if (CurrentMenu == NULL)
{
// only play a sound if no menu was active before
M_StartControlPanel(menuactive == MENU_Off);
}
DMenu *newmenu = new DMessageBoxMenu(DMenu::CurrentMenu, message, messagemode, false, action);
newmenu->mParentMenu = DMenu::CurrentMenu;
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, message, messagemode, false, action);
newmenu->mParentMenu = CurrentMenu;
M_ActivateMenu(newmenu);
}
@ -732,4 +266,4 @@ DEFINE_ACTION_FUNCTION(DMenu, StartMessage)
PARAM_NAME_DEF(action);
M_StartMessage(msg, mode, action);
return 0;
}
}

View file

@ -49,32 +49,6 @@
#include "menu/menu.h"
//=============================================================================
//
//
//
//=============================================================================
void DOptionMenuDescriptor::CalcIndent()
{
// calculate the menu indent
int widest = 0, thiswidth;
for (unsigned i = 0; i < mItems.Size(); i++)
{
thiswidth = mItems[i]->GetIndent();
if (thiswidth > widest) widest = thiswidth;
}
mIndent = widest + 4;
}
DEFINE_ACTION_FUNCTION(DOptionMenuDescriptor, CalcIndent)
{
PARAM_SELF_PROLOGUE(DOptionMenuDescriptor);
self->CalcIndent();
return 0;
}
//=============================================================================
//
//
@ -85,7 +59,7 @@ DMenuItemBase *DOptionMenuDescriptor::GetItem(FName name)
{
for(unsigned i=0;i<mItems.Size(); i++)
{
FName nm = mItems[i]->GetAction(NULL);
FName nm = mItems[i]->mAction;
if (nm == name) return mItems[i];
}
return NULL;

View file

@ -61,12 +61,12 @@ EXTERN_CVAR(Bool, cl_run)
DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(r);
PARAM_INT(g);
PARAM_INT(b);
// only allow if the menu is active to prevent abuse.
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
char command[24];
players[consoleplayer].userinfo.ColorChanged(MAKERGB(r, g, b));
@ -86,12 +86,12 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_STRING(s);
const char *pp = s;
FString command("name \"");
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
// Escape any backslashes or quotation marks before sending the name to the console.
for (auto p = pp; *p != '\0'; ++p)
@ -116,9 +116,9 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, PlayerNameChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(sel);
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
players[consoleplayer].userinfo.ColorSetChanged(sel);
char command[24];
@ -136,10 +136,10 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ColorSetChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(sel);
PARAM_POINTER(cls, FPlayerClass);
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
players[consoleplayer].userinfo.PlayerClassNumChanged(gameinfo.norandomplayerclass ? sel : sel - 1);
cvar_set("playerclass", sel == 0 && !gameinfo.norandomplayerclass ? "Random" : GetPrintableDisplayName(cls->Type).GetChars());
@ -156,9 +156,9 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, ClassChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(sel);
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
players[consoleplayer].userinfo.SkinNumChanged(sel);
cvar_set("skin", Skins[sel].Name);
@ -174,10 +174,10 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SkinChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_FLOAT(val);
// only allow if the menu is active to prevent abuse.
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
autoaim = float(val);
}
@ -192,10 +192,10 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, AutoaimChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(val);
// only allow if the menu is active to prevent abuse.
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
team = val == 0 ? TEAM_NONE : val - 1;
}
@ -210,10 +210,10 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, TeamChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(v);
// only allow if the menu is active to prevent abuse.
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
cvar_set("gender", v == 0 ? "male" : v == 1 ? "female" : "other");
}
@ -228,10 +228,10 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, GenderChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(v);
// only allow if the menu is active to prevent abuse.
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
neverswitchonpickup = !!v;
}
@ -246,10 +246,10 @@ DEFINE_ACTION_FUNCTION(DPlayerMenu, SwitchOnPickupChanged)
DEFINE_ACTION_FUNCTION(DPlayerMenu, AlwaysRunChanged)
{
PARAM_SELF_PROLOGUE(DListMenu);
PARAM_SELF_PROLOGUE(DMenu);
PARAM_INT(v);
// only allow if the menu is active to prevent abuse.
if (self == DMenu::CurrentMenu)
if (self == CurrentMenu)
{
cl_run = !!v;
}

View file

@ -1,149 +0,0 @@
/*
** readthis.cpp
** Help screens
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "menu/menu.h"
#include "v_video.h"
#include "g_level.h"
#include "gi.h"
#include "g_levellocals.h"
#include "textures/textures.h"
class DReadThisMenu : public DMenu
{
DECLARE_CLASS(DReadThisMenu, DMenu)
int mScreen;
int mInfoTic;
public:
DReadThisMenu(DMenu *parent = NULL);
void Drawer();
bool MenuEvent(int mkey, bool fromcontroller);
bool DimAllowed () { return false; }
bool MouseEvent(int type, int x, int y);
};
IMPLEMENT_CLASS(DReadThisMenu, false, false)
//=============================================================================
//
// Read This Menus
//
//=============================================================================
DReadThisMenu::DReadThisMenu(DMenu *parent)
: DMenu(parent)
{
mScreen = 1;
mInfoTic = gametic;
}
//=============================================================================
//
//
//
//=============================================================================
void DReadThisMenu::Drawer()
{
FTexture *tex = NULL, *prevpic = NULL;
double alpha;
// Did the mapper choose a custom help page via MAPINFO?
if ((level.info != NULL) && level.info->F1Pic.Len() != 0)
{
tex = TexMan.FindTexture(level.info->F1Pic);
mScreen = 1;
}
if (tex == NULL)
{
tex = TexMan[gameinfo.infoPages[mScreen-1].GetChars()];
}
if (mScreen > 1)
{
prevpic = TexMan[gameinfo.infoPages[mScreen-2].GetChars()];
}
screen->Dim(0, 1.0, 0,0, SCREENWIDTH, SCREENHEIGHT);
alpha = MIN((gametic - mInfoTic) * (3. / TICRATE), 1.);
if (alpha < 1. && prevpic != NULL)
{
screen->DrawTexture (prevpic, 0, 0, DTA_Fullscreen, true, TAG_DONE);
}
screen->DrawTexture (tex, 0, 0, DTA_Fullscreen, true, DTA_Alpha, alpha, TAG_DONE);
}
//=============================================================================
//
//
//
//=============================================================================
bool DReadThisMenu::MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == MKEY_Enter)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
mScreen++;
mInfoTic = gametic;
if ((level.info != NULL && level.info->F1Pic.Len() != 0) || mScreen > int(gameinfo.infoPages.Size()))
{
Close();
}
return true;
}
else return Super::MenuEvent(mkey, fromcontroller);
}
//=============================================================================
//
//
//
//=============================================================================
bool DReadThisMenu::MouseEvent(int type, int x, int y)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}

View file

@ -347,7 +347,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker
}
// Convert the rest of the data to our own internal format.
node->Dialogue = ncopystring (speech.Dialogue);
node->Dialogue = speech.Dialogue;
// The speaker's portrait, if any.
speech.Dialogue[0] = 0; //speech.Backdrop[8] = 0;
@ -360,7 +360,7 @@ static FStrifeDialogueNode *ReadRetailNode (FileReader *lump, DWORD &prevSpeaker
// The speaker's name, if any.
speech.Sound[0] = 0; //speech.Name[16] = 0;
node->SpeakerName = ncopystring(speech.Name);
node->SpeakerName = speech.Name;
// The item the speaker should drop when killed.
node->DropType = dyn_cast<PClassActor>(GetStrifeType(speech.DropType));
@ -422,7 +422,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker
}
// Convert the rest of the data to our own internal format.
node->Dialogue = ncopystring (speech.Dialogue);
node->Dialogue = speech.Dialogue;
// The Teaser version doesn't have portraits.
node->Backdrop.SetInvalid();
@ -440,7 +440,7 @@ static FStrifeDialogueNode *ReadTeaserNode (FileReader *lump, DWORD &prevSpeaker
// The speaker's name, if any.
speech.Dialogue[0] = 0; //speech.Name[16] = 0;
node->SpeakerName = ncopystring (speech.Name);
node->SpeakerName = speech.Name;
// The item the speaker should drop when killed.
node->DropType = dyn_cast<PClassActor>(GetStrifeType (speech.DropType));
@ -505,7 +505,7 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
// The message to record in the log for this reply.
reply->LogNumber = rsp->Log;
reply->LogString = NULL;
reply->LogString = "";
// The item to receive when this reply is used.
reply->GiveType = dyn_cast<PClassActor>(GetStrifeType (rsp->GiveType));
@ -520,31 +520,32 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
reply->ItemCheck[k].Item = inv;
reply->ItemCheck[k].Amount = rsp->Count[k];
}
reply->PrintAmount = reply->ItemCheck[0].Amount;
reply->ItemCheckRequire.Clear();
reply->ItemCheckExclude.Clear();
// If the first item check has a positive amount required, then
// add that to the reply string. Otherwise, use the reply as-is.
reply->Reply = copystring (rsp->Reply);
reply->Reply = rsp->Reply;
reply->NeedsGold = (rsp->Count[0] > 0);
// QuickYes messages are shown when you meet the item checks.
// QuickNo messages are shown when you don't.
if (rsp->Yes[0] == '_' && rsp->Yes[1] == 0)
{
reply->QuickYes = NULL;
reply->QuickYes = "";
}
else
{
reply->QuickYes = ncopystring (rsp->Yes);
reply->QuickYes = rsp->Yes;
}
if (reply->ItemCheck[0].Item != 0)
{
reply->QuickNo = ncopystring (rsp->No);
reply->QuickNo = rsp->No;
}
else
{
reply->QuickNo = NULL;
reply->QuickNo = "";
}
reply->Next = *replyptr;
*replyptr = reply;
@ -560,9 +561,6 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses)
FStrifeDialogueNode::~FStrifeDialogueNode ()
{
if (SpeakerName != NULL) delete[] SpeakerName;
if (Dialogue != NULL) delete[] Dialogue;
if (Goodbye != nullptr) delete[] Goodbye;
FStrifeDialogueReply *tokill = Children;
while (tokill != NULL)
{
@ -580,9 +578,6 @@ FStrifeDialogueNode::~FStrifeDialogueNode ()
FStrifeDialogueReply::~FStrifeDialogueReply ()
{
if (Reply != NULL) delete[] Reply;
if (QuickYes != NULL) delete[] QuickYes;
if (QuickNo != NULL) delete[] QuickNo;
}
//============================================================================
@ -672,7 +667,7 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player)
{
if (reply->Reply == nullptr)
if (reply->Reply.IsEmpty())
return true;
int i;
@ -772,7 +767,7 @@ public:
ReplyText = GStrings(ReplyText + 1);
}
FString ReplyString = ReplyText;
if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->ItemCheck[0].Amount);
if (reply->NeedsGold) ReplyString.AppendFormat(" for %u", reply->PrintAmount);
FBrokenLines *ReplyLines = V_BreakLines (SmallFont, 320-50-10, ReplyString);
@ -785,7 +780,7 @@ public:
V_FreeBrokenLines (ReplyLines);
}
const char *goodbyestr = CurNode->Goodbye;
if (goodbyestr == nullptr)
if (*goodbyestr == 0)
{
char goodbye[25];
mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1 + (pr_randomspeech() % NUM_RANDOM_GOODBYES));
@ -1012,7 +1007,7 @@ public:
linesize = 10 * CleanYfac;
// Who is talking to you?
if (CurNode->SpeakerName != NULL)
if (CurNode->SpeakerName.IsNotEmpty())
{
speakerName = CurNode->SpeakerName;
if (speakerName[0] == '$') speakerName = GStrings(speakerName+1);
@ -1097,7 +1092,7 @@ public:
if (response == mSelection+1)
{
int color = ((DMenu::MenuTime%8) < 4) || DMenu::CurrentMenu != this ? CR_RED:CR_GREY;
int color = ((MenuTime%8) < 4) || CurrentMenu != this ? CR_RED:CR_GREY;
x = (50 + 3 - 160) * CleanXfac + screen->GetWidth() / 2;
int yy = (y + fontheight/2 - 5 - 100) * CleanYfac + screen->GetHeight() / 2;
@ -1135,9 +1130,9 @@ void P_FreeStrifeConversations ()
ClassRoots.Clear();
PrevNode = NULL;
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu)))
if (CurrentMenu != NULL && CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu)))
{
DMenu::CurrentMenu->Close();
CurrentMenu->Close();
}
}
@ -1315,7 +1310,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
if (!CheckStrifeItem(player, reply->ItemCheck[i].Item, reply->ItemCheck[i].Amount))
{
// No, you don't. Say so and let the NPC animate negatively.
if (reply->QuickNo && isconsole)
if (reply->QuickNo.IsNotEmpty() && isconsole)
{
TerminalResponse(reply->QuickNo);
}
@ -1396,7 +1391,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
}
// Update the quest log, if needed.
if (reply->LogString != NULL)
if (reply->LogString.IsNotEmpty())
{
const char *log = reply->LogString;
if (log[0] == '$')
@ -1482,10 +1477,10 @@ void P_ConversationCommand (int netcode, int pnum, BYTE **stream)
// The conversation menus are normally closed by the menu code, but that
// doesn't happen during demo playback, so we need to do it here.
if (demoplayback && DMenu::CurrentMenu != NULL &&
DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu)))
if (demoplayback && CurrentMenu != NULL &&
CurrentMenu->IsKindOf(RUNTIME_CLASS(DConversationMenu)))
{
DMenu::CurrentMenu->Close();
CurrentMenu->Close();
}
if (netcode == DEM_CONVREPLY)
{

View file

@ -26,11 +26,11 @@ struct FStrifeDialogueNode
int ItemCheckNode; // index into StrifeDialogues
PClassActor *SpeakerType;
char *SpeakerName;
FString SpeakerName;
FSoundID SpeakerVoice;
FTextureID Backdrop;
char *Dialogue;
char *Goodbye = nullptr; // must init to null for binary scripts to work as intended
FString Dialogue;
FString Goodbye; // must init to null for binary scripts to work as intended
FStrifeDialogueReply *Children;
};
@ -44,15 +44,16 @@ struct FStrifeDialogueReply
PClassActor *GiveType;
int ActionSpecial;
int Args[5];
int PrintAmount;
TArray<FStrifeDialogueItemCheck> ItemCheck;
TArray<FStrifeDialogueItemCheck> ItemCheckRequire;
TArray<FStrifeDialogueItemCheck> ItemCheckExclude;
char *Reply;
char *QuickYes;
FString Reply;
FString QuickYes;
FString QuickNo;
FString LogString;
int NextNode; // index into StrifeDialogues
int LogNumber;
char *LogString;
char *QuickNo;
bool NeedsGold;
};

View file

@ -232,20 +232,21 @@ class USDFParser : public UDMFParserBase
// Todo: Finalize
if (reply->ItemCheck.Size() > 0)
{
if (reply->ItemCheck[0].Amount <= 0) reply->NeedsGold = false;
reply->PrintAmount = reply->ItemCheck[0].Amount;
if (reply->PrintAmount <= 0) reply->NeedsGold = false;
}
reply->Reply = ncopystring(ReplyString);
reply->QuickYes = ncopystring(QuickYes);
reply->Reply = ReplyString;
reply->QuickYes = QuickYes;
if (reply->ItemCheck.Size() > 0 && reply->ItemCheck[0].Item != NULL)
{
reply->QuickNo = ncopystring(QuickNo);
reply->QuickNo = QuickNo;
}
else
{
reply->QuickNo = NULL;
reply->QuickNo = "";
}
reply->LogString = ncopystring(LogString);
reply->LogString = LogString;
if(!closeDialog) reply->NextNode *= -1;
return true;
}
@ -373,9 +374,9 @@ class USDFParser : public UDMFParserBase
}
}
}
node->SpeakerName = ncopystring(SpeakerName);
node->Dialogue = ncopystring(Dialogue);
node->Goodbye = ncopystring(Goodbye);
node->SpeakerName = SpeakerName;
node->Dialogue = Dialogue;
node->Goodbye = Goodbye;
return true;
}

View file

@ -802,7 +802,7 @@ void R_InitSkins (void)
if (spr == 0 && maxframe <= 0)
{
Printf (PRINT_BOLD, "Skin %s (#%u) has no frames. Removing.\n", Skins[i].Name, i);
Printf (PRINT_BOLD, "Skin %s (#%u) has no frames. Removing.\n", Skins[i].Name.GetChars(), i);
remove = true;
break;
}

View file

@ -906,7 +906,10 @@ void InitThingdef()
fieldptr = new PField("OptionMenuSettings", NewStruct("FOptionMenuSettings", nullptr), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&OptionSettings);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("gametic", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gametic);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
// Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag.
// It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution'
// is to create a static variable from it and reference that in the script. Yuck!!!
@ -1213,10 +1216,12 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
ACTION_RETURN_STRING(s);
}
DEFINE_ACTION_FUNCTION(FStringStruct, Len)
DEFINE_ACTION_FUNCTION(FStringStruct, Truncate)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
ACTION_RETURN_INT((int)self->Len());
PARAM_UINT(len);
self->Truncate(len);
return 0;
}
// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int.
@ -1239,3 +1244,10 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt)
ACTION_RETURN_INT(0);
ACTION_RETURN_INT((*self)[pos]);
}
DEFINE_ACTION_FUNCTION(FStringStruct, Filter)
{
PARAM_SELF_STRUCT_PROLOGUE(FString);
ACTION_RETURN_STRING(strbin1(*self));
}

View file

@ -8,6 +8,8 @@
#include "doomerrors.h"
#include "memarena.h"
class DObject;
extern FMemArena ClassDataAllocator;
#define MAX_RETURNS 8 // Maximum number of results a function called by script code can return
@ -1028,6 +1030,7 @@ void NullParam(const char *varname);
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, self->GetClass());
#define PARAM_STATE_ACTION_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); FState *x = (FState *)StateLabels.GetState(param[p].i, stateowner->GetClass());
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
#define PARAM_POINTERTYPE_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type x = (type )param[p].a;
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x);
@ -1072,6 +1075,7 @@ void NullParam(const char *varname);
#define PARAM_STATE(x) ++paramnum; PARAM_STATE_AT(paramnum,x)
#define PARAM_STATE_ACTION(x) ++paramnum; PARAM_STATE_ACTION_AT(paramnum,x)
#define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type)
#define PARAM_POINTERTYPE(x,type) ++paramnum; PARAM_POINTERTYPE_AT(paramnum,x,type)
#define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type)
#define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base)
#define PARAM_POINTER_NOT_NULL(x,type) ++paramnum; PARAM_POINTER_NOT_NULL_AT(paramnum,x,type)

View file

@ -337,6 +337,20 @@ void DCanvas::Dim (PalEntry color)
Dim (dimmer, amount, 0, 0, Width, Height);
}
DEFINE_ACTION_FUNCTION(_Screen, Dim)
{
PARAM_PROLOGUE;
PARAM_INT(color);
PARAM_FLOAT(amount);
PARAM_INT(x1);
PARAM_INT(y1);
PARAM_INT(w);
PARAM_INT(h);
screen->Dim(color, float(amount), x1, y1, w, h);
return 0;
}
//==========================================================================
//
// DCanvas :: GetScreenshotBuffer

View file

@ -100,7 +100,4 @@ const char *GetVersionString();
#endif
// The maximum length of one save game description for the menus.
#define SAVESTRINGSIZE 24
#endif //__VERSION_H__

View file

@ -9,17 +9,20 @@
#include "zscript/menu/menuitembase.txt"
#include "zscript/menu/menu.txt"
#include "zscript/menu/messagebox.txt"
#include "zscript/menu/listmenu.txt"
#include "zscript/menu/listmenuitems.txt"
#include "zscript/menu/optionmenu.txt"
#include "zscript/menu/optionmenuitems.txt"
#include "zscript/menu/colorpickermenu.txt"
#include "zscript/menu/joystickmenu.txt"
#include "zscript/menu/loadsavemenu.txt"
#include "zscript/menu/playermenu.txt"
#include "zscript/menu/playerdisplay.txt"
#include "zscript/menu/playercontrols.txt"
#include "zscript/menu/textentermenu.txt"
#include "zscript/menu/videomenu.txt"
#include "zscript/menu/readthis.txt"
#include "zscript/inventory/inventory.txt"
#include "zscript/inventory/inv_misc.txt"

View file

@ -158,15 +158,11 @@ enum DrawTextureTags
struct Screen native
{
int CleanWidth, CleanHeight;
int CleanXFac, CleanYFac;
int CleanWidth_1, CleanHeight_1;
int CleanXFac_1, CleanYFac_1;
native static Color PaletteColor(int index);
native static int GetWidth();
native static int GetHeight();
native static void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1);
native static void Dim(Color col, double amount, int x, int y, int w, int h);
native static void DrawHUDTexture(TextureID tex, double x, double y);
native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...);
@ -175,13 +171,6 @@ struct Screen native
native static void DrawFrame(int x, int y, int w, int h);
}
class BrokenLines : Object native
{
native int Count();
native int StringWidth(int line);
native String StringAt(int line);
}
struct Font native
{
enum EColorRange
@ -252,7 +241,7 @@ struct Font native
native static int FindFontColor(Name color);
native static Font FindFont(Name fontname);
native static Font GetFont(Name fontname);
native static BrokenLines BreakLines(String text, int maxlen);
native BrokenLines BreakLines(String text, int maxlen);
}
struct Translation
@ -310,6 +299,7 @@ struct GameInfoStruct native
native String ArmorIcon2;
native int gametype;
native bool norandomplayerclass;
native Array<Name> infoPages;
}
class Object native
@ -336,6 +326,13 @@ class Object native
virtual void OnDestroy() {}
}
class BrokenLines : Object native
{
native int Count();
native int StringWidth(int line);
native String StringAt(int line);
}
class Thinker : Object native
{
enum EStatnums
@ -440,6 +437,7 @@ struct LevelLocals native
native readonly String MapName;
native String NextMap;
native String NextSecretMap;
native String F1Pic;
native readonly int maptype;
native readonly String Music;
native readonly int musicorder;
@ -582,9 +580,10 @@ struct StringStruct native
native void Replace(String pattern, String replacement);
native String Mid(int pos = 0, int len = 2147483647);
native int Len();
native void Truncate(int newlen);
native String CharAt(int pos);
native int CharCodeAt(int pos);
native String Filter();
}
class Floor : Thinker native

View file

@ -40,10 +40,10 @@ class ListMenuDescriptor : MenuDescriptor native
//
//=============================================================================
class ListMenu : Menu native
class ListMenu : Menu
{
native ListMenuDescriptor mDesc;
native MenuItemBase mFocusControl;
ListMenuDescriptor mDesc;
MenuItemBase mFocusControl;
virtual void Init(Menu parent = NULL, ListMenuDescriptor desc = NULL)
{
@ -76,7 +76,13 @@ class ListMenu : Menu native
}
}
MenuItemBase GetItem(Name name)
//=============================================================================
//
//
//
//=============================================================================
ListMenuItem GetItem(Name name)
{
for(int i = 0; i < mDesc.mItems.Size(); i++)
{
@ -86,12 +92,173 @@ class ListMenu : Menu native
return NULL;
}
//bool Responder (InputEventData ev);
//bool MenuEvent (int mkey, bool fromcontroller);
//bool MouseEvent(int type, int x, int y);
//void Ticker ();
//void Drawer ();
//=============================================================================
//
//
//
//=============================================================================
override bool Responder (InputEventData ev)
{
if (ev.type == InputEventData.GUI_Event)
{
if (ev.subtype == InputEventData.GUI_KeyDown)
{
// tolower
int ch = ev.data1;
ch = ch >= 65 && ch <91? ch + 32 : ch;
for(int i = mDesc.mSelectedItem + 1; i < mDesc.mItems.Size(); i++)
{
if (mDesc.mItems[i].CheckHotkey(ch))
{
mDesc.mSelectedItem = i;
MenuSound("menu/cursor");
return true;
}
}
for(int i = 0; i < mDesc.mSelectedItem; i++)
{
if (mDesc.mItems[i].CheckHotkey(ch))
{
mDesc.mSelectedItem = i;
MenuSound("menu/cursor");
return true;
}
}
}
}
return Super.Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
int oldSelect = mDesc.mSelectedItem;
int startedAt = mDesc.mSelectedItem;
if (startedAt < 0) startedAt = 0;
switch (mkey)
{
case MKEY_Up:
do
{
if (--mDesc.mSelectedItem < 0) mDesc.mSelectedItem = mDesc.mItems.Size()-1;
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect;
MenuSound("menu/cursor");
return true;
case MKEY_Down:
do
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size()) mDesc.mSelectedItem = 0;
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect;
MenuSound("menu/cursor");
return true;
case MKEY_Enter:
if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate())
{
MenuSound("menu/choose");
}
return true;
default:
return Super.MenuEvent(mkey, fromcontroller);
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
int sel = -1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100;
if (mFocusControl != NULL)
{
mFocusControl.MouseEvent(type, x, y);
return true;
}
else
{
if ((mDesc.mWLeft <= 0 || x > mDesc.mWLeft) &&
(mDesc.mWRight <= 0 || x < mDesc.mWRight))
{
for(int i=0;i<mDesc.mItems.Size(); i++)
{
if (mDesc.mItems[i].CheckCoordinate(x, y))
{
if (i != mDesc.mSelectedItem)
{
//MenuSound("menu/cursor");
}
mDesc.mSelectedItem = i;
mDesc.mItems[i].MouseEvent(type, x, y);
return true;
}
}
}
}
mDesc.mSelectedItem = -1;
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
override void Ticker ()
{
Super.Ticker();
for(int i=0;i<mDesc.mItems.Size(); i++)
{
mDesc.mItems[i].Ticker();
}
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
for(int i=0;i<mDesc.mItems.Size(); i++)
{
if (mDesc.mItems[i].mEnabled) mDesc.mItems[i].Drawer(mDesc.mSelectedItem == i);
}
if (mDesc.mSelectedItem >= 0 && mDesc.mSelectedItem < mDesc.mItems.Size())
mDesc.mItems[mDesc.mSelectedItem].DrawSelector(mDesc.mSelectOfsX, mDesc.mSelectOfsY, mDesc.mSelector);
Super.Drawer();
}
//=============================================================================
//
//
//
//=============================================================================
override void SetFocus(MenuItemBase fc)
{
mFocusControl = fc;
@ -106,3 +273,4 @@ class ListMenu : Menu native
}
}

View file

@ -52,7 +52,7 @@ class ListMenuItem : MenuItemBase
}
else
{
screen.DrawTexture (tex, mXpos + xofs, mYpos + yofs, DTA_Clean, true);
screen.DrawTexture (tex, true, mXpos + xofs, mYpos + yofs, DTA_Clean, true);
}
}
}

View file

@ -0,0 +1,577 @@
/*
** loacpp
** The load game and save game menus
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010-2017 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
struct SaveGameNode native
{
native String SaveTitle;
native String Filename;
native bool bOldVersion;
native bool bMissingWads;
native bool bNoDelete;
}
struct SavegameManager native
{
native int WindowSize;
native SaveGameNode quickSaveSlot;
native static SavegameManager GetManager();
native void ReadSaveStrings();
native void UnloadSaveData();
native int RemoveSaveSlot(int index);
native void LoadSavegame(int Selected);
native void DoSave(int Selected, String savegamestring);
native int ExtractSaveData(int index);
native void ClearSaveStuff();
native bool DrawSavePic(int x, int y, int w, int h);
native void DrawSaveComment(Font font, int cr, int x, int y, int scalefactor);
native void SetFileInfo(int Selected);
native int SavegameCount();
native SaveGameNode GetSavegame(int i);
native void InsertNewSaveNode();
native bool RemoveNewSaveNode();
}
class LoadSaveMenu : ListMenu
{
SavegameManager manager;
int TopItem;
int Selected;
int savepicLeft;
int savepicTop;
int savepicWidth;
int savepicHeight;
int rowHeight;
int listboxLeft;
int listboxTop;
int listboxWidth;
int listboxRows;
int listboxHeight;
int listboxRight;
int listboxBottom;
int commentLeft;
int commentTop;
int commentWidth;
int commentHeight;
int commentRight;
int commentBottom;
bool mEntering;
TextEnterMenu mInput;
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, ListMenuDescriptor desc)
{
Super.Init(parent, desc);
manager = SavegameManager.GetManager();
manager.ReadSaveStrings();
savepicLeft = 10;
savepicTop = 54*CleanYfac;
savepicWidth = 216*screen.GetWidth()/640;
savepicHeight = 135*screen.GetHeight()/400;
manager.WindowSize = savepicWidth / CleanXfac;
rowHeight = (SmallFont.GetHeight() + 1) * CleanYfac;
listboxLeft = savepicLeft + savepicWidth + 14;
listboxTop = savepicTop;
listboxWidth = screen.GetWidth() - listboxLeft - 10;
int listboxHeight1 = screen.GetHeight() - listboxTop - 10;
listboxRows = (listboxHeight1 - 1) / rowHeight;
listboxHeight = listboxRows * rowHeight + 1;
listboxRight = listboxLeft + listboxWidth;
listboxBottom = listboxTop + listboxHeight;
commentLeft = savepicLeft;
commentTop = savepicTop + savepicHeight + 16;
commentWidth = savepicWidth;
commentHeight = (51+(screen.GetHeight()>200?10:0))*CleanYfac;
commentRight = commentLeft + commentWidth;
commentBottom = commentTop + commentHeight;
}
//=============================================================================
//
//
//
//=============================================================================
override void OnDestroy()
{
manager.ClearSaveStuff ();
Super.OnDestroy();
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
Super.Drawer();
SaveGameNode node;
int i;
int j;
bool didSeeSelected = false;
// Draw picture area
if (gameaction == ga_loadgame || gameaction == ga_loadgamehidecon || gameaction == ga_savegame)
{
return;
}
Screen.DrawFrame (savepicLeft, savepicTop, savepicWidth, savepicHeight);
if (!manager.DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight))
{
screen.Clear (savepicLeft, savepicTop, savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0);
if (manager.SavegameCount() > 0)
{
String text = (Selected == -1 || !manager.GetSavegame(Selected).bOldVersion)? Stringtable.Localize("$MNU_NOPICTURE") : Stringtable.Localize("$MNU_DIFFVERSION");
int textlen = SmallFont.StringWidth(text) * CleanXfac;
screen.DrawText (SmallFont, Font.CR_GOLD, savepicLeft+(savepicWidth-textlen)/2,
savepicTop+(savepicHeight-rowHeight)/2, text, DTA_CleanNoMove, true);
}
}
// Draw comment area
Screen.DrawFrame (commentLeft, commentTop, commentWidth, commentHeight);
screen.Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0);
manager.DrawSaveComment(SmallFont, Font.CR_GOLD, commentLeft, commentTop, CleanYfac);
// Draw file area
Screen.DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight);
screen.Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0);
if (manager.SavegameCount() == 0)
{
String text = Stringtable.Localize("$MNU_NOFILES");
int textlen = SmallFont.StringWidth(text) * CleanXfac;
screen.DrawText (SmallFont, Font.CR_GOLD, listboxLeft+(listboxWidth-textlen)/2, listboxTop+(listboxHeight-rowHeight)/2, text, DTA_CleanNoMove, true);
return;
}
j = TopItem;
for (i = 0; i < listboxRows && j < manager.SavegameCount(); i++)
{
int colr;
node = manager.GetSavegame(j);
if (node.bOldVersion)
{
colr = Font.CR_BLUE;
}
else if (node.bMissingWads)
{
colr = Font.CR_ORANGE;
}
else if (j == Selected)
{
colr = Font.CR_WHITE;
}
else
{
colr = Font.CR_TAN;
}
if (j == Selected)
{
screen.Clear (listboxLeft, listboxTop+rowHeight*i, listboxRight, listboxTop+rowHeight*(i+1), mEntering ? Color(255,255,0,0) : Color(255,0,0,255));
didSeeSelected = true;
if (!mEntering)
{
screen.DrawText (SmallFont, colr, listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node.SaveTitle, DTA_CleanNoMove, true);
}
else
{
String s = mInput.GetText() .. SmallFont.GetCursor();
screen.DrawText (SmallFont, Font.CR_WHITE, listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, s, DTA_CleanNoMove, true);
}
}
else
{
screen.DrawText (SmallFont, colr, listboxLeft+1, listboxTop+rowHeight*i+CleanYfac, node.SaveTitle, DTA_CleanNoMove, true);
}
j++;
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
switch (mkey)
{
case MKEY_Up:
if (manager.SavegameCount() > 1)
{
if (Selected == -1) Selected = TopItem;
else
{
if (--Selected < 0) Selected = manager.SavegameCount()-1;
if (Selected < TopItem) TopItem = Selected;
else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1);
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
}
return true;
case MKEY_Down:
if (manager.SavegameCount() > 1)
{
if (Selected == -1) Selected = TopItem;
else
{
if (++Selected >= manager.SavegameCount()) Selected = 0;
if (Selected < TopItem) TopItem = Selected;
else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1);
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
}
return true;
case MKEY_PageDown:
if (manager.SavegameCount() > 1)
{
if (TopItem >= manager.SavegameCount() - listboxRows)
{
TopItem = 0;
if (Selected != -1) Selected = 0;
}
else
{
TopItem = MIN(TopItem + listboxRows, manager.SavegameCount() - listboxRows);
if (TopItem > Selected && Selected != -1) Selected = TopItem;
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
}
return true;
case MKEY_PageUp:
if (manager.SavegameCount() > 1)
{
if (TopItem == 0)
{
TopItem = MAX(0, manager.SavegameCount() - listboxRows);
if (Selected != -1) Selected = TopItem;
}
else
{
TopItem = MAX(TopItem - listboxRows, 0);
if (Selected >= TopItem + listboxRows) Selected = TopItem;
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
}
return true;
case MKEY_Enter:
return false; // This event will be handled by the subclasses
case MKEY_MBYes:
{
if (Selected < manager.SavegameCount())
{
Selected = manager.RemoveSaveSlot (Selected);
}
return true;
}
default:
return Super.MenuEvent(mkey, fromcontroller);
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (x >= listboxLeft && x < listboxLeft + listboxWidth &&
y >= listboxTop && y < listboxTop + listboxHeight)
{
int lineno = (y - listboxTop) / rowHeight;
if (TopItem + lineno < manager.SavegameCount())
{
Selected = TopItem + lineno;
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
if (type == MOUSE_Release)
{
if (MenuEvent(MKEY_Enter, true))
{
return true;
}
}
}
else Selected = -1;
}
else Selected = -1;
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
override bool Responder (InputEventData ev)
{
if (ev.type == InputEventData.GUI_Event)
{
if (ev.subtype == InputEventData.GUI_KeyDown)
{
if (Selected < manager.SavegameCount())
{
switch (ev.data1)
{
case UIEvent.Key_F1:
manager.SetFileInfo(Selected);
return true;
case UIEvent.Key_DEL:
{
String EndString;
EndString = String.Format("%s%s%s%s?\n\n%s", Stringtable.Localize("$MNU_DELETESG"), TEXTCOLOR_WHITE, manager.GetSavegame(Selected).SaveTitle, TEXTCOLOR_NORMAL, Stringtable.Localize("$PRESSYN"));
StartMessage (EndString, 0);
}
return true;
}
}
}
else if (ev.subtype == InputEventData.GUI_WheelUp)
{
if (TopItem > 0) TopItem--;
return true;
}
else if (ev.subtype == InputEventData.GUI_WheelDown)
{
if (TopItem < manager.SavegameCount() - listboxRows) TopItem++;
return true;
}
}
return Super.Responder(ev);
}
}
class SaveMenu : LoadSaveMenu
{
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, ListMenuDescriptor desc)
{
Super.Init(parent, desc);
manager.InsertNewSaveNode();
TopItem = 0;
Selected = manager.ExtractSaveData (-1);
}
//=============================================================================
//
//
//
//=============================================================================
override void OnDestroy()
{
if (manager.RemoveNewSaveNode())
{
Selected--;
}
Super.OnDestroy();
}
//=============================================================================
//
//
//
//=============================================================================
const SAVESTRINGSIZE = 32;
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (Super.MenuEvent(mkey, fromcontroller))
{
return true;
}
if (Selected == -1)
{
return false;
}
if (mkey == MKEY_Enter)
{
String SavegameString = (Selected != 0)? manager.GetSavegame(Selected).SaveTitle : "";
mInput = TextEnterMenu.Open(self, SavegameString, SAVESTRINGSIZE, 1, fromcontroller);
mInput.ActivateMenu();
mEntering = true;
}
else if (mkey == MKEY_Input)
{
mEntering = false;
manager.DoSave(Selected, mInput.GetText());
mInput = null;
}
else if (mkey == MKEY_Abort)
{
mEntering = false;
mInput = null;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override bool Responder (InputEventData ev)
{
if (ev.subtype == InputEventData.GUI_KeyDown)
{
if (Selected != -1)
{
switch (ev.data1)
{
case UIEvent.Key_DEL:
// cannot delete 'new save game' item
if (Selected == 0) return true;
break;
case 78://'N':
Selected = TopItem = 0;
manager.UnloadSaveData ();
return true;
}
}
}
return Super.Responder(ev);
}
}
//=============================================================================
//
//
//
//=============================================================================
class LoadMenu : LoadSaveMenu
{
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, ListMenuDescriptor desc)
{
Super.Init(parent, desc);
TopItem = 0;
Selected = manager.ExtractSaveData (-1);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (Super.MenuEvent(mkey, fromcontroller))
{
return true;
}
if (Selected == -1 || manager.SavegameCount() == 0)
{
return false;
}
if (mkey == MKEY_Enter)
{
manager.LoadSavegame(Selected);
return true;
}
return false;
}
}

View file

@ -87,6 +87,8 @@ class Menu : Object native
};
native Menu mParentMenu;
native bool mMouseCapture;
native bool mBackbuttonSelected;
void Init(Menu parent)
{
@ -111,7 +113,6 @@ class Menu : Object native
native virtual void Ticker();
native virtual void Drawer();
native void Close();
native MenuItemBase GetItem(Name n);
native void ActivateMenu();
static void MenuSound(Sound snd)

View file

@ -0,0 +1,293 @@
/*
** messagebox.cpp
** Confirmation, notification screns
**
**---------------------------------------------------------------------------
** Copyright 2010-2017 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
class MessageBoxMenu : Menu
{
BrokenLines mMessage;
voidptr Handler;
int mMessageMode;
int messageSelection;
int mMouseLeft, mMouseRight, mMouseY;
Name mAction;
native static void CallHandler(voidptr hnd);
//=============================================================================
//
//
//
//=============================================================================
void Init(Menu parent, String message, int messagemode, bool playsound = false, Name cmd = 'None', voidptr native_handler = null)
{
Super.Init(parent);
mAction = cmd;
messageSelection = 0;
mMouseLeft = 140;
mMouseY = 0x80000000;
int mr1 = 170 + SmallFont.StringWidth(Stringtable.Localize("$TXT_YES"));
int mr2 = 170 + SmallFont.StringWidth(Stringtable.Localize("TXT_NO"));
mMouseRight = MAX(mr1, mr2);
mParentMenu = parent;
mMessage = SmallFont.BreakLines(message, 300);
mMessageMode = messagemode;
if (playsound)
{
MenuSound ("menu/prompt");
}
Handler = native_handler;
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
int i, y;
int fontheight = SmallFont.GetHeight();
y = 100;
int c = mMessage.Count();
for (i = 0; i < c; i++)
y -= SmallFont.GetHeight () / 2;
for (i = 0; i < c; i++)
{
screen.DrawText (SmallFont, Font.CR_UNTRANSLATED, 160 - mMessage.StringWidth(i)/2, y, mMessage.StringAt(i), DTA_Clean, true);
y += fontheight;
}
if (mMessageMode == 0)
{
y += fontheight;
mMouseY = y;
screen.DrawText(SmallFont, messageSelection == 0? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, 160, y, Stringtable.Localize("$TXT_YES"), DTA_Clean, true);
screen.DrawText(SmallFont, messageSelection == 1? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, 160, y + fontheight + 1, Stringtable.Localize("$TXT_NO"), DTA_Clean, true);
if (messageSelection >= 0)
{
if ((MenuTime() % 8) < 6)
{
screen.DrawText(ConFont, OptionMenuSettings.mFontColorSelection,
(150 - 160) * CleanXfac + screen.GetWidth() / 2,
(y + (fontheight + 1) * messageSelection - 100 + fontheight/2 - 5) * CleanYfac + screen.GetHeight() / 2,
"\xd", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
protected void CloseSound()
{
MenuSound (GetCurrentMenu() != NULL? "menu/backup" : "menu/dismiss");
}
//=============================================================================
//
//
//
//=============================================================================
virtual void HandleResult(bool res)
{
if (Handler != null)
{
if (res)
{
CallHandler(Handler);
}
else
{
Close();
CloseSound();
}
}
else if (mParentMenu != NULL)
{
if (mMessageMode == 0)
{
if (mAction == 'None')
{
mParentMenu.MenuEvent(res? MKEY_MBYes : MKEY_MBNo, false);
Close();
}
else
{
Close();
if (res) SetMenu(mAction, -1);
}
CloseSound();
}
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool Responder(InputEventData ev)
{
if (ev.type == InputEventData.GUI_Event && ev.subtype == InputEventData.GUI_KeyDown)
{
if (mMessageMode == 0)
{
// tolower
int ch = ev.data1;
ch = ch >= 65 && ch <91? ch + 32 : ch;
if (ch == 78 /*'n'*/ || ch == 32)
{
HandleResult(false);
return true;
}
else if (ch == 89 /*'y'*/)
{
HandleResult(true);
return true;
}
}
else
{
Close();
return true;
}
return false;
}
else if (ev.type == InputEventData.KeyDown)
{
Close();
return true;
}
return Super.Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent(int mkey, bool fromcontroller)
{
if (mMessageMode == 0)
{
if (mkey == MKEY_Up || mkey == MKEY_Down)
{
MenuSound("menu/cursor");
messageSelection = !messageSelection;
return true;
}
else if (mkey == MKEY_Enter)
{
// 0 is yes, 1 is no
HandleResult(!messageSelection);
return true;
}
else if (mkey == MKEY_Back)
{
HandleResult(false);
return true;
}
return false;
}
else
{
Close();
CloseSound();
return true;
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (mMessageMode == 1)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}
else
{
int sel = -1;
int fh = SmallFont.GetHeight() + 1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100;
if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + 2 * fh)
{
sel = y >= mMouseY + fh;
}
if (sel != -1 && sel != messageSelection)
{
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
messageSelection = sel;
if (type == MOUSE_Release)
{
return MenuEvent(MKEY_Enter, true);
}
return true;
}
}
}

View file

@ -56,8 +56,6 @@ class OptionMenuDescriptor : MenuDescriptor native
native int mPosition;
native bool mDontDim;
native void CalcIndent();
native OptionMenuItem GetItem(Name iname);
void Reset()
{
// Reset the default settings (ignore all other values in the struct)
@ -66,6 +64,25 @@ class OptionMenuDescriptor : MenuDescriptor native
mIndent = 0;
mDontDim = 0;
}
//=============================================================================
//
//
//
//=============================================================================
void CalcIndent()
{
// calculate the menu indent
int widest = 0, thiswidth;
for (int i = 0; i < mItems.Size(); i++)
{
thiswidth = mItems[i].GetIndent();
if (thiswidth > widest) widest = thiswidth;
}
mIndent = widest + 4;
}
}
@ -88,10 +105,27 @@ class OptionMenu : Menu
mParentMenu = parent;
mDesc = desc;
if (mDesc != NULL && mDesc.mSelectedItem == -1) mDesc.mSelectedItem = FirstSelectable();
mDesc.CalcIndent();
}
//=============================================================================
//
//
//
//=============================================================================
OptionMenuItem GetItem(Name name)
{
for(int i = 0; i < mDesc.mItems.Size(); i++)
{
Name nm = mDesc.mItems[i].GetAction();
if (nm == name) return mDesc.mItems[i];
}
return NULL;
}
//=============================================================================
//
//

View file

@ -136,7 +136,7 @@ class OptionMenuItemCommand : OptionMenuItemSubmenu
// don't execute if no menu is active
if (m == null) return false;
// don't execute if this item cannot be found in the current menu.
if (m.mDesc.GetItem(mAction) != self) return false;
if (m.GetItem(mAction) != self) return false;
Menu.MenuSound("menu/choose");
DoCommand(mAction);
return true;
@ -388,7 +388,7 @@ class EnterKey : Menu
let parent = OptionMenu(mParentMenu);
if (parent != null)
{
let it = parent.mDesc.GetItem('Controlmessage');
let it = parent.GetItem('Controlmessage');
if (it != null)
{
it.SetValue(0, which);

View file

@ -0,0 +1,124 @@
/*
** readthis.cpp
** Help screens
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
class ReadThisMenu : Menu
{
int mScreen;
int mInfoTic;
//=============================================================================
//
//
//
//=============================================================================
override void Drawer()
{
double alpha;
TextureID tex, prevpic;
if (mScreen == 0)
{
mScreen = 1;
mInfoTic = gametic;
}
// Did the mapper choose a custom help page via MAPINFO?
if (level.F1Pic.Length() != 0)
{
tex = TexMan.CheckForTexture(level.F1Pic, TexMan.Type_MiscPatch);
mScreen = 1;
}
if (!tex.IsValid())
{
tex = TexMan.CheckForTexture(gameinfo.infoPages[mScreen-1], TexMan.Type_MiscPatch);
}
if (mScreen > 1)
{
prevpic = TexMan.CheckForTexture(gameinfo.infoPages[mScreen-2], TexMan.Type_MiscPatch);
}
screen.Dim(0, 1.0, 0,0, screen.GetWidth(), screen.GetHeight());
alpha = MIN((gametic - mInfoTic) * (3. / Thinker.TICRATE), 1.);
if (alpha < 1. && prevpic.IsValid())
{
screen.DrawTexture (prevpic, false, 0, 0, DTA_Fullscreen, true);
}
else alpha = 1;
screen.DrawTexture (tex, false, 0, 0, DTA_Fullscreen, true, DTA_Alpha, alpha);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == MKEY_Enter)
{
MenuSound("menu/choose");
mScreen++;
mInfoTic = gametic;
if (level.F1Pic.Length() != 0 || mScreen > gameinfo.infoPages.Size())
{
Close();
}
return true;
}
else return Super.MenuEvent(mkey, fromcontroller);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}
}

View file

@ -1,15 +1,365 @@
/*
** menuinput.cpp
** The string input code
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010-2017 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// This is only the parts that are needed to make the menu fully work right now. More to come later.
class TextEnterMenu : Menu native
class TextEnterMenu : Menu
{
native bool mInputGridOkay;
const INPUTGRID_WIDTH = 13;
const INPUTGRID_HEIGHT = 5;
native static TextEnterMenu Open(Menu parent, String text, int maxlen, int sizemode, bool fromcontroller);
native String GetText();
const Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-=.,!?@'\":;[]()<>^#$%&*/_ \b";
String mEnterString;
int mEnterSize;
int mEnterPos;
int mSizeMode; // 1: size is length in chars. 2: also check string width
bool mInputGridOkay;
int InputGridX;
int InputGridY;
bool AllowColors;
//=============================================================================
//
//
//
//=============================================================================
// [TP] Added allowcolors
private void Init(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors)
{
Super.init(parent);
mEnterString = textbuffer;
mEnterSize = maxlen < 0 ? 0x7fffffff : maxlen;
mSizeMode = sizemode;
mInputGridOkay = showgrid || m_showinputgrid;
if (mEnterString.Length() > 0)
{
InputGridX = INPUTGRID_WIDTH - 1;
InputGridY = INPUTGRID_HEIGHT - 1;
}
else
{
// If we are naming a new save, don't start the cursor on "end".
InputGridX = 0;
InputGridY = 0;
}
AllowColors = allowcolors; // [TP]
}
static TextEnterMenu Open(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid = false, bool allowcolors = false)
{
let me = new("TextEnterMenu");
me.Init(parent, textbuffer, maxlen, sizemode, showgrid, allowcolors);
return me;
}
//=============================================================================
//
//
//
//=============================================================================
String GetText()
{
return mEnterString;
}
override bool TranslateKeyboardEvents()
{
return mInputGridOkay;
}
//=============================================================================
//
//
//
//=============================================================================
override bool Responder(InputEventData ev)
{
if (ev.type == InputEventData.GUI_Event)
{
// Save game and player name string input
if (ev.subtype == InputEventData.GUI_Char)
{
mInputGridOkay = false;
if (mEnterString.Length() < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString.AppendFormat("%c", ev.data1);
}
return true;
}
int ch = ev.data1;
if ((ev.subtype == InputEventData.GUI_KeyDown || ev.subtype == InputEventData.GUI_KeyRepeat) && ch == 8)
{
if (mEnterString.Length() > 0)
{
mEnterString.Truncate(mEnterString.Length() - 1);
}
}
else if (ev.subtype == InputEventData.GUI_KeyDown)
{
if (ch == UIEvent.Key_ESCAPE)
{
Menu parent = mParentMenu;
Close();
parent.MenuEvent(MKEY_Abort, false);
return true;
}
else if (ch == 13)
{
if (mEnterString.Length() > 0)
{
// [TP] If we allow color codes, colorize the string now.
if (AllowColors)
mEnterString = mEnterString.Filter();
Menu parent = mParentMenu;
parent.MenuEvent(MKEY_Input, false);
Close();
return true;
}
}
}
if (ev.subtype == InputEventData.GUI_KeyDown || ev.subtype == InputEventData.GUI_KeyRepeat)
{
return true;
}
}
return Super.Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (mMouseCapture || m_use_mouse == 1)
{
int cell_width = 18 * CleanXfac;
int cell_height = 12 * CleanYfac;
int screen_y = screen.GetHeight() - INPUTGRID_HEIGHT * cell_height;
int screen_x = (screen.GetWidth() - INPUTGRID_WIDTH * cell_width) / 2;
if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y)
{
InputGridX = (x - screen_x) / cell_width;
InputGridY = (y - screen_y) / cell_height;
if (type == MOUSE_Release)
{
if (MenuEvent(MKEY_Enter, true))
{
MenuSound("menu/choose");
if (m_use_mouse == 2) InputGridX = InputGridY = -1;
return true;
}
}
}
else
{
InputGridX = InputGridY = -1;
}
}
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int key, bool fromcontroller)
{
String InputGridChars = Chars;
if (key == MKEY_Back)
{
mParentMenu.MenuEvent(MKEY_Abort, false);
return Super.MenuEvent(key, fromcontroller);
}
if (fromcontroller)
{
mInputGridOkay = true;
}
if (mInputGridOkay)
{
int ch;
if (InputGridX == -1 || InputGridY == -1)
{
InputGridX = InputGridY = 0;
}
switch (key)
{
case MKEY_Down:
InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Up:
InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Right:
InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Left:
InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Clear:
if (mEnterString.Length() > 0)
{
mEnterString.Truncate(mEnterString.Length() - 1);
}
return true;
case MKEY_Enter:
if (mInputGridOkay)
{
String c = InputGridChars.CharAt(InputGridX + InputGridY * INPUTGRID_WIDTH);
int ch = c.CharCodeAt(0);
if (ch == 0) // end
{
if (mEnterString.Length() > 0)
{
Menu parent = mParentMenu;
Close();
parent.MenuEvent(MKEY_Input, false);
return true;
}
}
else if (ch == 8) // bs
{
if (mEnterString.Length() > 0)
{
mEnterString.Truncate(mEnterString.Length() - 1);
}
}
else if (mEnterString.Length() < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString = mEnterString .. c;
}
}
return true;
default:
break; // Keep GCC quiet
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
mParentMenu.Drawer();
if (mInputGridOkay)
{
String InputGridChars = Chars;
int cell_width = 18 * CleanXfac;
int cell_height = 12 * CleanYfac;
int top_padding = cell_height / 2 - SmallFont.GetHeight() * CleanYfac / 2;
// Darken the background behind the character grid.
screen.Dim(0, 0.8, 0, screen.GetHeight() - INPUTGRID_HEIGHT * cell_height, screen.GetWidth(), INPUTGRID_HEIGHT * cell_height);
if (InputGridX >= 0 && InputGridY >= 0)
{
// Highlight the background behind the selected character.
screen.Dim(Color(255,248,220), 0.6,
InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2,
InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen.GetHeight(),
cell_width, cell_height);
}
for (int y = 0; y < INPUTGRID_HEIGHT; ++y)
{
int yy = y * cell_height - INPUTGRID_HEIGHT * cell_height + screen.GetHeight();
for (int x = 0; x < INPUTGRID_WIDTH; ++x)
{
int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2;
int ch = InputGridChars.CharCodeAt(y * INPUTGRID_WIDTH + x);
int width = SmallFont.GetCharWidth(ch);
// The highlighted character is yellow; the rest are dark gray.
int colr = (x == InputGridX && y == InputGridY) ? Font.CR_YELLOW : Font.CR_DARKGRAY;
Color palcolor = (x == InputGridX && y == InputGridY) ? Color(160, 120, 0) : Color(120, 120, 120);
if (ch > 32)
{
// Draw a normal character.
screen.DrawChar(SmallFont, colr, xx + cell_width/2 - width*CleanXfac/2, yy + top_padding, ch, DTA_CleanNoMove, true);
}
else if (ch == 32)
{
// Draw the space as a box outline. We also draw it 50% wider than it really is.
int x1 = xx + cell_width/2 - width * CleanXfac * 3 / 4;
int x2 = x1 + width * 3 * CleanXfac / 2;
int y1 = yy + top_padding;
int y2 = y1 + SmallFont.GetHeight() * CleanYfac;
screen.Clear(x1, y1, x2, y1+CleanYfac, palcolor); // top
screen.Clear(x1, y2, x2, y2+CleanYfac, palcolor); // bottom
screen.Clear(x1, y1+CleanYfac, x1+CleanXfac, y2, palcolor); // left
screen.Clear(x2-CleanXfac, y1+CleanYfac, x2, y2, palcolor); // right
}
else if (ch == 8 || ch == 0)
{
// Draw the backspace and end "characters".
String str = ch == 8 ? "BS" : "ED";
screen.DrawText(SmallFont, colr,
xx + cell_width/2 - SmallFont.StringWidth(str)*CleanXfac/2,
yy + top_padding, str, DTA_CleanNoMove, true);
}
}
}
}
Super.Drawer();
}
}