This commit is contained in:
Rachael Alexanderson 2017-02-12 21:39:20 -05:00
commit 8c176575c8
64 changed files with 5349 additions and 4585 deletions

View file

@ -914,7 +914,6 @@ set( FASTMATH_PCH_SOURCES
SkylineBinPack.cpp
intermission/intermission.cpp
intermission/intermission_parse.cpp
menu/colorpickermenu.cpp
menu/joystickmenu.cpp
menu/listmenu.cpp
menu/loadsavemenu.cpp
@ -923,7 +922,6 @@ set( FASTMATH_PCH_SOURCES
menu/menuinput.cpp
menu/messagebox.cpp
menu/optionmenu.cpp
menu/playerdisplay.cpp
menu/playermenu.cpp
menu/readthis.cpp
menu/videomenu.cpp

View file

@ -44,6 +44,7 @@
#include "i_system.h"
#include "d_event.h"
#include "w_wad.h"
#include "templates.h"
#include <math.h>
#include <stdlib.h>
@ -261,11 +262,27 @@ static const char *ConfigKeyName(int keynum)
//
//=============================================================================
DEFINE_ACTION_FUNCTION(FKeyBindings, SetBind)
{
PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
PARAM_INT(k);
PARAM_STRING(cmd);
self->SetBind(k, cmd);
return 0;
}
//=============================================================================
//
//
//
//=============================================================================
void C_NameKeys (char *str, int first, int second)
{
int c = 0;
*str = 0;
if (second == first) second = 0;
if (first)
{
c++;
@ -284,6 +301,16 @@ void C_NameKeys (char *str, int first, int second)
*str = '\0';
}
DEFINE_ACTION_FUNCTION(FKeyBindings, NameKeys)
{
PARAM_PROLOGUE;
PARAM_INT(k1);
PARAM_INT(k2);
char buffer[120];
C_NameKeys(buffer, k1, k2);
ACTION_RETURN_STRING(buffer);
}
//=============================================================================
//
//
@ -445,6 +472,17 @@ int FKeyBindings::GetKeysForCommand (const char *cmd, int *first, int *second)
return c;
}
DEFINE_ACTION_FUNCTION(FKeyBindings, GetKeysForCommand)
{
PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
PARAM_STRING(cmd);
int k1, k2, c;
self->GetKeysForCommand(cmd.GetChars(), &k1, &k2);
if (numret > 0) ret[0].SetInt(k1);
if (numret > 1) ret[1].SetInt(k2);
return MIN(numret, 2);
}
//=============================================================================
//
//
@ -464,6 +502,14 @@ void FKeyBindings::UnbindACommand (const char *str)
}
}
DEFINE_ACTION_FUNCTION(FKeyBindings, UnbindACommand)
{
PARAM_SELF_STRUCT_PROLOGUE(FKeyBindings);
PARAM_STRING(cmd);
self->UnbindACommand(cmd);
return 0;
}
//=============================================================================
//
//

View file

@ -1336,6 +1336,14 @@ DEFINE_ACTION_FUNCTION(_Console, HideConsole)
return 0;
}
DEFINE_ACTION_FUNCTION(_Console, Printf)
{
PARAM_PROLOGUE;
FString s = FStringFormat(param, defaultparam, numparam, ret, numret);
Printf("%s\n", s.GetChars());
return 0;
}
static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
{
int data1 = ev->data1;

View file

@ -192,7 +192,7 @@ DEFINE_ACTION_FUNCTION(_CVar, GetFloat)
{
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
auto v = self->GetGenericRep(CVAR_Float);
ACTION_RETURN_FLOAT(v.Int);
ACTION_RETURN_FLOAT(v.Float);
}
DEFINE_ACTION_FUNCTION(_CVar, GetString)
@ -202,6 +202,36 @@ DEFINE_ACTION_FUNCTION(_CVar, GetString)
ACTION_RETURN_STRING(v.String);
}
DEFINE_ACTION_FUNCTION(_CVar, SetInt)
{
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
PARAM_INT(val);
UCVarValue v;
v.Int = val;
self->SetGenericRep(v, CVAR_Int);
return 0;
}
DEFINE_ACTION_FUNCTION(_CVar, SetFloat)
{
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
PARAM_FLOAT(val);
UCVarValue v;
v.Float = val;
self->SetGenericRep(v, CVAR_Float);
return 0;
}
DEFINE_ACTION_FUNCTION(_CVar, SetString)
{
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
PARAM_STRING(val);
UCVarValue v;
v.String = val.GetChars();
self->SetGenericRep(v, CVAR_String);
return 0;
}
bool FBaseCVar::ToBool (UCVarValue value, ECVarType type)
{
switch (type)
@ -643,6 +673,12 @@ void FBaseCVar::DisableCallbacks ()
m_UseCallback = false;
}
DEFINE_ACTION_FUNCTION(_CVar, GetRealType)
{
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
ACTION_RETURN_INT(self->GetRealType());
}
//
// Boolean cvar implementation
//
@ -1082,6 +1118,13 @@ void FBaseCVar::ResetToDefault ()
}
}
DEFINE_ACTION_FUNCTION(_CVar, ResetToDefault)
{
PARAM_SELF_STRUCT_PROLOGUE(FBaseCVar);
self->ResetToDefault();
return 0;
}
//
// Flag cvar implementation
//
@ -1487,6 +1530,13 @@ FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev)
return var;
}
DEFINE_ACTION_FUNCTION(_CVar, FindCVar)
{
PARAM_PROLOGUE;
PARAM_NAME(name);
ACTION_RETURN_POINTER(FindCVar(name, nullptr));
}
FBaseCVar *FindCVarSub (const char *var_name, int namelen)
{
FBaseCVar *var;

View file

@ -662,6 +662,14 @@ void C_DoCommand (const char *cmd, int keynum)
}
}
DEFINE_ACTION_FUNCTION(_Console, DoCommand)
{
PARAM_PROLOGUE;
PARAM_STRING(cmd);
C_DoCommand(cmd);
return 0;
}
void AddCommandString (char *cmd, int keynum)
{
char *brkpt;

View file

@ -614,16 +614,16 @@ int strbin (char *str)
case '6':
case '7':
c = 0;
for (i = 0; i < 3; i++) {
c <<= 3;
for (i = 0; i < 2; i++)
{
p++;
if (*p >= '0' && *p <= '7')
c += *p-'0';
c = (c << 3) + *p - '0';
else
{
p--;
break;
}
p++;
}
*str++ = c;
break;
@ -717,16 +717,16 @@ FString strbin1 (const char *start)
case '6':
case '7':
c = 0;
for (i = 0; i < 3; i++) {
c <<= 3;
for (i = 0; i < 2; i++)
{
p++;
if (*p >= '0' && *p <= '7')
c += *p-'0';
c = (c << 3) + *p - '0';
else
{
p--;
break;
}
p++;
}
result << c;
break;

View file

@ -2293,7 +2293,7 @@ static int PatchStrings (int dummy)
holdstring.StripRight();
if (holdstring.Len() > 0 && holdstring[holdstring.Len()-1] == '\\')
{
holdstring.Truncate((long)holdstring.Len()-1);
holdstring.Truncate(holdstring.Len()-1);
Line2 = igets ();
}
else

View file

@ -2520,7 +2520,10 @@ void D_DoomMain (void)
// Create replacements for dehacked pickups
FinishDehPatch();
if (!batchrun) Printf("M_Init: Init menus.\n");
M_Init();
// clean up the compiler symbols which are not needed any longer.
RemoveUnusedSymbols();
@ -2538,9 +2541,6 @@ void D_DoomMain (void)
bglobal.spawn_tries = 0;
bglobal.wanted_botnum = bglobal.getspawned.Size();
if (!batchrun) Printf ("M_Init: Init menus.\n");
M_Init ();
if (!batchrun) Printf ("P_Init: Init Playloop state.\n");
StartScreen->LoadingStatus ("Init game engine", 0x3f);
AM_StaticInit();
@ -2827,3 +2827,10 @@ void FStartupScreen::NetMessage(char const *,...) {}
void FStartupScreen::NetDone(void) {}
bool FStartupScreen::NetLoop(bool (*)(void *),void *) { return false; }
DEFINE_FIELD_X(InputEvent, event_t, type)
DEFINE_FIELD_X(InputEvent, event_t, subtype)
DEFINE_FIELD_X(InputEvent, event_t, data1)
DEFINE_FIELD_X(InputEvent, event_t, data2)
DEFINE_FIELD_X(InputEvent, event_t, data3)
DEFINE_FIELD_X(InputEvent, event_t, x)
DEFINE_FIELD_X(InputEvent, event_t, y)

View file

@ -204,6 +204,7 @@ enum EObjectFlags
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
OF_Released = 1 << 12, // Object was released from the GC system and should not be processed by GC function
OF_Abstract = 1 << 13, // Marks a class that cannot be created with CreateNew
};
template<class T> class TObjPtr;

View file

@ -1985,7 +1985,7 @@ void PDynArray::DestroyValue(void *addr) const
void PDynArray::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) const
{
memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array.
if (base != nullptr) memset((char*)base + offset, 0, sizeof(FArray)); // same as constructing an empty array.
if (special != nullptr)
{
special->Push(std::make_pair(this, offset));
@ -3047,6 +3047,10 @@ DObject *PClass::CreateNew() const
else
memset (mem, 0, Size);
if (ConstructNative == nullptr)
{
I_Error("Attempt to instantiate abstract class %s.", TypeName.GetChars());
}
ConstructNative (mem);
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
InitializeSpecials(mem, Defaults);
@ -3165,8 +3169,7 @@ void PClass::InitializeDefaults()
{
// Copy parent values from the parent defaults.
assert(ParentClass != nullptr);
ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
for (const PField *field : Fields)
{
if (!(field->Flags & VARF_Native))

View file

@ -101,7 +101,7 @@ EXTERN_CVAR (Float, snd_musicvolume) // maximum volume for music
// Status flags for refresh.
//
enum EMenuState
enum EMenuState : int
{
MENU_Off, // Menu is closed
MENU_On, // Menu is opened

View file

@ -2307,7 +2307,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
WriteZip(filename, savegame_filenames, savegame_content);
M_NotifyNewSave (filename.GetChars(), description, okForQuicksave);
savegameManager.NotifyNewSave (filename.GetChars(), description, okForQuicksave);
// delete the JSON buffers we created just above. Everything else will
// either still be needed or taken care of automatically.

View file

@ -589,7 +589,7 @@ bool FMapInfoParser::ParseLookupName(FString &dest)
}
while (sc.CheckString(","));
// strip off the last newline
dest.Truncate(long(dest.Len()-1));
dest.Truncate(dest.Len()-1);
return false;
}
}

View file

@ -1,154 +0,0 @@
/*
** colorpickermenu.cpp
** The color picker menu
**
**---------------------------------------------------------------------------
** 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 <float.h>
#include "menu/menu.h"
#include "c_dispatch.h"
#include "w_wad.h"
#include "sc_man.h"
#include "v_font.h"
#include "g_level.h"
#include "d_player.h"
#include "v_video.h"
#include "gi.h"
#include "i_system.h"
#include "c_bind.h"
#include "v_palette.h"
#include "d_event.h"
#include "d_gui.h"
#define NO_IMP
#include "menu/optionmenuitems.h"
class DColorPickerMenu : public DOptionMenu
{
DECLARE_CLASS(DColorPickerMenu, DOptionMenu)
public:
float mRed;
float mGreen;
float mBlue;
int mGridPosX;
int mGridPosY;
int mStartItem;
FColorCVar *mCVar;
DColorPickerMenu(DMenu *parent, const char *name, DOptionMenuDescriptor *desc, FColorCVar *cvar)
{
mStartItem = desc->mItems.Size();
mRed = (float)RPART(DWORD(*cvar));
mGreen = (float)GPART(DWORD(*cvar));
mBlue = (float)BPART(DWORD(*cvar));
mGridPosX = 0;
mGridPosY = 0;
mCVar = cvar;
// This menu uses some featurs that are hard to implement in an external control lump
// so it creates its own list of menu items.
desc->mItems.Resize(mStartItem+8);
desc->mItems[mStartItem+0] = new DOptionMenuItemStaticText(name, false);
desc->mItems[mStartItem+1] = new DOptionMenuItemStaticText(" ", false);
desc->mItems[mStartItem+2] = new DOptionMenuSliderVar("Red", &mRed, 0, 255, 15, 0);
desc->mItems[mStartItem+3] = new DOptionMenuSliderVar("Green", &mGreen, 0, 255, 15, 0);
desc->mItems[mStartItem+4] = new DOptionMenuSliderVar("Blue", &mBlue, 0, 255, 15, 0);
desc->mItems[mStartItem+5] = new DOptionMenuItemStaticText(" ", false);
desc->mItems[mStartItem+6] = new DOptionMenuItemCommand("Undo changes", "undocolorpic");
desc->mItems[mStartItem+7] = new DOptionMenuItemStaticText(" ", false);
for (auto &p : desc->mItems)
{
GC::WriteBarrier(p);
}
desc->mSelectedItem = mStartItem + 2;
Init(parent, desc);
desc->mIndent = 0;
desc->CalcIndent();
}
void OnDestroy() override
{
if (mStartItem >= 0)
{
mDesc->mItems.Resize(mStartItem);
UCVarValue val;
val.Int = MAKERGB(int(mRed), int(mGreen), int(mBlue));
if (mCVar != NULL) mCVar->SetGenericRep (val, CVAR_Int);
mStartItem = -1;
}
}
void Reset()
{
mRed = (float)RPART(DWORD(*mCVar));
mGreen = (float)GPART(DWORD(*mCVar));
mBlue = (float)BPART(DWORD(*mCVar));
}
};
IMPLEMENT_CLASS(DColorPickerMenu, true, false)
CCMD(undocolorpic)
{
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DColorPickerMenu)))
{
static_cast<DColorPickerMenu*>(DMenu::CurrentMenu)->Reset();
}
}
DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar)
{
DMenuDescriptor **desc = MenuDescriptors.CheckKey(NAME_Colorpickermenu);
if (desc != NULL && (*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
{
return new DColorPickerMenu(parent, name, (DOptionMenuDescriptor*)(*desc), cvar);
}
else
{
return NULL;
}
}
DEFINE_FIELD(DColorPickerMenu, mRed);
DEFINE_FIELD(DColorPickerMenu, mGreen);
DEFINE_FIELD(DColorPickerMenu, mBlue);
DEFINE_FIELD(DColorPickerMenu, mGridPosX);
DEFINE_FIELD(DColorPickerMenu, mGridPosY);
DEFINE_FIELD(DColorPickerMenu, mStartItem);
DEFINE_FIELD(DColorPickerMenu, mCVar);

View file

@ -51,220 +51,79 @@
#include "i_music.h"
#include "m_joy.h"
#define NO_IMP
#include "optionmenuitems.h"
static TArray<IJoystickConfig *> Joysticks;
IJoystickConfig *SELECTED_JOYSTICK;
DEFINE_ACTION_FUNCTION(DMenu, GetCurrentJoystickConfig)
{
ACTION_RETURN_POINTER(SELECTED_JOYSTICK);
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetSensitivity)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
ACTION_RETURN_FLOAT(self->GetSensitivity());
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetSensitivity)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_FLOAT(sens);
self->SetSensitivity((float)sens);
return 0;
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisScale)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
ACTION_RETURN_FLOAT(self->GetAxisScale(axis));
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisScale)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
PARAM_FLOAT(sens);
self->SetAxisScale(axis, (float)sens);
return 0;
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisDeadZone)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
ACTION_RETURN_FLOAT(self->GetAxisDeadZone(axis));
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisDeadZone)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
PARAM_FLOAT(dz);
self->SetAxisDeadZone(axis, (float)dz);
return 0;
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, GetAxisMap)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
ACTION_RETURN_INT(self->GetAxisMap(axis));
}
DEFINE_ACTION_FUNCTION(IJoystickConfig, SetAxisMap)
{
PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig);
PARAM_INT(axis);
PARAM_INT(map);
self->SetAxisMap(axis, (EJoyAxis)map);
return 0;
}
DOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy);
//=============================================================================
//
//
//
//=============================================================================
class DOptionMenuSliderJoySensitivity : public DOptionMenuSliderBase
{
public:
DOptionMenuSliderJoySensitivity(const char *label, double min, double max, double step, int showval)
: DOptionMenuSliderBase(label, min, max, step, showval)
{
}
double GetSliderValue()
{
return SELECTED_JOYSTICK->GetSensitivity();
}
void SetSliderValue(double val)
{
SELECTED_JOYSTICK->SetSensitivity(float(val));
}
};
//=============================================================================
//
//
//
//=============================================================================
class DOptionMenuSliderJoyScale : public DOptionMenuSliderBase
{
int mAxis;
int mNeg;
public:
DOptionMenuSliderJoyScale(const char *label, int axis, double min, double max, double step, int showval)
: DOptionMenuSliderBase(label, min, max, step, showval)
{
mAxis = axis;
mNeg = 1;
}
double GetSliderValue()
{
double d = SELECTED_JOYSTICK->GetAxisScale(mAxis);
mNeg = d < 0? -1:1;
return d;
}
void SetSliderValue(double val)
{
SELECTED_JOYSTICK->SetAxisScale(mAxis, float(val * mNeg));
}
};
//=============================================================================
//
//
//
//=============================================================================
class DOptionMenuSliderJoyDeadZone : public DOptionMenuSliderBase
{
int mAxis;
int mNeg;
public:
DOptionMenuSliderJoyDeadZone(const char *label, int axis, double min, double max, double step, int showval)
: DOptionMenuSliderBase(label, min, max, step, showval)
{
mAxis = axis;
mNeg = 1;
}
double GetSliderValue()
{
double d = SELECTED_JOYSTICK->GetAxisDeadZone(mAxis);
mNeg = d < 0? -1:1;
return d;
}
void SetSliderValue(double val)
{
SELECTED_JOYSTICK->SetAxisDeadZone(mAxis, float(val * mNeg));
}
};
//=============================================================================
//
//
//
//=============================================================================
class DOptionMenuItemJoyMap : public DOptionMenuItemOptionBase
{
int mAxis;
public:
DOptionMenuItemJoyMap(const char *label, int axis, const char *values, int center)
: DOptionMenuItemOptionBase(label, "none", values, NULL, center)
{
mAxis = axis;
}
int GetSelection()
{
double f = SELECTED_JOYSTICK->GetAxisMap(mAxis);
FOptionValues **opt = OptionValues.CheckKey(mValues);
if (opt != NULL && *opt != NULL)
{
// Map from joystick axis to menu selection.
for(unsigned i = 0; i < (*opt)->mValues.Size(); i++)
{
if (fabs(f - (*opt)->mValues[i].Value) < FLT_EPSILON)
{
return i;
}
}
}
return -1;
}
void SetSelection(int selection)
{
FOptionValues **opt = OptionValues.CheckKey(mValues);
// Map from menu selection to joystick axis.
if (opt == NULL || *opt == NULL || (unsigned)selection >= (*opt)->mValues.Size())
{
selection = JOYAXIS_None;
}
else
{
selection = (int)(*opt)->mValues[selection].Value;
}
SELECTED_JOYSTICK->SetAxisMap(mAxis, (EJoyAxis)selection);
}
};
//=============================================================================
//
//
//
//=============================================================================
class DOptionMenuItemInverter : public DOptionMenuItemOptionBase
{
int mAxis;
public:
DOptionMenuItemInverter(const char *label, int axis, int center)
: DOptionMenuItemOptionBase(label, "none", "YesNo", NULL, center)
{
mAxis = axis;
}
int GetSelection()
{
float f = SELECTED_JOYSTICK->GetAxisScale(mAxis);
return f > 0? 0:1;
}
void SetSelection(int Selection)
{
float f = fabsf(SELECTED_JOYSTICK->GetAxisScale(mAxis));
if (Selection) f*=-1;
SELECTED_JOYSTICK->SetAxisScale(mAxis, f);
}
};
class DJoystickConfigMenu : public DOptionMenu
{
DECLARE_CLASS(DJoystickConfigMenu, DOptionMenu)
};
IMPLEMENT_CLASS(DJoystickConfigMenu, false, false)
//=============================================================================
//
// Executes a CCMD, action is a CCMD name
//
//=============================================================================
class DOptionMenuItemJoyConfigMenu : public DOptionMenuItemSubmenu
{
DECLARE_CLASS(DOptionMenuItemJoyConfigMenu, DOptionMenuItemSubmenu)
IJoystickConfig *mJoy;
public:
DOptionMenuItemJoyConfigMenu(const char *label = nullptr, IJoystickConfig *joy = nullptr)
: DOptionMenuItemSubmenu(label, "JoystickConfigMenu")
{
mJoy = joy;
}
bool Activate()
{
UpdateJoystickConfigMenu(mJoy);
return DOptionMenuItemSubmenu::Activate();
}
};
IMPLEMENT_CLASS(DOptionMenuItemJoyConfigMenu, false, false)
/*=======================================
*
* Joystick Menu
@ -277,12 +136,12 @@ DOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy)
if (desc != NULL && (*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
{
DOptionMenuDescriptor *opt = (DOptionMenuDescriptor *)*desc;
DOptionMenuItem *it;
DMenuItemBase *it;
opt->mItems.Clear();
if (joy == NULL)
{
opt->mTitle = "Configure Controller";
it = new DOptionMenuItemStaticText("Invalid controller specified for menu", false);
it = CreateOptionMenuItemStaticText("Invalid controller specified for menu", false);
opt->mItems.Push(it);
}
else
@ -291,34 +150,34 @@ DOptionMenuDescriptor *UpdateJoystickConfigMenu(IJoystickConfig *joy)
SELECTED_JOYSTICK = joy;
it = new DOptionMenuSliderJoySensitivity("Overall sensitivity", 0, 2, 0.1, 3);
it = CreateOptionMenuSliderJoySensitivity("Overall sensitivity", 0, 2, 0.1, 3);
opt->mItems.Push(it);
it = new DOptionMenuItemStaticText(" ", false);
it = CreateOptionMenuItemStaticText(" ", false);
opt->mItems.Push(it);
if (joy->GetNumAxes() > 0)
{
it = new DOptionMenuItemStaticText("Axis Configuration", true);
it = CreateOptionMenuItemStaticText("Axis Configuration", true);
opt->mItems.Push(it);
for (int i = 0; i < joy->GetNumAxes(); ++i)
{
it = new DOptionMenuItemStaticText(" ", false);
it = CreateOptionMenuItemStaticText(" ", false);
opt->mItems.Push(it);
it = new DOptionMenuItemJoyMap(joy->GetAxisName(i), i, "JoyAxisMapNames", false);
it = CreateOptionMenuItemJoyMap(joy->GetAxisName(i), i, "JoyAxisMapNames", false);
opt->mItems.Push(it);
it = new DOptionMenuSliderJoyScale("Overall sensitivity", i, 0, 4, 0.1, 3);
it = CreateOptionMenuSliderJoyScale("Overall sensitivity", i, 0, 4, 0.1, 3);
opt->mItems.Push(it);
it = new DOptionMenuItemInverter("Invert", i, false);
it = CreateOptionMenuItemInverter("Invert", i, false);
opt->mItems.Push(it);
it = new DOptionMenuSliderJoyDeadZone("Dead Zone", i, 0, 0.9, 0.05, 3);
it = CreateOptionMenuSliderJoyDeadZone("Dead Zone", i, 0, 0.9, 0.05, 3);
opt->mItems.Push(it);
}
}
else
{
it = new DOptionMenuItemStaticText("No configurable axes", false);
it = CreateOptionMenuItemStaticText("No configurable axes", false);
opt->mItems.Push(it);
}
}
@ -344,7 +203,7 @@ void UpdateJoystickMenu(IJoystickConfig *selected)
if (desc != NULL && (*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
{
DOptionMenuDescriptor *opt = (DOptionMenuDescriptor *)*desc;
DOptionMenuItem *it;
DMenuItemBase *it;
opt->mItems.Clear();
int i;
@ -368,40 +227,40 @@ void UpdateJoystickMenu(IJoystickConfig *selected)
}
// Todo: Block joystick for changing this one.
it = new DOptionMenuItemOption("Enable controller support", "use_joystick", "YesNo", NULL, false);
it = CreateOptionMenuItemOption("Enable controller support", "use_joystick", "YesNo", NULL, false);
opt->mItems.Push(it);
#ifdef _WIN32
it = new DOptionMenuItemOption("Enable DirectInput controllers", "joy_dinput", "YesNo", NULL, false);
it = CreateOptionMenuItemOption("Enable DirectInput controllers", "joy_dinput", "YesNo", NULL, false);
opt->mItems.Push(it);
it = new DOptionMenuItemOption("Enable XInput controllers", "joy_xinput", "YesNo", NULL, false);
it = CreateOptionMenuItemOption("Enable XInput controllers", "joy_xinput", "YesNo", NULL, false);
opt->mItems.Push(it);
it = new DOptionMenuItemOption("Enable raw PlayStation 2 adapters", "joy_ps2raw", "YesNo", NULL, false);
it = CreateOptionMenuItemOption("Enable raw PlayStation 2 adapters", "joy_ps2raw", "YesNo", NULL, false);
opt->mItems.Push(it);
#endif
it = new DOptionMenuItemStaticText(" ", false);
it = CreateOptionMenuItemStaticText(" ", false);
opt->mItems.Push(it);
if (Joysticks.Size() == 0)
{
it = new DOptionMenuItemStaticText("No controllers detected", false);
it = CreateOptionMenuItemStaticText("No controllers detected", false);
opt->mItems.Push(it);
if (!use_joystick)
{
it = new DOptionMenuItemStaticText("Controller support must be", false);
it = CreateOptionMenuItemStaticText("Controller support must be", false);
opt->mItems.Push(it);
it = new DOptionMenuItemStaticText("enabled to detect any", false);
it = CreateOptionMenuItemStaticText("enabled to detect any", false);
opt->mItems.Push(it);
}
}
else
{
it = new DOptionMenuItemStaticText("Configure controllers:", false);
it = CreateOptionMenuItemStaticText("Configure controllers:", false);
opt->mItems.Push(it);
for (int i = 0; i < (int)Joysticks.Size(); ++i)
{
it = new DOptionMenuItemJoyConfigMenu(Joysticks[i]->GetName(), Joysticks[i]);
it = CreateOptionMenuItemJoyConfigMenu(Joysticks[i]->GetName(), Joysticks[i]);
opt->mItems.Push(it);
if (i == itemnum) opt->mSelectedItem = opt->mItems.Size();
}
@ -429,7 +288,7 @@ void UpdateJoystickMenu(IJoystickConfig *selected)
if (i == (int)Joysticks.Size())
{
SELECTED_JOYSTICK = NULL;
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf(RUNTIME_CLASS(DJoystickConfigMenu)))
if (DMenu::CurrentMenu != NULL && DMenu::CurrentMenu->IsKindOf("JoystickConfigMenu"))
{
DMenu::CurrentMenu->Close();
}

View file

@ -278,309 +278,4 @@ void DListMenu::Drawer ()
// base class for menu items
//
//=============================================================================
IMPLEMENT_CLASS(DMenuItemBase, true, false)
bool DMenuItemBase::CheckCoordinate(int x, int y)
{
return false;
}
void DMenuItemBase::Ticker()
{
}
void DMenuItemBase::Drawer(bool selected)
{
}
bool DMenuItemBase::Selectable()
{
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);
}
}
bool DMenuItemBase::Activate()
{
return false; // cannot be activated
}
FName DMenuItemBase::GetAction(int *pparam)
{
return mAction;
}
bool DMenuItemBase::SetString(int i, const char *s)
{
return false;
}
bool DMenuItemBase::GetString(int i, char *s, int len)
{
return false;
}
bool DMenuItemBase::SetValue(int i, int value)
{
return false;
}
bool DMenuItemBase::GetValue(int i, int *pvalue)
{
return false;
}
void DMenuItemBase::Enable(bool on)
{
mEnabled = on;
}
bool DMenuItemBase::MenuEvent(int mkey, bool fromcontroller)
{
return false;
}
DEFINE_ACTION_FUNCTION(DMenuItemBase, MenuEvent)
{
PARAM_SELF_PROLOGUE(DMenuItemBase);
PARAM_INT(key);
PARAM_BOOL(fromcontroller);
ACTION_RETURN_BOOL(self->MenuEvent(key, fromcontroller));
}
bool DMenuItemBase::MouseEvent(int type, int x, int y)
{
return false;
}
bool DMenuItemBase::CheckHotkey(int c)
{
return false;
}
int DMenuItemBase::GetWidth()
{
return 0;
}
//=============================================================================
//
// static patch
//
//=============================================================================
IMPLEMENT_CLASS(DListMenuItemStaticPatch, false, false)
DListMenuItemStaticPatch::DListMenuItemStaticPatch(int x, int y, FTextureID patch, bool centered)
: DMenuItemBase(x, y)
{
mTexture = patch;
mCentered = centered;
}
void DListMenuItemStaticPatch::Drawer(bool selected)
{
if (!mTexture.Exists())
{
return;
}
int x = mXpos;
FTexture *tex = TexMan(mTexture);
if (mYpos >= 0)
{
if (mCentered) x -= tex->GetScaledWidth()/2;
screen->DrawTexture (tex, x, mYpos, DTA_Clean, true, TAG_DONE);
}
else
{
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
if (mCentered) x -= (tex->GetScaledWidth()*CleanXfac)/2;
screen->DrawTexture (tex, x, -mYpos*CleanYfac, DTA_CleanNoMove, true, TAG_DONE);
}
}
//=============================================================================
//
// static text
//
//=============================================================================
IMPLEMENT_CLASS(DListMenuItemStaticText, false, false)
DListMenuItemStaticText::DListMenuItemStaticText(int x, int y, const char *text, FFont *font, EColorRange color, bool centered)
: DMenuItemBase(x, y)
{
mText = text;
mFont = font;
mColor = color;
mCentered = centered;
}
void DListMenuItemStaticText::Drawer(bool selected)
{
if (mText.IsNotEmpty())
{
const char *text = mText;
if (*text == '$') text = GStrings(text+1);
if (mYpos >= 0)
{
int x = mXpos;
if (mCentered) x -= mFont->StringWidth(text)/2;
screen->DrawText(mFont, mColor, x, mYpos, text, DTA_Clean, true, TAG_DONE);
}
else
{
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
if (mCentered) x -= (mFont->StringWidth(text)*CleanXfac)/2;
screen->DrawText (mFont, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true, TAG_DONE);
}
}
}
//=============================================================================
//
// base class for selectable items
//
//=============================================================================
IMPLEMENT_CLASS(DListMenuItemSelectable, false, false)
DListMenuItemSelectable::DListMenuItemSelectable(int x, int y, int height, FName action, int param)
: DMenuItemBase(x, y, action)
{
mHeight = height;
mParam = param;
mHotkey = 0;
}
bool DListMenuItemSelectable::CheckCoordinate(int x, int y)
{
return mEnabled && y >= mYpos && y < mYpos + mHeight; // no x check here
}
bool DListMenuItemSelectable::Selectable()
{
return mEnabled;
}
bool DListMenuItemSelectable::Activate()
{
M_SetMenu(mAction, mParam);
return true;
}
FName DListMenuItemSelectable::GetAction(int *pparam)
{
if (pparam != NULL) *pparam = mParam;
return mAction;
}
bool DListMenuItemSelectable::CheckHotkey(int c)
{
return c == tolower(mHotkey);
}
bool DListMenuItemSelectable::MouseEvent(int type, int x, int y)
{
if (type == DMenu::MOUSE_Release)
{
if (NULL != DMenu::CurrentMenu && DMenu::CurrentMenu->MenuEvent(MKEY_Enter, true))
{
return true;
}
}
return false;
}
//=============================================================================
//
// text item
//
//=============================================================================
IMPLEMENT_CLASS(DListMenuItemText, false, false)
DListMenuItemText::DListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, EColorRange color2, FName child, int param)
: DListMenuItemSelectable(x, y, height, child, param)
{
mText = ncopystring(text);
mFont = font;
mColor = color;
mColorSelected = color2;
mHotkey = hotkey;
}
void DListMenuItemText::OnDestroy()
{
if (mText != NULL)
{
delete [] mText;
}
}
void DListMenuItemText::Drawer(bool selected)
{
const char *text = mText;
if (text != NULL)
{
if (*text == '$') text = GStrings(text+1);
screen->DrawText(mFont, selected ? mColorSelected : mColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
}
}
int DListMenuItemText::GetWidth()
{
const char *text = mText;
if (text != NULL)
{
if (*text == '$') text = GStrings(text+1);
return mFont->StringWidth(text);
}
return 1;
}
//=============================================================================
//
// patch item
//
//=============================================================================
IMPLEMENT_CLASS(DListMenuItemPatch, false, false)
DListMenuItemPatch::DListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID patch, FName child, int param)
: DListMenuItemSelectable(x, y, height, child, param)
{
mHotkey = hotkey;
mTexture = patch;
}
void DListMenuItemPatch::Drawer(bool selected)
{
screen->DrawTexture (TexMan(mTexture), mXpos, mYpos, DTA_Clean, true, TAG_DONE);
}
int DListMenuItemPatch::GetWidth()
{
return mTexture.isValid()
? TexMan[mTexture]->GetScaledWidth()
: 0;
}
IMPLEMENT_CLASS(DMenuItemBase, false, false)

File diff suppressed because it is too large Load diff

View file

@ -70,8 +70,19 @@ 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);
}
int DMenu::MenuTime;
DEFINE_ACTION_FUNCTION(DMenu, MenuTime)
{
ACTION_RETURN_INT(DMenu::MenuTime);
}
FGameStartup GameStartupInfo;
EMenuState menuactive;
bool M_DemoNoPlay;
@ -82,6 +93,8 @@ int BackbuttonTime;
float BackbuttonAlpha;
static bool MenuEnabled = true;
void M_InitVideoModes();
#define KEY_REPEAT_DELAY (TICRATE*5/12)
#define KEY_REPEAT_RATE (3)
@ -96,6 +109,14 @@ IMPLEMENT_CLASS(DMenuDescriptor, false, false)
IMPLEMENT_CLASS(DListMenuDescriptor, false, false)
IMPLEMENT_CLASS(DOptionMenuDescriptor, false, false)
DEFINE_ACTION_FUNCTION(DMenuDescriptor, GetDescriptor)
{
PARAM_PROLOGUE;
PARAM_NAME(name);
DMenuDescriptor **desc = MenuDescriptors.CheckKey(name);
auto retn = desc ? *desc : nullptr;
ACTION_RETURN_OBJECT(retn);
}
size_t DListMenuDescriptor::PropagateMark()
{
@ -180,6 +201,26 @@ bool DMenu::Responder (event_t *ev)
return false;
}
DEFINE_ACTION_FUNCTION(DMenu, Responder)
{
PARAM_SELF_PROLOGUE(DMenu);
PARAM_POINTER(ev, event_t);
ACTION_RETURN_BOOL(self->Responder(ev));
}
bool DMenu::CallResponder(event_t *ev)
{
IFVIRTUAL(DMenu, Responder)
{
VMValue params[] = { (DObject*)this, ev};
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
return !!retval;
}
else return Responder(ev);
}
//=============================================================================
//
//
@ -337,6 +378,24 @@ void DMenu::Ticker ()
{
}
DEFINE_ACTION_FUNCTION(DMenu, Ticker)
{
PARAM_SELF_PROLOGUE(DMenu);
self->Drawer();
return 0;
}
void DMenu::CallTicker()
{
IFVIRTUAL(DMenu, Ticker)
{
VMValue params[] = { (DObject*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
else Drawer();
}
void DMenu::Drawer ()
{
if (this == DMenu::CurrentMenu && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse)
@ -375,6 +434,20 @@ void DMenu::CallDrawer()
else Drawer();
}
DEFINE_ACTION_FUNCTION(DMenu, Close)
{
PARAM_SELF_PROLOGUE(DMenu);
self->Close();
return 0;
}
DEFINE_ACTION_FUNCTION(DMenu, GetItem)
{
PARAM_SELF_PROLOGUE(DMenu);
PARAM_NAME(name);
ACTION_RETURN_OBJECT(self->GetItem(name));
}
bool DMenu::DimAllowed()
@ -384,6 +457,14 @@ bool DMenu::DimAllowed()
bool DMenu::TranslateKeyboardEvents()
{
IFVIRTUAL(DMenu, TranslateKeyboardEvents)
{
VMValue params[] = { (DObject*)this };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return true;
}
@ -433,6 +514,13 @@ void M_ActivateMenu(DMenu *menu)
GC::WriteBarrier(DMenu::CurrentMenu);
}
DEFINE_ACTION_FUNCTION(DMenu, ActivateMenu)
{
PARAM_SELF_PROLOGUE(DMenu);
M_ActivateMenu(self);
return 0;
}
//=============================================================================
//
//
@ -500,6 +588,11 @@ void M_SetMenu(FName menu, int param)
M_StartMessage (GStrings("SAVEDEAD"), 1);
return;
}
case NAME_VideoModeMenu:
M_InitVideoModes();
break;
}
// End of special checks
@ -533,10 +626,14 @@ void M_SetMenu(FName menu, int param)
else if ((*desc)->IsKindOf(RUNTIME_CLASS(DOptionMenuDescriptor)))
{
DOptionMenuDescriptor *ld = static_cast<DOptionMenuDescriptor*>(*desc);
const PClass *cls = ld->mClass == nullptr? RUNTIME_CLASS(DOptionMenu) : ld->mClass;
const PClass *cls = ld->mClass == nullptr? PClass::FindClass("OptionMenu") : ld->mClass;
DOptionMenu *newmenu = (DOptionMenu *)cls->CreateNew();
newmenu->Init(DMenu::CurrentMenu, ld);
DMenu *newmenu = (DMenu*)cls->CreateNew();
IFVIRTUALPTRNAME(newmenu, "OptionMenu", Init)
{
VMValue params[3] = { newmenu, DMenu::CurrentMenu, ld };
GlobalVMStack.Call(func, params, 3, nullptr, 0);
}
M_ActivateMenu(newmenu);
}
return;
@ -559,6 +656,14 @@ void M_SetMenu(FName menu, int param)
M_ClearMenus();
}
DEFINE_ACTION_FUNCTION(DMenu, SetMenu)
{
PARAM_PROLOGUE;
PARAM_NAME(menu);
PARAM_INT(mparam);
M_SetMenu(menu, mparam);
return 0;
}
//=============================================================================
//
//
@ -612,7 +717,7 @@ bool M_Responder (event_t *ev)
}
// pass everything else on to the current menu
return DMenu::CurrentMenu->Responder(ev);
return DMenu::CurrentMenu->CallResponder(ev);
}
else if (DMenu::CurrentMenu->TranslateKeyboardEvents())
{
@ -633,7 +738,7 @@ bool M_Responder (event_t *ev)
default:
if (!keyup)
{
return DMenu::CurrentMenu->Responder(ev);
return DMenu::CurrentMenu->CallResponder(ev);
}
break;
}
@ -720,7 +825,7 @@ bool M_Responder (event_t *ev)
return true;
}
}
return DMenu::CurrentMenu->Responder(ev) || !keyup;
return DMenu::CurrentMenu->CallResponder(ev) || !keyup;
}
else if (MenuEnabled)
{
@ -764,7 +869,7 @@ void M_Ticker (void)
DMenu::MenuTime++;
if (DMenu::CurrentMenu != nullptr && menuactive != MENU_Off)
{
DMenu::CurrentMenu->Ticker();
DMenu::CurrentMenu->CallTicker();
for (int i = 0; i < NUM_MKEYS; ++i)
{
@ -773,7 +878,7 @@ void M_Ticker (void)
if (MenuButtonTickers[i] > 0 && --MenuButtonTickers[i] <= 0)
{
MenuButtonTickers[i] = KEY_REPEAT_RATE;
DMenu::CurrentMenu->MenuEvent(i, MenuButtonOrigin[i]);
DMenu::CurrentMenu->CallMenuEvent(i, MenuButtonOrigin[i]);
}
}
}
@ -1071,10 +1176,23 @@ CCMD(reset2saved)
}
// This really should be in the script but we can't do scripted CCMDs yet.
CCMD(undocolorpic)
{
if (DMenu::CurrentMenu != NULL)
{
IFVIRTUALPTR(DMenu::CurrentMenu, DMenu, ResetColor)
{
VMValue params[] = { (DObject*)DMenu::CurrentMenu };
GlobalVMStack.Call(func, params, countof(params), nullptr, 0, nullptr);
}
}
}
//native void OptionMenuDescriptor.CalcIndent();
//native OptionMenuItem OptionMenuDescriptor.GetItem(Name iname);
//native void OptionMenuItem.drawLabel(int indent, int y, EColorRange color, bool grayed = false);
DEFINE_FIELD(DMenu, mParentMenu)
DEFINE_FIELD(DMenuDescriptor, mMenuName)
DEFINE_FIELD(DMenuDescriptor, mNetgameMessage)
@ -1085,6 +1203,23 @@ DEFINE_FIELD(DMenuItemBase, mYpos)
DEFINE_FIELD(DMenuItemBase, mAction)
DEFINE_FIELD(DMenuItemBase, mEnabled)
DEFINE_FIELD(DListMenuDescriptor, mItems)
DEFINE_FIELD(DListMenuDescriptor, mSelectedItem)
DEFINE_FIELD(DListMenuDescriptor, mSelectOfsX)
DEFINE_FIELD(DListMenuDescriptor, mSelectOfsY)
DEFINE_FIELD(DListMenuDescriptor, mSelector)
DEFINE_FIELD(DListMenuDescriptor, mDisplayTop)
DEFINE_FIELD(DListMenuDescriptor, mXpos)
DEFINE_FIELD(DListMenuDescriptor, mYpos)
DEFINE_FIELD(DListMenuDescriptor, mWLeft)
DEFINE_FIELD(DListMenuDescriptor, mWRight)
DEFINE_FIELD(DListMenuDescriptor, mLinespacing)
DEFINE_FIELD(DListMenuDescriptor, mAutoselect)
DEFINE_FIELD(DListMenuDescriptor, mFont)
DEFINE_FIELD(DListMenuDescriptor, mFontColor)
DEFINE_FIELD(DListMenuDescriptor, mFontColor2)
DEFINE_FIELD(DListMenuDescriptor, mCenter)
DEFINE_FIELD(DOptionMenuDescriptor, mItems)
DEFINE_FIELD(DOptionMenuDescriptor, mTitle)
DEFINE_FIELD(DOptionMenuDescriptor, mSelectedItem)
@ -1095,15 +1230,6 @@ DEFINE_FIELD(DOptionMenuDescriptor, mIndent)
DEFINE_FIELD(DOptionMenuDescriptor, mPosition)
DEFINE_FIELD(DOptionMenuDescriptor, mDontDim)
DEFINE_FIELD(DOptionMenuItem, mLabel)
DEFINE_FIELD(DOptionMenuItem, mCentered)
DEFINE_FIELD(DOptionMenu, CanScrollUp)
DEFINE_FIELD(DOptionMenu, CanScrollDown)
DEFINE_FIELD(DOptionMenu, VisBottom)
DEFINE_FIELD(DOptionMenu, mFocusControl)
DEFINE_FIELD(DOptionMenu, mDesc)
DEFINE_FIELD(FOptionMenuSettings, mTitleColor)
DEFINE_FIELD(FOptionMenuSettings, mFontColor)
DEFINE_FIELD(FOptionMenuSettings, mFontColorValue)
@ -1112,3 +1238,380 @@ DEFINE_FIELD(FOptionMenuSettings, mFontColorHeader)
DEFINE_FIELD(FOptionMenuSettings, mFontColorHighlight)
DEFINE_FIELD(FOptionMenuSettings, mFontColorSelection)
DEFINE_FIELD(FOptionMenuSettings, mLinespacing)
struct IJoystickConfig;
DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, bool v)
{
auto c = PClass::FindClass("OptionMenuItemStaticText");
auto p = c->CreateNew();
VMValue params[] = { p, FString(name), v };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuSliderVar(const char *name, int index, double min, double max, double step, int showval)
{
auto c = PClass::FindClass("OptionMenuItemSliderVar");
auto p = c->CreateNew();
VMValue params[] = { p, FString(name), index, min, max, step, showval };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuItemCommand(const char * label, FName cmd)
{
auto c = PClass::FindClass("OptionMenuItemCommand");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), cmd.GetIndex() };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuItemOption(const char * label, FName cmd, FName values, FBaseCVar *graycheck, bool center)
{
auto c = PClass::FindClass("OptionMenuItemOption");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), cmd.GetIndex(), values.GetIndex(), graycheck, center };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy)
{
auto c = PClass::FindClass("OptionMenuItemJoyConfigMenu");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), joy };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuItemJoyMap(const char *label, int axis, FName values, bool center)
{
auto c = PClass::FindClass("OptionMenuItemJoyMap");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), axis, values.GetIndex(), center };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuSliderJoySensitivity(const char * label, double min, double max, double step, int showval)
{
auto c = PClass::FindClass("OptionMenuSliderJoySensitivity");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), min, max, step, showval };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuSliderJoyScale(const char *label, int axis, double min, double max, double step, int showval)
{
auto c = PClass::FindClass("OptionMenuSliderJoyScale");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), min, max, step, showval };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuItemInverter(const char *label, int axis, int center)
{
auto c = PClass::FindClass("OptionMenuItemInverter");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), axis, center };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuSliderJoyDeadZone(const char *label, int axis, double min, double max, double step, int showval)
{
auto c = PClass::FindClass("OptionMenuSliderJoyDeadZone");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), min, max, step, showval };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center)
{
auto c = PClass::FindClass("OptionMenuItemSubmenu");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), cmd.GetIndex(), center };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings)
{
auto c = PClass::FindClass("OptionMenuItemControl");
auto p = c->CreateNew();
VMValue params[] = { p, FString(label), cmd.GetIndex(), bindings };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("Init", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID tex, FName command, int param)
{
auto c = PClass::FindClass("ListMenuItemPatchItem");
auto p = c->CreateNew();
VMValue params[] = { p, x, y, height, tex.GetIndex(), FString(char(hotkey)), command.GetIndex(), param };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("InitDirect", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
return (DMenuItemBase*)p;
}
DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param)
{
auto c = PClass::FindClass("ListMenuItemTextItem");
auto p = c->CreateNew();
VMValue params[] = { p, x, y, height, FString(char(hotkey)), text, font, int(color1.d), int(color2.d), command.GetIndex(), param };
auto f = dyn_cast<PFunction>(c->Symbols.FindSymbol("InitDirect", false));
GlobalVMStack.Call(f->Variants[0].Implementation, params, countof(params), nullptr, 0);
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)
{
VMValue params[] = { (DObject*)this };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
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)
{
IFVIRTUAL(DMenuItemBase, SetString)
{
VMValue params[] = { (DObject*)this, i, FString(s) };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return false;
}
bool DMenuItemBase::GetString(int i, char *s, int len)
{
IFVIRTUAL(DMenuItemBase, GetString)
{
VMValue params[] = { (DObject*)this, i };
int retval;
FString retstr;
VMReturn ret[2]; ret[0].IntAt(&retval); ret[1].StringAt(&retstr);
GlobalVMStack.Call(func, params, countof(params), ret, 2, nullptr);
strncpy(s, retstr, len);
return !!retval;
}
return false;
}
bool DMenuItemBase::SetValue(int i, int value)
{
IFVIRTUAL(DMenuItemBase, SetValue)
{
VMValue params[] = { (DObject*)this, i, value };
int retval;
VMReturn ret(&retval);
GlobalVMStack.Call(func, params, countof(params), &ret, 1, nullptr);
return !!retval;
}
return false;
}
bool DMenuItemBase::GetValue(int i, int *pvalue)
{
IFVIRTUAL(DMenuItemBase, GetValue)
{
VMValue params[] = { (DObject*)this, i };
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);
*pvalue = retval[1];
return !!retval[0];
}
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, 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);
}
}

View file

@ -22,6 +22,7 @@ class FFont;
enum EColorRange : int;
class FPlayerClass;
class FKeyBindings;
struct FBrokenLines;
enum EMenuKey
{
@ -66,7 +67,37 @@ struct FSaveGameNode
FSaveGameNode() { bNoDelete = false; }
};
struct SavegameManager
{
TArray<FSaveGameNode*> SaveGames;
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();
int InsertSaveNode(FSaveGameNode *node);
int RemoveSaveSlot(int index);
void ReadSaveStrings();
void NotifyNewSave(const char *file, const char *title, bool okForQuicksave);
void LoadSavegame(int Selected);
void DoSave(int Selected, const char *savegamestring);
void DeleteEntry(int Selected);
void ExtractSaveData(int index);
void UnloadSaveData();
void ClearSaveStuff();
bool DrawSavePic(int x, int y, int w, int h);
void SetFileInfo(int Selected);
};
extern SavegameManager savegameManager;
//=============================================================================
//
@ -87,7 +118,6 @@ public:
};
class DMenuItemBase;
class DOptionMenuItem;
class DListMenuDescriptor : public DMenuDescriptor
{
@ -145,7 +175,7 @@ class DOptionMenuDescriptor : public DMenuDescriptor
DECLARE_CLASS(DOptionMenuDescriptor, DMenuDescriptor)
public:
TArray<DOptionMenuItem *> mItems;
TArray<DMenuItemBase *> mItems;
FString mTitle;
int mSelectedItem;
int mDrawTop;
@ -156,7 +186,7 @@ public:
bool mDontDim;
void CalcIndent();
DOptionMenuItem *GetItem(FName name);
DMenuItemBase *GetItem(FName name);
void Reset()
{
// Reset the default settings (ignore all other values in the struct)
@ -239,12 +269,20 @@ public:
virtual void Ticker ();
virtual void Drawer ();
virtual bool DimAllowed ();
virtual bool TranslateKeyboardEvents();
bool TranslateKeyboardEvents();
virtual void Close();
virtual bool MouseEvent(int type, int x, int y);
virtual void SetFocus(DMenuItemBase *fc) {}
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);
void CallTicker();
void CallDrawer();
bool MouseEventBack(int type, int x, int y);
@ -267,256 +305,35 @@ class DMenuItemBase : public DObject
DECLARE_CLASS(DMenuItemBase, DObject)
public:
int mXpos, mYpos;
FName mAction;
FNameNoInit mAction;
bool mEnabled;
DMenuItemBase(int xpos = 0, int ypos = 0, FName action = NAME_None)
{
mXpos = xpos;
mYpos = ypos;
mAction = action;
mEnabled = true;
}
virtual bool CheckCoordinate(int x, int y);
virtual void Ticker();
virtual void Drawer(bool selected);
virtual bool Selectable();
virtual bool Activate();
virtual FName GetAction(int *pparam);
virtual bool SetString(int i, const char *s);
virtual bool GetString(int i, char *s, int len);
virtual bool SetValue(int i, int value);
virtual bool GetValue(int i, int *pvalue);
virtual void Enable(bool on);
virtual bool MenuEvent (int mkey, bool fromcontroller);
virtual bool MouseEvent(int type, int x, int y);
virtual bool CheckHotkey(int c);
virtual int GetWidth();
void DrawSelector(int xofs, int yofs, FTextureID tex);
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);
};
class DListMenuItemStaticPatch : public DMenuItemBase
{
DECLARE_CLASS(DListMenuItemStaticPatch, DMenuItemBase)
protected:
FTextureID mTexture;
bool mCentered;
DListMenuItemStaticPatch() {}
public:
DListMenuItemStaticPatch(int x, int y, FTextureID patch, bool centered);
void Drawer(bool selected);
};
class DListMenuItemStaticText : public DMenuItemBase
{
DECLARE_CLASS(DListMenuItemStaticText, DMenuItemBase)
protected:
FString mText;
FFont *mFont;
EColorRange mColor;
bool mCentered;
DListMenuItemStaticText() {}
public:
DListMenuItemStaticText(int x, int y, const char *text, FFont *font, EColorRange color, bool centered);
void Drawer(bool selected);
};
//=============================================================================
//
// the player sprite window
//
//=============================================================================
class DListMenuItemPlayerDisplay : public DMenuItemBase
{
DECLARE_CLASS(DListMenuItemPlayerDisplay, DMenuItemBase)
DListMenuDescriptor *mOwner;
FTexture *mBackdrop;
FRemapTable mRemap;
FPlayerClass *mPlayerClass;
FState *mPlayerState;
int mPlayerTics;
bool mNoportrait;
BYTE mRotation;
BYTE mMode; // 0: automatic (used by class selection), 1: manual (used by player setup)
BYTE mTranslate;
int mSkin;
int mRandomClass;
int mRandomTimer;
int mClassNum;
void SetPlayerClass(int classnum, bool force = false);
bool UpdatePlayerClass();
void UpdateRandomClass();
void UpdateTranslation();
DListMenuItemPlayerDisplay() {}
public:
enum
{
PDF_ROTATION = 0x10001,
PDF_SKIN = 0x10002,
PDF_CLASS = 0x10003,
PDF_MODE = 0x10004,
PDF_TRANSLATE = 0x10005,
};
DListMenuItemPlayerDisplay(DListMenuDescriptor *menu, int x, int y, PalEntry c1, PalEntry c2, bool np, FName action);
void OnDestroy() override;
virtual void Ticker();
virtual void Drawer(bool selected);
bool SetValue(int i, int value);
};
//=============================================================================
//
// selectable items
//
//=============================================================================
class DListMenuItemSelectable : public DMenuItemBase
{
DECLARE_CLASS(DListMenuItemSelectable, DMenuItemBase)
protected:
int mHotkey;
int mHeight;
int mParam;
DListMenuItemSelectable() {}
public:
DListMenuItemSelectable(int x, int y, int height, FName childmenu, int mParam = -1);
bool CheckCoordinate(int x, int y);
bool Selectable();
bool CheckHotkey(int c);
bool Activate();
bool MouseEvent(int type, int x, int y);
FName GetAction(int *pparam);
};
class DListMenuItemText : public DListMenuItemSelectable
{
DECLARE_CLASS(DListMenuItemText, DListMenuItemSelectable)
const char *mText;
FFont *mFont;
EColorRange mColor;
EColorRange mColorSelected;
DListMenuItemText() {}
public:
DListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, EColorRange color, EColorRange color2, FName child, int param = 0);
void OnDestroy() override;
void Drawer(bool selected);
int GetWidth();
};
class DListMenuItemPatch : public DListMenuItemSelectable
{
DECLARE_CLASS(DListMenuItemPatch, DListMenuItemSelectable)
FTextureID mTexture;
DListMenuItemPatch() {}
public:
DListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID patch, FName child, int param = 0);
void Drawer(bool selected);
int GetWidth();
};
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class DPlayerNameBox : public DListMenuItemSelectable
{
DECLARE_CLASS(DPlayerNameBox, DListMenuItemSelectable)
FString mText;
FFont *mFont;
EColorRange mFontColor;
int mFrameSize;
char mPlayerName[MAXPLAYERNAME+1];
char mEditName[MAXPLAYERNAME+2];
bool mEntering;
void DrawBorder (int x, int y, int len);
DPlayerNameBox() {}
public:
DPlayerNameBox(int x, int y, int height, int frameofs, const char *text, FFont *font, EColorRange color, FName action);
bool SetString(int i, const char *s);
bool GetString(int i, char *s, int len);
void Drawer(bool selected);
bool MenuEvent (int mkey, bool fromcontroller);
};
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class DValueTextItem : public DListMenuItemSelectable
{
DECLARE_CLASS(DValueTextItem, DListMenuItemSelectable)
TArray<FString> mSelections;
FString mText;
int mSelection;
FFont *mFont;
EColorRange mFontColor;
EColorRange mFontColor2;
DValueTextItem() {}
public:
DValueTextItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, EColorRange valuecolor, FName action, FName values);
bool SetString(int i, const char *s);
bool SetValue(int i, int value);
bool GetValue(int i, int *pvalue);
bool MenuEvent (int mkey, bool fromcontroller);
void Drawer(bool selected);
};
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class DSliderItem : public DListMenuItemSelectable
{
DECLARE_CLASS(DSliderItem, DListMenuItemSelectable)
FString mText;
FFont *mFont;
EColorRange mFontColor;
int mMinrange, mMaxrange;
int mStep;
int mSelection;
void DrawSlider (int x, int y);
DSliderItem() {}
public:
DSliderItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, FName action, int min, int max, int step);
bool SetValue(int i, int value);
bool GetValue(int i, int *pvalue);
bool MenuEvent (int mkey, bool fromcontroller);
void Drawer(bool selected);
bool MouseEvent(int type, int x, int y);
};
//=============================================================================
//
// list menu class runs a menu described by a DListMenuDescriptor
@ -556,34 +373,6 @@ public:
};
//=============================================================================
//
// base class for menu items
//
//=============================================================================
class DOptionMenuItem : public DMenuItemBase
{
DECLARE_ABSTRACT_CLASS(DOptionMenuItem, DMenuItemBase)
public:
FString mLabel;
bool mCentered;
void drawLabel(int indent, int y, EColorRange color, bool grayed = false);
DOptionMenuItem(const char *text = nullptr, FName action = NAME_None, bool center = false)
: DMenuItemBase(0, 0, action)
{
mLabel = text;
mCentered = center;
}
virtual int Draw(DOptionMenuDescriptor *desc, int y, int indent, bool selected);
virtual bool Selectable();
virtual int GetIndent();
virtual bool MouseEvent(int type, int x, int y);
};
//=============================================================================
//
//
@ -606,50 +395,6 @@ typedef TMap< FName, FOptionValues* > FOptionMap;
extern FOptionMap OptionValues;
//=============================================================================
//
// Option menu class runs a menu described by a DOptionMenuDescriptor
//
//=============================================================================
class DOptionMenu : public DMenu
{
DECLARE_CLASS(DOptionMenu, DMenu)
HAS_OBJECT_POINTERS;
public: // needs to be public for script access
bool CanScrollUp;
bool CanScrollDown;
int VisBottom;
DOptionMenuItem *mFocusControl;
DOptionMenuDescriptor *mDesc;
//public:
DOptionMenuItem *GetItem(FName name);
DOptionMenu(DMenu *parent = NULL, DOptionMenuDescriptor *desc = NULL);
virtual void Init(DMenu *parent = NULL, DOptionMenuDescriptor *desc = NULL);
int FirstSelectable();
bool Responder (event_t *ev);
bool MenuEvent (int mkey, bool fromcontroller);
bool MouseEvent(int type, int x, int y);
void Ticker ();
void Drawer ();
const DOptionMenuDescriptor *GetDescriptor() const { return mDesc; }
void SetFocus(DOptionMenuItem *fc)
{
mFocusControl = fc;
}
bool CheckFocus(DOptionMenuItem *fc)
{
return mFocusControl == fc;
}
void ReleaseFocus()
{
mFocusControl = NULL;
}
};
//=============================================================================
//
// Input some text
@ -660,7 +405,8 @@ class DTextEnterMenu : public DMenu
{
DECLARE_ABSTRACT_CLASS(DTextEnterMenu, DMenu)
char *mEnterString;
public:
FString mEnterString;
unsigned int mEnterSize;
unsigned int mEnterPos;
int mSizeMode; // 1: size is length in chars. 2: also check string width
@ -672,17 +418,15 @@ class DTextEnterMenu : public DMenu
// [TP]
bool AllowColors;
public:
// [TP] Added allowcolors
DTextEnterMenu(DMenu *parent, char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors = false);
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 TranslateKeyboardEvents();
bool MouseEvent(int type, int x, int y);
FString GetText();
};
@ -702,7 +446,6 @@ void M_StartupSkillMenu(FGameStartup *gs);
int M_GetDefaultSkill();
void M_StartControlPanel (bool makeSound);
void M_SetMenu(FName menu, int param = -1);
void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave);
void M_StartMessage(const char *message, int messagemode, FName action = NAME_None);
DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar);
void M_RefreshModesList ();
@ -710,4 +453,20 @@ void M_InitVideoModesMenu ();
void M_MarkMenus();
struct IJoystickConfig;
DMenuItemBase * CreateOptionMenuItemStaticText(const char *name, bool v);
DMenuItemBase * CreateOptionMenuSliderVar(const char *name, int index, double min, double max, double step, int showval);
DMenuItemBase * CreateOptionMenuItemCommand(const char * label, FName cmd);
DMenuItemBase * CreateOptionMenuItemOption(const char * label, FName cmd, FName values, FBaseCVar *graycheck, bool center);
DMenuItemBase * CreateOptionMenuItemSubmenu(const char *label, FName cmd, int center);
DMenuItemBase * CreateOptionMenuItemControl(const char *label, FName cmd, FKeyBindings *bindings);
DMenuItemBase * CreateOptionMenuItemJoyConfigMenu(const char *label, IJoystickConfig *joy);
DMenuItemBase * CreateOptionMenuItemJoyMap(const char *label, int axis, FName values, bool center);
DMenuItemBase * CreateOptionMenuSliderJoySensitivity(const char * label, double min, double max, double step, int showval);
DMenuItemBase * CreateOptionMenuSliderJoyScale(const char *label, int axis, double min, double max, double step, int showval);
DMenuItemBase * CreateOptionMenuItemInverter(const char *label, int axis, int center);
DMenuItemBase * CreateOptionMenuSliderJoyDeadZone(const char *label, int axis, double min, double max, double step, int showval);
DMenuItemBase * CreateListMenuItemPatch(int x, int y, int height, int hotkey, FTextureID tex, FName command, int param);
DMenuItemBase * CreateListMenuItemText(int x, int y, int height, int hotkey, const char *text, FFont *font, PalEntry color1, PalEntry color2, FName command, int param);
#endif

View file

@ -52,7 +52,7 @@
#include "i_sound.h"
#include "cmdlib.h"
#include "optionmenuitems.h"
void ClearSaveGames();
@ -65,6 +65,71 @@ bool mustPrintErrors;
void I_BuildALDeviceList(FOptionValues *opt);
DEFINE_ACTION_FUNCTION(FOptionValues, GetCount)
{
PARAM_PROLOGUE;
PARAM_NAME(grp);
int cnt = 0;
FOptionValues **pGrp = OptionValues.CheckKey(grp);
if (pGrp != nullptr)
{
cnt = (*pGrp)->mValues.Size();
}
ACTION_RETURN_INT(cnt);
}
DEFINE_ACTION_FUNCTION(FOptionValues, GetValue)
{
PARAM_PROLOGUE;
PARAM_NAME(grp);
PARAM_UINT(index);
double val = 0;
FOptionValues **pGrp = OptionValues.CheckKey(grp);
if (pGrp != nullptr)
{
if (index < (*pGrp)->mValues.Size())
{
val = (*pGrp)->mValues[index].Value;
}
}
ACTION_RETURN_FLOAT(val);
}
DEFINE_ACTION_FUNCTION(FOptionValues, GetTextValue)
{
PARAM_PROLOGUE;
PARAM_NAME(grp);
PARAM_UINT(index);
FString val;
FOptionValues **pGrp = OptionValues.CheckKey(grp);
if (pGrp != nullptr)
{
if (index < (*pGrp)->mValues.Size())
{
val = (*pGrp)->mValues[index].TextValue;
}
}
ACTION_RETURN_STRING(val);
}
DEFINE_ACTION_FUNCTION(FOptionValues, GetText)
{
PARAM_PROLOGUE;
PARAM_NAME(grp);
PARAM_UINT(index);
FString val;
FOptionValues **pGrp = OptionValues.CheckKey(grp);
if (pGrp != nullptr)
{
if (index < (*pGrp)->mValues.Size())
{
val = (*pGrp)->mValues[index].Text;
}
}
ACTION_RETURN_STRING(val);
}
static void DeinitMenus()
{
{
@ -81,7 +146,7 @@ static void DeinitMenus()
MenuDescriptors.Clear();
OptionValues.Clear();
DMenu::CurrentMenu = nullptr;
ClearSaveGames();
savegameManager.ClearSaveGames();
}
static FTextureID GetMenuTexture(const char* const name)
@ -269,87 +334,6 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc)
sc.MustGetNumber();
desc->mWRight = sc.Number;
}
else if (sc.Compare("StaticPatch") || sc.Compare("StaticPatchCentered"))
{
bool centered = sc.Compare("StaticPatchCentered");
sc.MustGetNumber();
int x = sc.Number;
sc.MustGetStringName(",");
sc.MustGetNumber();
int y = sc.Number;
sc.MustGetStringName(",");
sc.MustGetString();
FTextureID tex = GetMenuTexture(sc.String);
DMenuItemBase *it = new DListMenuItemStaticPatch(x, y, tex, centered);
desc->mItems.Push(it);
}
else if (sc.Compare("StaticText") || sc.Compare("StaticTextCentered"))
{
bool centered = sc.Compare("StaticTextCentered");
sc.MustGetNumber();
int x = sc.Number;
sc.MustGetStringName(",");
sc.MustGetNumber();
int y = sc.Number;
sc.MustGetStringName(",");
sc.MustGetString();
FString label = sc.String;
EColorRange cr = desc->mFontColor;
if (sc.CheckString(","))
{
sc.MustGetString();
cr = V_FindFontColor(sc.String);
if (cr == CR_UNTRANSLATED && !sc.Compare("untranslated")) cr = desc->mFontColor;
}
DMenuItemBase *it = new DListMenuItemStaticText(x, y, label, desc->mFont, cr, centered);
desc->mItems.Push(it);
}
else if (sc.Compare("PatchItem"))
{
sc.MustGetString();
FTextureID tex = GetMenuTexture(sc.String);
sc.MustGetStringName(",");
sc.MustGetString();
int hotkey = sc.String[0];
sc.MustGetStringName(",");
sc.MustGetString();
FName action = sc.String;
int param = 0;
if (sc.CheckString(","))
{
sc.MustGetNumber();
param = sc.Number;
}
DMenuItemBase *it = new DListMenuItemPatch(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, tex, action, param);
desc->mItems.Push(it);
desc->mYpos += desc->mLinespacing;
if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
}
else if (sc.Compare("TextItem"))
{
sc.MustGetString();
FString text = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
int hotkey = sc.String[0];
sc.MustGetStringName(",");
sc.MustGetString();
FName action = sc.String;
int param = 0;
if (sc.CheckString(","))
{
sc.MustGetNumber();
param = sc.Number;
}
DMenuItemBase *it = new DListMenuItemText(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, text, desc->mFont, desc->mFontColor, desc->mFontColor2, action, param);
desc->mItems.Push(it);
desc->mYpos += desc->mLinespacing;
if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
}
else if (sc.Compare("Font"))
{
sc.MustGetString();
@ -376,90 +360,134 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc)
sc.MustGetString();
desc->mNetgameMessage = sc.String;
}
else if (sc.Compare("PlayerDisplay"))
{
bool noportrait = false;
FName action = NAME_None;
sc.MustGetNumber();
int x = sc.Number;
sc.MustGetStringName(",");
sc.MustGetNumber();
int y = sc.Number;
sc.MustGetStringName(",");
sc.MustGetString();
PalEntry c1 = V_GetColor(nullptr, sc);
sc.MustGetStringName(",");
sc.MustGetString();
PalEntry c2 = V_GetColor(nullptr, sc);
if (sc.CheckString(","))
{
sc.MustGetNumber();
noportrait = !!sc.Number;
if (sc.CheckString(","))
{
sc.MustGetString();
action = sc.String;
}
}
DListMenuItemPlayerDisplay *it = new DListMenuItemPlayerDisplay(desc, x, y, c1, c2, noportrait, action);
desc->mItems.Push(it);
}
else if (sc.Compare("PlayerNameBox"))
{
sc.MustGetString();
FString text = sc.String;
sc.MustGetStringName(",");
sc.MustGetNumber();
int ofs = sc.Number;
sc.MustGetStringName(",");
sc.MustGetString();
DMenuItemBase *it = new DPlayerNameBox(desc->mXpos, desc->mYpos, desc->mLinespacing, ofs, text, desc->mFont, desc->mFontColor, sc.String);
desc->mItems.Push(it);
desc->mYpos += desc->mLinespacing;
if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
}
else if (sc.Compare("ValueText"))
{
sc.MustGetString();
FString text = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FName action = sc.String;
FName values;
if (sc.CheckString(","))
{
sc.MustGetString();
values = sc.String;
}
DMenuItemBase *it = new DValueTextItem(desc->mXpos, desc->mYpos, desc->mLinespacing, text, desc->mFont, desc->mFontColor, desc->mFontColor2, action, values);
desc->mItems.Push(it);
desc->mYpos += desc->mLinespacing;
if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
}
else if (sc.Compare("Slider"))
{
sc.MustGetString();
FString text = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FString action = sc.String;
sc.MustGetStringName(",");
sc.MustGetNumber();
int min = sc.Number;
sc.MustGetStringName(",");
sc.MustGetNumber();
int max = sc.Number;
sc.MustGetStringName(",");
sc.MustGetNumber();
int step = sc.Number;
DMenuItemBase *it = new DSliderItem(desc->mXpos, desc->mYpos, desc->mLinespacing, text, desc->mFont, desc->mFontColor, action, min, max, step);
desc->mItems.Push(it);
desc->mYpos += desc->mLinespacing;
if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
}
else
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
bool success = false;
FStringf buildname("ListMenuItem%s", sc.String);
PClass *cls = PClass::FindClass(buildname);
if (cls != nullptr && cls->IsDescendantOf("ListMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->Symbols.FindSymbol("Init", false));
if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method.
{
auto &args = func->Variants[0].Proto->ArgumentTypes;
TArray<VMValue> params;
int start = 1;
params.Push(0);
if (args.Size() > 1 && args[1] == NewPointer(PClass::FindClass("ListMenuDescriptor")))
{
params.Push(desc);
start = 2;
}
auto TypeCVar = NewPointer(NewNativeStruct("CVar", nullptr));
for (unsigned i = start; i < args.Size(); i++)
{
sc.MustGetString();
if (args[i] == TypeString)
{
params.Push(FString(sc.String));
}
else if (args[i] == TypeName)
{
params.Push(FName(sc.String).GetIndex());
}
else if (args[i] == TypeColor)
{
params.Push(V_GetColor(nullptr, sc));
}
else if (args[i] == TypeFont)
{
auto f = FFont::FindFont(sc.String);
if (f == nullptr)
{
sc.ScriptError("Unknown font %s", sc.String);
}
params.Push(f);
}
else if (args[i] == TypeTextureID)
{
auto f = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch);
if (!f.isValid())
{
sc.ScriptError("Unknown texture %s", sc.String);
}
params.Push(f.GetIndex());
}
else if (args[i]->IsKindOf(RUNTIME_CLASS(PInt)))
{
char *endp;
int v = (int)strtoll(sc.String, &endp, 0);
if (*endp != 0)
{
// special check for font color ranges.
v = V_FindFontColor(sc.String);
if (v == CR_UNTRANSLATED && !sc.Compare("untranslated"))
{
// todo: check other data types that may get used.
sc.ScriptError("Integer expected, got %s", sc.String);
}
}
if (args[i] == TypeBool) v = !!v;
params.Push(v);
}
else if (args[i]->IsKindOf(RUNTIME_CLASS(PFloat)))
{
char *endp;
double v = strtod(sc.String, &endp);
if (*endp != 0)
{
sc.ScriptError("Float expected, got %s", sc.String);
}
params.Push(v);
}
else if (args[i] == TypeCVar)
{
auto cv = FindCVar(sc.String, nullptr);
if (cv == nullptr && *sc.String)
{
sc.ScriptError("Unknown CVar %s", sc.String);
}
params.Push(cv);
}
else
{
sc.ScriptError("Invalid parameter type %s for menu item", args[i]->DescriptiveName());
}
if (sc.CheckString(","))
{
if (i == args.Size() - 1)
{
sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars());
}
}
else
{
if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional))
{
sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars());
}
break;
}
}
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
params[0] = item;
GlobalVMStack.Call(func->Variants[0].Implementation, &params[0], params.Size(), nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
if (cls->IsDescendantOf("ListMenuItemSelectable"))
{
desc->mYpos += desc->mLinespacing;
if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size() - 1;
}
success = true;
}
}
if (!success)
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
}
}
}
for (auto &p : desc->mItems)
@ -642,21 +670,6 @@ static void ParseOptionSettings(FScanner &sc)
//
//=============================================================================
static EColorRange ParseOptionColor(FScanner &sc, DOptionMenuDescriptor *desc)
{
EColorRange cr = OptionSettings.mFontColor;
if (sc.CheckString(","))
{
sc.MustGetString();
cr = V_FindFontColor(sc.String);
if (cr == CR_UNTRANSLATED && !sc.Compare("untranslated") && isdigit(sc.String[0]))
{
if (strtoll(sc.String, nullptr, 0)) cr = OptionSettings.mFontColorHeader;
}
}
return cr;
}
static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc)
{
sc.MustGetStringName("{");
@ -687,7 +700,7 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc)
{
sc.MustGetString();
const PClass *cls = PClass::FindClass(sc.String);
if (cls == nullptr || !cls->IsDescendantOf(RUNTIME_CLASS(DOptionMenu)))
if (cls == nullptr || !cls->IsDescendantOf("OptionMenu"))
{
sc.ScriptError("Unknown menu class '%s'", sc.String);
}
@ -718,198 +731,108 @@ static void ParseOptionMenuBody(FScanner &sc, DOptionMenuDescriptor *desc)
sc.MustGetNumber();
desc->mIndent = sc.Number;
}
else if (sc.Compare("Submenu"))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
DOptionMenuItem *it = new DOptionMenuItemSubmenu(label, sc.String);
desc->mItems.Push(it);
}
else if (sc.Compare("Option"))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FString cvar = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FString values = sc.String;
FString check;
int center = 0;
if (sc.CheckString(","))
{
sc.MustGetString();
if (*sc.String != 0) check = sc.String;
if (sc.CheckString(","))
{
sc.MustGetNumber();
center = sc.Number;
}
}
DOptionMenuItem *it = new DOptionMenuItemOption(label, cvar, values, check, center);
desc->mItems.Push(it);
}
else if (sc.Compare("Command"))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
DOptionMenuItem *it = new DOptionMenuItemCommand(label, sc.String);
desc->mItems.Push(it);
}
else if (sc.Compare("SafeCommand"))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FString command = sc.String;
FString prompt;
// Check for optional custom prompt
if (sc.CheckString(","))
{
sc.MustGetString();
prompt = sc.String;
}
DOptionMenuItem *it = new DOptionMenuItemSafeCommand(label, command, prompt);
desc->mItems.Push(it);
}
else if (sc.Compare("Control") || sc.Compare("MapControl"))
{
bool map = sc.Compare("MapControl");
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
DOptionMenuItem *it = new DOptionMenuItemControl(label, sc.String, map? &AutomapBindings : &Bindings);
desc->mItems.Push(it);
}
else if (sc.Compare("ColorPicker"))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
DOptionMenuItem *it = new DOptionMenuItemColorPicker(label, sc.String);
desc->mItems.Push(it);
}
else if (sc.Compare("StaticText"))
{
sc.MustGetString();
FString label = sc.String;
EColorRange cr = ParseOptionColor(sc, desc);
DOptionMenuItem *it = new DOptionMenuItemStaticText(label, cr);
desc->mItems.Push(it);
}
else if (sc.Compare("StaticTextSwitchable"))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FString label2 = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FName action = sc.String;
EColorRange cr = ParseOptionColor(sc, desc);
DOptionMenuItem *it = new DOptionMenuItemStaticTextSwitchable(label, label2, action, cr);
desc->mItems.Push(it);
}
else if (sc.Compare("Slider"))
{
sc.MustGetString();
FString text = sc.String;
sc.MustGetStringName(",");
sc.MustGetString();
FString action = sc.String;
sc.MustGetStringName(",");
sc.MustGetFloat();
double min = sc.Float;
sc.MustGetStringName(",");
sc.MustGetFloat();
double max = sc.Float;
sc.MustGetStringName(",");
sc.MustGetFloat();
double step = sc.Float;
int showvalue = 1;
if (sc.CheckString(","))
{
sc.MustGetNumber();
showvalue = sc.Number;
}
DOptionMenuItem *it = new DOptionMenuSliderCVar(text, action, min, max, step, showvalue);
desc->mItems.Push(it);
}
else if (sc.Compare("screenresolution"))
{
sc.MustGetString();
DOptionMenuItem *it = new DOptionMenuScreenResolutionLine(sc.String);
desc->mItems.Push(it);
}
// [TP] -- Text input widget
else if ( sc.Compare( "TextField" ))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName( "," );
sc.MustGetString();
FString cvar = sc.String;
FString check;
if ( sc.CheckString( "," ))
{
sc.MustGetString();
check = sc.String;
}
DOptionMenuItem* it = new DOptionMenuTextField( label, cvar, check );
desc->mItems.Push( it );
}
// [TP] -- Number input widget
else if ( sc.Compare( "NumberField" ))
{
sc.MustGetString();
FString label = sc.String;
sc.MustGetStringName( "," );
sc.MustGetString();
FString cvar = sc.String;
float minimum = 0.0f;
float maximum = 100.0f;
float step = 1.0f;
FString check;
if ( sc.CheckString( "," ))
{
sc.MustGetFloat();
minimum = (float) sc.Float;
sc.MustGetStringName( "," );
sc.MustGetFloat();
maximum = (float) sc.Float;
if ( sc.CheckString( "," ))
{
sc.MustGetFloat();
step = (float) sc.Float;
if ( sc.CheckString( "," ))
{
sc.MustGetString();
check = sc.String;
}
}
}
DOptionMenuItem* it = new DOptionMenuNumberField( label, cvar,
minimum, maximum, step, check );
desc->mItems.Push( it );
}
else
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
bool success = false;
FStringf buildname("OptionMenuItem%s", sc.String);
// Handle one special case: MapControl maps to Control with one parameter different
PClass *cls = PClass::FindClass(buildname);
if (cls != nullptr && cls->IsDescendantOf("OptionMenuItem"))
{
auto func = dyn_cast<PFunction>(cls->Symbols.FindSymbol("Init", false));
if (func != nullptr && !(func->Variants[0].Flags & (VARF_Protected | VARF_Private))) // skip internal classes which have a protexted init method.
{
auto &args = func->Variants[0].Proto->ArgumentTypes;
TArray<VMValue> params;
params.Push(0);
auto TypeCVar = NewPointer(NewNativeStruct("CVar", nullptr));
for (unsigned i = 1; i < args.Size(); i++)
{
sc.MustGetString();
if (args[i] == TypeString)
{
params.Push(FString(sc.String));
}
else if (args[i] == TypeName)
{
params.Push(FName(sc.String).GetIndex());
}
else if (args[i] == TypeColor)
{
params.Push(V_GetColor(nullptr, sc));
}
else if (args[i]->IsKindOf(RUNTIME_CLASS(PInt)))
{
char *endp;
int v = (int)strtoll(sc.String, &endp, 0);
if (*endp != 0)
{
// special check for font color ranges.
v = V_FindFontColor(sc.String);
if (v == CR_UNTRANSLATED && !sc.Compare("untranslated"))
{
// todo: check other data types that may get used.
sc.ScriptError("Integer expected, got %s", sc.String);
}
// Color ranges need to be marked for option menu items to support an older feature where a boolean number could be passed instead.
v |= 0x12340000;
}
if (args[i] == TypeBool) v = !!v;
params.Push(v);
}
else if (args[i]->IsKindOf(RUNTIME_CLASS(PFloat)))
{
char *endp;
double v = strtod(sc.String, &endp);
if (*endp != 0)
{
sc.ScriptError("Float expected, got %s", sc.String);
}
params.Push(v);
}
else if (args[i] == TypeCVar)
{
auto cv = FindCVar(sc.String, nullptr);
if (cv == nullptr && *sc.String)
{
sc.ScriptError("Unknown CVar %s", sc.String);
}
params.Push(cv);
}
else
{
sc.ScriptError("Invalid parameter type %s for menu item", args[i]->DescriptiveName());
}
if (sc.CheckString(","))
{
if (i == args.Size() - 1)
{
sc.ScriptError("Too many parameters for %s", cls->TypeName.GetChars());
}
}
else
{
if (i < args.Size() - 1 && !(func->Variants[0].ArgFlags[i + 1] & VARF_Optional))
{
sc.ScriptError("Insufficient parameters for %s", cls->TypeName.GetChars());
}
break;
}
}
DMenuItemBase *item = (DMenuItemBase*)cls->CreateNew();
params[0] = item;
GlobalVMStack.Call(func->Variants[0].Implementation, &params[0], params.Size(), nullptr, 0);
desc->mItems.Push((DMenuItemBase*)item);
success = true;
}
}
if (!success)
{
sc.ScriptError("Unknown keyword '%s'", sc.String);
}
}
}
for (auto &p : desc->mItems)
@ -1077,12 +1000,11 @@ static void BuildEpisodeMenu()
if (AllEpisodes[i].mPicName.IsNotEmpty())
{
FTextureID tex = GetMenuTexture(AllEpisodes[i].mPicName);
it = new DListMenuItemPatch(ld->mXpos, posy, ld->mLinespacing, AllEpisodes[i].mShortcut,
tex, NAME_Skillmenu, i);
it = CreateListMenuItemPatch(ld->mXpos, posy, ld->mLinespacing, AllEpisodes[i].mShortcut, tex, NAME_Skillmenu, i);
}
else
{
it = new DListMenuItemText(ld->mXpos, posy, ld->mLinespacing, AllEpisodes[i].mShortcut,
it = CreateListMenuItemText(ld->mXpos, posy, ld->mLinespacing, AllEpisodes[i].mShortcut,
AllEpisodes[i].mEpisodeName, ld->mFont, ld->mFontColor, ld->mFontColor2, NAME_Skillmenu, i);
}
ld->mItems.Push(it);
@ -1118,7 +1040,7 @@ static void BuildEpisodeMenu()
GC::WriteBarrier(od);
for(unsigned i = 0; i < AllEpisodes.Size(); i++)
{
DOptionMenuItemSubmenu *it = new DOptionMenuItemSubmenu(AllEpisodes[i].mEpisodeName, "Skillmenu", i);
auto it = CreateOptionMenuItemSubmenu(AllEpisodes[i].mEpisodeName, "Skillmenu", i);
od->mItems.Push(it);
GC::WriteBarrier(od, it);
}
@ -1175,7 +1097,7 @@ static void BuildPlayerclassMenu()
if (numclassitems <= 1)
{
// create a dummy item that auto-chooses the default class.
DListMenuItemText *it = new DListMenuItemText(0, 0, 0, 'p', "player",
auto it = CreateListMenuItemText(0, 0, 0, 'p', "player",
ld->mFont,ld->mFontColor, ld->mFontColor2, NAME_Episodemenu, -1000);
ld->mAutoselect = ld->mItems.Push(it);
success = true;
@ -1201,7 +1123,7 @@ static void BuildPlayerclassMenu()
const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type);
if (pname != nullptr)
{
DListMenuItemText *it = new DListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname,
auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname,
pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, i);
ld->mItems.Push(it);
ld->mYpos += ld->mLinespacing;
@ -1211,7 +1133,7 @@ static void BuildPlayerclassMenu()
}
if (n > 1 && !gameinfo.norandomplayerclass)
{
DListMenuItemText *it = new DListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, 'r',
auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, 'r',
"$MNU_RANDOM", ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, -1);
ld->mItems.Push(it);
}
@ -1220,7 +1142,7 @@ static void BuildPlayerclassMenu()
const char *pname = GetPrintableDisplayName(PlayerClasses[0].Type);
if (pname != nullptr)
{
DListMenuItemText *it = new DListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname,
auto it = CreateListMenuItemText(ld->mXpos, ld->mYpos, ld->mLinespacing, *pname,
pname, ld->mFont,ld->mFontColor,ld->mFontColor2, NAME_Episodemenu, 0);
ld->mItems.Push(it);
}
@ -1257,13 +1179,13 @@ static void BuildPlayerclassMenu()
const char *pname = GetPrintableDisplayName(PlayerClasses[i].Type);
if (pname != nullptr)
{
DOptionMenuItemSubmenu *it = new DOptionMenuItemSubmenu(pname, "Episodemenu", i);
auto it = CreateOptionMenuItemSubmenu(pname, "Episodemenu", i);
od->mItems.Push(it);
GC::WriteBarrier(od, it);
}
}
}
DOptionMenuItemSubmenu *it = new DOptionMenuItemSubmenu("Random", "Episodemenu", -1);
auto it = CreateOptionMenuItemSubmenu("Random", "Episodemenu", -1);
od->mItems.Push(it);
GC::WriteBarrier(od, it);
}
@ -1344,14 +1266,14 @@ static void InitKeySections()
for (unsigned i = 0; i < KeySections.Size(); i++)
{
FKeySection *sect = &KeySections[i];
DOptionMenuItem *item = new DOptionMenuItemStaticText(" ", false);
DMenuItemBase *item = CreateOptionMenuItemStaticText(" ", false);
menu->mItems.Push(item);
item = new DOptionMenuItemStaticText(sect->mTitle, true);
item = CreateOptionMenuItemStaticText(sect->mTitle, true);
menu->mItems.Push(item);
for (unsigned j = 0; j < sect->mActions.Size(); j++)
{
FKeyAction *act = &sect->mActions[j];
item = new DOptionMenuItemControl(act->mTitle, act->mAction, &Bindings);
item = CreateOptionMenuItemControl(act->mTitle, act->mAction, &Bindings);
menu->mItems.Push(item);
}
}
@ -1481,13 +1403,13 @@ void M_StartupSkillMenu(FGameStartup *gs)
if (skill.PicName.Len() != 0 && pItemText == nullptr)
{
FTextureID tex = GetMenuTexture(skill.PicName);
li = new DListMenuItemPatch(ld->mXpos, y, ld->mLinespacing, skill.Shortcut, tex, action, i);
li = CreateListMenuItemPatch(ld->mXpos, y, ld->mLinespacing, skill.Shortcut, tex, action, i);
}
else
{
EColorRange color = (EColorRange)skill.GetTextColor();
if (color == CR_UNTRANSLATED) color = ld->mFontColor;
li = new DListMenuItemText(x, y, ld->mLinespacing, skill.Shortcut,
li = CreateListMenuItemText(x, y, ld->mLinespacing, skill.Shortcut,
pItemText? *pItemText : skill.MenuName, ld->mFont, color,ld->mFontColor2, action, i);
}
ld->mItems.Push(li);
@ -1532,7 +1454,7 @@ fail:
for(unsigned int i = 0; i < AllSkills.Size(); i++)
{
FSkillInfo &skill = AllSkills[i];
DOptionMenuItem *li;
DMenuItemBase *li;
// Using a different name for skills that must be confirmed makes handling this easier.
const char *action = (skill.MustConfirm && !AllEpisodes[gs->Episode].mNoSkill) ?
"StartgameConfirm" : "Startgame";
@ -1542,7 +1464,7 @@ fail:
{
pItemText = skill.MenuNamesForPlayerClass.CheckKey(gs->PlayerClass);
}
li = new DOptionMenuItemSubmenu(pItemText? *pItemText : skill.MenuName, action, i);
li = CreateOptionMenuItemSubmenu(pItemText? *pItemText : skill.MenuName, action, i);
od->mItems.Push(li);
GC::WriteBarrier(od, li);
if (!done)

View file

@ -61,6 +61,8 @@ static const char InputGridChars[INPUTGRID_WIDTH * INPUTGRID_HEIGHT] =
CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
DEFINE_FIELD(DTextEnterMenu, mInputGridOkay)
//=============================================================================
//
//
@ -68,15 +70,14 @@ CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//=============================================================================
// [TP] Added allowcolors
DTextEnterMenu::DTextEnterMenu(DMenu *parent, char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors)
DTextEnterMenu::DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors)
: DMenu(parent)
{
mEnterString = textbuffer;
mEnterSize = maxlen;
mEnterPos = (unsigned)strlen(textbuffer);
mEnterSize = maxlen < 0 ? UINT_MAX : unsigned(maxlen);
mSizeMode = sizemode;
mInputGridOkay = showgrid || m_showinputgrid;
if (mEnterPos > 0)
if (mEnterString.IsNotEmpty())
{
InputGridX = INPUTGRID_WIDTH - 1;
InputGridY = INPUTGRID_HEIGHT - 1;
@ -96,11 +97,18 @@ DTextEnterMenu::DTextEnterMenu(DMenu *parent, char *textbuffer, int maxlen, int
//
//=============================================================================
bool DTextEnterMenu::TranslateKeyboardEvents()
FString DTextEnterMenu::GetText()
{
return mInputGridOkay;
return mEnterString;
}
//=============================================================================
//
//
//
//=============================================================================
//=============================================================================
//
//
@ -115,21 +123,19 @@ bool DTextEnterMenu::Responder(event_t *ev)
if (ev->subtype == EV_GUI_Char)
{
mInputGridOkay = false;
if (mEnterPos < mEnterSize &&
if (mEnterString.Len() < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString[mEnterPos] = (char)ev->data1;
mEnterString[++mEnterPos] = 0;
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 (mEnterPos > 0)
if (mEnterString.IsNotEmpty())
{
mEnterPos--;
mEnterString[mEnterPos] = 0;
mEnterString.Truncate(mEnterString.Len() - 1);
}
}
else if (ev->subtype == EV_GUI_KeyDown)
@ -143,15 +149,15 @@ bool DTextEnterMenu::Responder(event_t *ev)
}
else if (ch == '\r')
{
if (mEnterString[0])
if (mEnterString.IsNotEmpty())
{
// [TP] If we allow color codes, colorize the string now.
if (AllowColors)
strbin(mEnterString);
mEnterString = strbin1(mEnterString);
DMenu *parent = mParentMenu;
Close();
parent->CallMenuEvent(MKEY_Input, false);
Close();
return true;
}
}
@ -245,9 +251,9 @@ bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller)
return true;
case MKEY_Clear:
if (mEnterPos > 0)
if (mEnterString.IsNotEmpty())
{
mEnterString[--mEnterPos] = 0;
mEnterString.Truncate(mEnterString.Len() - 1);
}
return true;
@ -258,7 +264,7 @@ bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller)
ch = InputGridChars[InputGridX + InputGridY * INPUTGRID_WIDTH];
if (ch == 0) // end
{
if (mEnterString[0] != '\0')
if (mEnterString.IsNotEmpty())
{
DMenu *parent = mParentMenu;
Close();
@ -268,16 +274,15 @@ bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller)
}
else if (ch == '\b') // bs
{
if (mEnterPos > 0)
if (mEnterString.IsNotEmpty())
{
mEnterString[--mEnterPos] = 0;
mEnterString.Truncate(mEnterString.Len() - 1);
}
}
else if (mEnterPos < mEnterSize &&
else if (mEnterString.Len() < mEnterSize &&
(mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8))
{
mEnterString[mEnterPos] = ch;
mEnterString[++mEnterPos] = 0;
mEnterString += char(ch);
}
}
return true;
@ -368,4 +373,24 @@ void DTextEnterMenu::Drawer ()
}
}
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

@ -47,7 +47,6 @@
#include "g_game.h"
extern FSaveGameNode *quickSaveSlot;
EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd]
class DMessageBoxMenu : public DMenu
@ -549,7 +548,7 @@ DQuickSaveMenu::DQuickSaveMenu(bool playsound)
{
FString tempstring;
tempstring.Format(GStrings("QSPROMPT"), quickSaveSlot->Title);
tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->Title);
Init(NULL, tempstring, 0, playsound);
}
@ -563,7 +562,7 @@ void DQuickSaveMenu::HandleResult(bool res)
{
if (res)
{
G_SaveGame (quickSaveSlot->Filename.GetChars(), quickSaveSlot->Title);
G_SaveGame (savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title);
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
M_ClearMenus();
}
@ -591,7 +590,7 @@ CCMD (quicksave)
if (gamestate != GS_LEVEL)
return;
if (quickSaveSlot == NULL)
if (savegameManager.quickSaveSlot == NULL)
{
S_Sound(CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
M_StartControlPanel(false);
@ -602,7 +601,7 @@ CCMD (quicksave)
// [mxd]. Just save the game, no questions asked.
if (!saveloadconfirmation)
{
G_SaveGame(quickSaveSlot->Filename.GetChars(), quickSaveSlot->Title);
G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title);
return;
}
@ -645,7 +644,7 @@ DQuickLoadMenu::DQuickLoadMenu(bool playsound)
{
FString tempstring;
tempstring.Format(GStrings("QLPROMPT"), quickSaveSlot->Title);
tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->Title);
Init(NULL, tempstring, 0, playsound);
}
@ -659,7 +658,7 @@ void DQuickLoadMenu::HandleResult(bool res)
{
if (res)
{
G_LoadGame (quickSaveSlot->Filename.GetChars());
G_LoadGame (savegameManager.quickSaveSlot->Filename.GetChars());
S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
M_ClearMenus();
}
@ -685,11 +684,11 @@ CCMD (quickload)
return;
}
if (quickSaveSlot == NULL)
if (savegameManager.quickSaveSlot == NULL)
{
M_StartControlPanel(true);
// signal that whatever gets loaded should be the new quicksave
quickSaveSlot = (FSaveGameNode *)1;
savegameManager.quickSaveSlot = (FSaveGameNode *)1;
M_SetMenu(NAME_Loadgamemenu);
return;
}
@ -697,7 +696,7 @@ CCMD (quickload)
// [mxd]. Just load the game, no questions asked.
if (!saveloadconfirmation)
{
G_LoadGame(quickSaveSlot->Filename.GetChars());
G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars());
return;
}
@ -725,3 +724,12 @@ void M_StartMessage(const char *message, int messagemode, FName action)
M_ActivateMenu(newmenu);
}
DEFINE_ACTION_FUNCTION(DMenu, StartMessage)
{
PARAM_PROLOGUE;
PARAM_STRING(msg);
PARAM_INT(mode);
PARAM_NAME_DEF(action);
M_StartMessage(msg, mode, action);
return 0;
}

View file

@ -3,7 +3,7 @@
** Handler class for the option menus and associated items
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** Copyright 2010-2017 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -49,485 +49,12 @@
#include "menu/menu.h"
//=============================================================================
//
// Draws a string in the console font, scaled to the 8x8 cells
// used by the default console font.
//
//=============================================================================
void M_DrawConText (int color, int x, int y, const char *str)
{
screen->DrawText (ConFont, color, x, y, str,
DTA_CellX, 8 * CleanXfac_1,
DTA_CellY, 8 * CleanYfac_1,
TAG_DONE);
}
IMPLEMENT_CLASS(DOptionMenu, false, false)
IMPLEMENT_POINTERS_START(DOptionMenu)
IMPLEMENT_POINTER(mFocusControl)
IMPLEMENT_POINTERS_END
//=============================================================================
//
//
//
//=============================================================================
DOptionMenu::DOptionMenu(DMenu *parent, DOptionMenuDescriptor *desc)
: DMenu(parent)
{
CanScrollUp = false;
CanScrollDown = false;
VisBottom = 0;
mFocusControl = NULL;
Init(parent, desc);
}
//=============================================================================
//
//
//
//=============================================================================
void DOptionMenu::Init(DMenu *parent, DOptionMenuDescriptor *desc)
{
mParentMenu = parent;
GC::WriteBarrier(this, parent);
mDesc = desc;
if (mDesc != NULL && mDesc->mSelectedItem == -1) mDesc->mSelectedItem = FirstSelectable();
}
//=============================================================================
//
//
//
//=============================================================================
int DOptionMenu::FirstSelectable()
{
if (mDesc != NULL)
{
// Go down to the first selectable item
int i = -1;
do
{
i++;
}
while (i < (int)mDesc->mItems.Size() && !mDesc->mItems[i]->Selectable());
if (i>=0 && i < (int)mDesc->mItems.Size()) return i;
}
return -1;
}
//=============================================================================
//
//
//
//=============================================================================
IMPLEMENT_CLASS(DOptionMenuItem, true, false)
DOptionMenuItem *DOptionMenu::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 DOptionMenu::Responder (event_t *ev)
{
if (ev->type == EV_GUI_Event)
{
if (ev->subtype == EV_GUI_WheelUp)
{
int scrollamt = MIN(2, mDesc->mScrollPos);
mDesc->mScrollPos -= scrollamt;
return true;
}
else if (ev->subtype == EV_GUI_WheelDown)
{
if (CanScrollDown)
{
if (VisBottom < (int)(mDesc->mItems.Size()-2))
{
mDesc->mScrollPos += 2;
VisBottom += 2;
}
else
{
mDesc->mScrollPos++;
VisBottom++;
}
}
return true;
}
}
return Super::Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
bool DOptionMenu::MenuEvent (int mkey, bool fromcontroller)
{
int startedAt = mDesc->mSelectedItem;
switch (mkey)
{
case MKEY_Up:
if (mDesc->mSelectedItem == -1)
{
mDesc->mSelectedItem = FirstSelectable();
break;
}
do
{
--mDesc->mSelectedItem;
if (mDesc->mScrollPos > 0 &&
mDesc->mSelectedItem <= mDesc->mScrollTop + mDesc->mScrollPos)
{
mDesc->mScrollPos = MAX(mDesc->mSelectedItem - mDesc->mScrollTop - 1, 0);
}
if (mDesc->mSelectedItem < 0)
{
// Figure out how many lines of text fit on the menu
int y = mDesc->mPosition;
if (y <= 0)
{
if (BigFont && mDesc->mTitle.IsNotEmpty())
{
y = -y + BigFont->GetHeight();
}
else
{
y = -y;
}
}
y *= CleanYfac_1;
int rowheight = OptionSettings.mLinespacing * CleanYfac_1;
int maxitems = (screen->GetHeight() - rowheight - y) / rowheight + 1;
mDesc->mScrollPos = MAX (0, (int)mDesc->mItems.Size() - maxitems + mDesc->mScrollTop);
mDesc->mSelectedItem = mDesc->mItems.Size()-1;
}
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
break;
case MKEY_Down:
if (mDesc->mSelectedItem == -1)
{
mDesc->mSelectedItem = FirstSelectable();
break;
}
do
{
++mDesc->mSelectedItem;
if (CanScrollDown && mDesc->mSelectedItem == VisBottom)
{
mDesc->mScrollPos++;
VisBottom++;
}
if (mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
{
if (startedAt == -1)
{
mDesc->mSelectedItem = -1;
mDesc->mScrollPos = -1;
break;
}
else
{
mDesc->mSelectedItem = 0;
mDesc->mScrollPos = 0;
}
}
}
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable() && mDesc->mSelectedItem != startedAt);
break;
case MKEY_PageUp:
if (mDesc->mScrollPos > 0)
{
mDesc->mScrollPos -= VisBottom - mDesc->mScrollPos - mDesc->mScrollTop;
if (mDesc->mScrollPos < 0)
{
mDesc->mScrollPos = 0;
}
if (mDesc->mSelectedItem != -1)
{
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos + 1;
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
{
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
{
mDesc->mSelectedItem = 0;
}
}
if (mDesc->mScrollPos > mDesc->mSelectedItem)
{
mDesc->mScrollPos = mDesc->mSelectedItem;
}
}
}
break;
case MKEY_PageDown:
if (CanScrollDown)
{
int pagesize = VisBottom - mDesc->mScrollPos - mDesc->mScrollTop;
mDesc->mScrollPos += pagesize;
if (mDesc->mScrollPos + mDesc->mScrollTop + pagesize > (int)mDesc->mItems.Size())
{
mDesc->mScrollPos = mDesc->mItems.Size() - mDesc->mScrollTop - pagesize;
}
if (mDesc->mSelectedItem != -1)
{
mDesc->mSelectedItem = mDesc->mScrollTop + mDesc->mScrollPos;
while (!mDesc->mItems[mDesc->mSelectedItem]->Selectable())
{
if (++mDesc->mSelectedItem >= (int)mDesc->mItems.Size())
{
mDesc->mSelectedItem = 0;
}
}
if (mDesc->mScrollPos > mDesc->mSelectedItem)
{
mDesc->mScrollPos = mDesc->mSelectedItem;
}
}
}
break;
case MKEY_Enter:
if (mDesc->mSelectedItem >= 0 && mDesc->mItems[mDesc->mSelectedItem]->Activate())
{
return true;
}
// fall through to default
default:
if (mDesc->mSelectedItem >= 0 &&
mDesc->mItems[mDesc->mSelectedItem]->MenuEvent(mkey, fromcontroller)) return true;
return Super::MenuEvent(mkey, fromcontroller);
}
if (mDesc->mSelectedItem != startedAt)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
return true;
}
//=============================================================================
//
//
//
//=============================================================================
bool DOptionMenu::MouseEvent(int type, int x, int y)
{
y = (y / CleanYfac_1) - mDesc->mDrawTop;
if (mFocusControl)
{
mFocusControl->MouseEvent(type, x, y);
return true;
}
else
{
int yline = (y / OptionSettings.mLinespacing);
if (yline >= mDesc->mScrollTop)
{
yline += mDesc->mScrollPos;
}
if ((unsigned)yline < mDesc->mItems.Size() && mDesc->mItems[yline]->Selectable())
{
if (yline != mDesc->mSelectedItem)
{
mDesc->mSelectedItem = yline;
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
mDesc->mItems[yline]->MouseEvent(type, x, y);
return true;
}
}
mDesc->mSelectedItem = -1;
return Super::MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
void DOptionMenu::Ticker ()
{
Super::Ticker();
for(unsigned i=0;i<mDesc->mItems.Size(); i++)
{
mDesc->mItems[i]->Ticker();
}
}
//=============================================================================
//
//
//
//=============================================================================
void DOptionMenu::Drawer ()
{
int y = mDesc->mPosition;
if (y <= 0)
{
if (BigFont && mDesc->mTitle.IsNotEmpty())
{
const char *tt = mDesc->mTitle;
if (*tt == '$') tt = GStrings(tt+1);
screen->DrawText (BigFont, OptionSettings.mTitleColor,
(screen->GetWidth() - BigFont->StringWidth(tt) * CleanXfac_1) / 2, 10*CleanYfac_1,
tt, DTA_CleanNoMove_1, true, TAG_DONE);
y = -y + BigFont->GetHeight();
}
else
{
y = -y;
}
}
mDesc->mDrawTop = y;
int fontheight = OptionSettings.mLinespacing * CleanYfac_1;
y *= CleanYfac_1;
int indent = mDesc->mIndent;
if (indent > 280)
{ // kludge for the compatibility options with their extremely long labels
if (indent + 40 <= CleanWidth_1)
{
indent = (screen->GetWidth() - ((indent + 40) * CleanXfac_1)) / 2 + indent * CleanXfac_1;
}
else
{
indent = screen->GetWidth() - 40 * CleanXfac_1;
}
}
else
{
indent = (indent - 160) * CleanXfac_1 + screen->GetWidth() / 2;
}
int ytop = y + mDesc->mScrollTop * 8 * CleanYfac_1;
int lastrow = screen->GetHeight() - SmallFont->GetHeight() * CleanYfac_1;
unsigned i;
for (i = 0; i < mDesc->mItems.Size() && y <= lastrow; i++, y += fontheight)
{
// Don't scroll the uppermost items
if ((int)i == mDesc->mScrollTop)
{
i += mDesc->mScrollPos;
if (i >= mDesc->mItems.Size()) break; // skipped beyond end of menu
}
bool isSelected = mDesc->mSelectedItem == (int)i;
int cur_indent = mDesc->mItems[i]->Draw(mDesc, y, indent, isSelected);
if (cur_indent >= 0 && isSelected && mDesc->mItems[i]->Selectable())
{
if (((DMenu::MenuTime%8) < 6) || DMenu::CurrentMenu != this)
{
M_DrawConText(OptionSettings.mFontColorSelection, cur_indent + 3 * CleanXfac_1, y+fontheight-9*CleanYfac_1, "\xd");
}
}
}
CanScrollUp = (mDesc->mScrollPos > 0);
CanScrollDown = (i < mDesc->mItems.Size());
VisBottom = i - 1;
if (CanScrollUp)
{
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, ytop, "\x1a");
}
if (CanScrollDown)
{
M_DrawConText(CR_ORANGE, 3 * CleanXfac_1, y - 8*CleanYfac_1, "\x1b");
}
Super::Drawer();
}
//=============================================================================
//
// base class for menu items
//
//=============================================================================
int DOptionMenuItem::Draw(DOptionMenuDescriptor *desc, int y, int indent, bool selected)
{
return indent;
}
bool DOptionMenuItem::Selectable()
{
return true;
}
bool DOptionMenuItem::MouseEvent(int type, int x, int y)
{
if (Selectable() && type == DMenu::MOUSE_Release)
{
return DMenu::CurrentMenu->CallMenuEvent(MKEY_Enter, true);
}
return false;
}
int DOptionMenuItem::GetIndent()
{
if (mCentered)
{
return 0;
}
const char *label = mLabel.GetChars();
if (*label == '$') label = GStrings(label+1);
return SmallFont->StringWidth(label);
}
void DOptionMenuItem::drawLabel(int indent, int y, EColorRange color, bool grayed)
{
const char *label = mLabel.GetChars();
if (*label == '$') label = GStrings(label+1);
int overlay = grayed? MAKEARGB(96,48,0,0) : 0;
int x;
int w = SmallFont->StringWidth(label) * CleanXfac_1;
if (!mCentered) x = indent - w;
else x = (screen->GetWidth() - w) / 2;
screen->DrawText (SmallFont, color, x, y, label, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay, TAG_DONE);
}
void DOptionMenuDescriptor::CalcIndent()
{
// calculate the menu indent
@ -541,13 +68,20 @@ void DOptionMenuDescriptor::CalcIndent()
mIndent = widest + 4;
}
DEFINE_ACTION_FUNCTION(DOptionMenuDescriptor, CalcIndent)
{
PARAM_SELF_PROLOGUE(DOptionMenuDescriptor);
self->CalcIndent();
return 0;
}
//=============================================================================
//
//
//
//=============================================================================
DOptionMenuItem *DOptionMenuDescriptor::GetItem(FName name)
DMenuItemBase *DOptionMenuDescriptor::GetItem(FName name)
{
for(unsigned i=0;i<mItems.Size(); i++)
{
@ -557,49 +91,3 @@ DOptionMenuItem *DOptionMenuDescriptor::GetItem(FName name)
return NULL;
}
class DGameplayMenu : public DOptionMenu
{
DECLARE_CLASS(DGameplayMenu, DOptionMenu)
public:
DGameplayMenu()
{}
void Drawer ()
{
Super::Drawer();
char text[64];
mysnprintf(text, 64, "dmflags = %d dmflags2 = %d", *dmflags, *dmflags2);
screen->DrawText (SmallFont, OptionSettings.mFontColorValue,
(screen->GetWidth() - SmallFont->StringWidth (text) * CleanXfac_1) / 2, 0, text,
DTA_CleanNoMove_1, true, TAG_DONE);
}
};
IMPLEMENT_CLASS(DGameplayMenu, false, false)
class DCompatibilityMenu : public DOptionMenu
{
DECLARE_CLASS(DCompatibilityMenu, DOptionMenu)
public:
DCompatibilityMenu()
{}
void Drawer ()
{
Super::Drawer();
char text[64];
mysnprintf(text, 64, "compatflags = %d compatflags2 = %d", *compatflags, *compatflags2);
screen->DrawText (SmallFont, OptionSettings.mFontColorValue,
(screen->GetWidth() - SmallFont->StringWidth (text) * CleanXfac_1) / 2, 0, text,
DTA_CleanNoMove_1, true, TAG_DONE);
}
};
IMPLEMENT_CLASS(DCompatibilityMenu, false, false)

File diff suppressed because it is too large Load diff

View file

@ -1,320 +0,0 @@
/*
** playerdisplay.cpp
** The player display for the player setup and class selection screen
**
**---------------------------------------------------------------------------
** 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 "doomtype.h"
#include "doomstat.h"
#include "d_player.h"
#include "templates.h"
#include "menu/menu.h"
#include "colormatcher.h"
#include "textures/textures.h"
#include "w_wad.h"
#include "v_font.h"
#include "v_video.h"
#include "g_level.h"
#include "gi.h"
#include "r_defs.h"
#include "r_state.h"
#include "r_data/r_translate.h"
//=============================================================================
//
//
//
//=============================================================================
IMPLEMENT_CLASS(DListMenuItemPlayerDisplay, false, false)
DListMenuItemPlayerDisplay::DListMenuItemPlayerDisplay(DListMenuDescriptor *menu, int x, int y, PalEntry c1, PalEntry c2, bool np, FName action)
: DMenuItemBase(x, y, action)
{
mOwner = menu;
FRemapTable *bdremap = translationtables[TRANSLATION_Players][MAXPLAYERS + 1];
for (int i = 0; i < 256; i++)
{
int r = c1.r + c2.r * i / 255;
int g = c1.g + c2.g * i / 255;
int b = c1.b + c2.b * i / 255;
bdremap->Remap[i] = ColorMatcher.Pick (r, g, b);
bdremap->Palette[i] = PalEntry(255, r, g, b);
}
auto id = TexMan.CheckForTexture("PlayerBackdrop", FTexture::TEX_MiscPatch);
mBackdrop = TexMan[id];
mPlayerClass = NULL;
mPlayerState = NULL;
mNoportrait = np;
mMode = 0;
mRotation = 0;
mTranslate = false;
mSkin = 0;
mRandomClass = 0;
mRandomTimer = 0;
mClassNum = -1;
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenuItemPlayerDisplay::OnDestroy()
{
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenuItemPlayerDisplay::UpdateRandomClass()
{
if (--mRandomTimer < 0)
{
if (++mRandomClass >= (int)PlayerClasses.Size ()) mRandomClass = 0;
mPlayerClass = &PlayerClasses[mRandomClass];
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SeeState;
if (mPlayerState == NULL)
{ // No see state, so try spawn state.
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SpawnState;
}
mPlayerTics = mPlayerState != NULL ? mPlayerState->GetTics() : -1;
mRandomTimer = 6;
// Since the newly displayed class may used a different translation
// range than the old one, we need to update the translation, too.
UpdateTranslation();
}
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenuItemPlayerDisplay::UpdateTranslation()
{
int PlayerColor = players[consoleplayer].userinfo.GetColor();
int PlayerSkin = players[consoleplayer].userinfo.GetSkin();
int PlayerColorset = players[consoleplayer].userinfo.GetColorSet();
if (mPlayerClass != NULL)
{
PlayerSkin = R_FindSkin (skins[PlayerSkin].name, int(mPlayerClass - &PlayerClasses[0]));
R_GetPlayerTranslation(PlayerColor, GetColorSet(mPlayerClass->Type, PlayerColorset),
&skins[PlayerSkin], translationtables[TRANSLATION_Players][MAXPLAYERS]);
}
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenuItemPlayerDisplay::SetPlayerClass(int classnum, bool force)
{
if (classnum < 0 || classnum >= (int)PlayerClasses.Size ())
{
if (mClassNum != -1)
{
mClassNum = -1;
mRandomTimer = 0;
UpdateRandomClass();
}
}
else if (mPlayerClass != &PlayerClasses[classnum] || force)
{
mPlayerClass = &PlayerClasses[classnum];
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SeeState;
if (mPlayerState == NULL)
{ // No see state, so try spawn state.
mPlayerState = GetDefaultByType (mPlayerClass->Type)->SpawnState;
}
mPlayerTics = mPlayerState != NULL ? mPlayerState->GetTics() : -1;
mClassNum = classnum;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenuItemPlayerDisplay::UpdatePlayerClass()
{
if (mOwner->mSelectedItem >= 0)
{
int classnum;
FName seltype = mOwner->mItems[mOwner->mSelectedItem]->GetAction(&classnum);
if (seltype != NAME_Episodemenu) return false;
if (PlayerClasses.Size() == 0) return false;
SetPlayerClass(classnum);
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenuItemPlayerDisplay::SetValue(int i, int value)
{
switch (i)
{
case PDF_MODE:
mMode = value;
return true;
case PDF_ROTATION:
mRotation = value;
return true;
case PDF_TRANSLATE:
mTranslate = value;
case PDF_CLASS:
SetPlayerClass(value, true);
break;
case PDF_SKIN:
mSkin = value;
break;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenuItemPlayerDisplay::Ticker()
{
if (mClassNum < 0) UpdateRandomClass();
if (mPlayerState != NULL && mPlayerState->GetTics () != -1 && mPlayerState->GetNextState () != NULL)
{
if (--mPlayerTics <= 0)
{
mPlayerState = mPlayerState->GetNextState();
mPlayerTics = mPlayerState->GetTics();
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenuItemPlayerDisplay::Drawer(bool selected)
{
if (mMode == 0 && !UpdatePlayerClass())
{
return;
}
FName portrait = ((APlayerPawn*)GetDefaultByType(mPlayerClass->Type))->Portrait;
if (portrait != NAME_None && !mNoportrait)
{
FTextureID texid = TexMan.CheckForTexture(portrait.GetChars(), FTexture::TEX_MiscPatch);
if (texid.isValid())
{
FTexture *tex = TexMan(texid);
if (tex != NULL)
{
screen->DrawTexture (tex, mXpos, mYpos, DTA_Clean, true, TAG_DONE);
return;
}
}
}
int x = (mXpos - 160) * CleanXfac + (SCREENWIDTH>>1);
int y = (mYpos - 100) * CleanYfac + (SCREENHEIGHT>>1);
screen->DrawTexture(mBackdrop, x, y - 1,
DTA_DestWidth, 72 * CleanXfac,
DTA_DestHeight, 80 * CleanYfac,
DTA_TranslationIndex, TRANSLATION(TRANSLATION_Players, MAXPLAYERS + 1),
DTA_Masked, true,
TAG_DONE);
V_DrawFrame (x, y, 72*CleanXfac, 80*CleanYfac-1);
spriteframe_t *sprframe = NULL;
DVector2 Scale;
if (mPlayerState != NULL)
{
if (mSkin == 0)
{
sprframe = &SpriteFrames[sprites[mPlayerState->sprite].spriteframes + mPlayerState->GetFrame()];
Scale = GetDefaultByType(mPlayerClass->Type)->Scale;
}
else
{
sprframe = &SpriteFrames[sprites[skins[mSkin].sprite].spriteframes + mPlayerState->GetFrame()];
Scale = skins[mSkin].Scale;
}
}
if (sprframe != NULL)
{
FTexture *tex = TexMan(sprframe->Texture[mRotation]);
if (tex != NULL && tex->UseType != FTexture::TEX_Null)
{
int trans = mTranslate? TRANSLATION(TRANSLATION_Players, MAXPLAYERS) : 0;
screen->DrawTexture (tex,
x + 36*CleanXfac, y + 71*CleanYfac,
DTA_DestWidthF, tex->GetScaledWidthDouble() * CleanXfac * Scale.X,
DTA_DestHeightF, tex->GetScaledHeightDouble() * CleanYfac * Scale.Y,
DTA_TranslationIndex, trans,
DTA_FlipX, sprframe->Flip & (1 << mRotation),
TAG_DONE);
}
}
}

View file

@ -55,428 +55,6 @@ EXTERN_CVAR (Float, autoaim)
EXTERN_CVAR(Bool, neverswitchonpickup)
EXTERN_CVAR (Bool, cl_run)
//=============================================================================
//
// Player's name
//
//=============================================================================
IMPLEMENT_CLASS(DPlayerNameBox, false, false)
DPlayerNameBox::DPlayerNameBox(int x, int y, int height, int frameofs, const char *text, FFont *font, EColorRange color, FName action)
: DListMenuItemSelectable(x, y, height, action)
{
mText = text;
mFont = font;
mFontColor = color;
mFrameSize = frameofs;
mPlayerName[0] = 0;
mEntering = false;
}
//=============================================================================
//
//
//
//=============================================================================
bool DPlayerNameBox::SetString(int i, const char *s)
{
if (i == 0)
{
strncpy(mPlayerName, s, MAXPLAYERNAME);
mPlayerName[MAXPLAYERNAME] = 0;
return true;
}
return false;
}
bool DPlayerNameBox::GetString(int i, char *s, int len)
{
if (i == 0)
{
strncpy(s, mPlayerName, len);
s[len] = 0;
return true;
}
return false;
}
//=============================================================================
//
// [RH] Width of the border is variable
//
//=============================================================================
void DPlayerNameBox::DrawBorder (int x, int y, int len)
{
FTexture *left = TexMan[TexMan.CheckForTexture("M_LSLEFT", FTexture::TEX_MiscPatch)];
FTexture *mid = TexMan[TexMan.CheckForTexture("M_LSCNTR", FTexture::TEX_MiscPatch)];
FTexture *right = TexMan[TexMan.CheckForTexture("M_LSRGHT", FTexture::TEX_MiscPatch)];
if (left != NULL && right != NULL && mid != NULL)
{
int i;
screen->DrawTexture (left, x-8, y+7, DTA_Clean, true, TAG_DONE);
for (i = 0; i < len; i++)
{
screen->DrawTexture (mid, x, y+7, DTA_Clean, true, TAG_DONE);
x += 8;
}
screen->DrawTexture (right, x, y+7, DTA_Clean, true, TAG_DONE);
}
else
{
FTexture *slot = TexMan[TexMan.CheckForTexture("M_FSLOT", FTexture::TEX_MiscPatch)];
if (slot != NULL)
{
screen->DrawTexture (slot, x, y+1, DTA_Clean, true, TAG_DONE);
}
else
{
screen->Clear(x, y, x + len, y + SmallFont->GetHeight() * 3/2, -1, 0);
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void DPlayerNameBox::Drawer(bool selected)
{
const char *text = mText;
if (text != NULL)
{
if (*text == '$') text = GStrings(text+1);
screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
}
// Draw player name box
int x = mXpos + mFont->StringWidth(text) + 16 + mFrameSize;
DrawBorder (x, mYpos - mFrameSize, MAXPLAYERNAME+1);
if (!mEntering)
{
screen->DrawText (SmallFont, CR_UNTRANSLATED, x + mFrameSize, mYpos, mPlayerName,
DTA_Clean, true, TAG_DONE);
}
else
{
size_t l = strlen(mEditName);
mEditName[l] = SmallFont->GetCursor();
mEditName[l+1] = 0;
screen->DrawText (SmallFont, CR_UNTRANSLATED, x + mFrameSize, mYpos, mEditName,
DTA_Clean, true, TAG_DONE);
mEditName[l] = 0;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DPlayerNameBox::MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == MKEY_Enter)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
strcpy(mEditName, mPlayerName);
mEntering = true;
DMenu *input = new DTextEnterMenu(DMenu::CurrentMenu, mEditName, MAXPLAYERNAME, 2, fromcontroller);
M_ActivateMenu(input);
return true;
}
else if (mkey == MKEY_Input)
{
strcpy(mPlayerName, mEditName);
mEntering = false;
return true;
}
else if (mkey == MKEY_Abort)
{
mEntering = false;
return true;
}
return false;
}
//=============================================================================
//
// items for the player menu
//
//=============================================================================
IMPLEMENT_CLASS(DValueTextItem, false, false)
DValueTextItem::DValueTextItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, EColorRange valuecolor, FName action, FName values)
: DListMenuItemSelectable(x, y, height, action)
{
mText = text;
mFont = font;
mFontColor = color;
mFontColor2 = valuecolor;
mSelection = 0;
if (values != NAME_None)
{
FOptionValues **opt = OptionValues.CheckKey(values);
if (opt != NULL)
{
for(unsigned i=0;i<(*opt)->mValues.Size(); i++)
{
SetString(i, (*opt)->mValues[i].Text);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
bool DValueTextItem::SetString(int i, const char *s)
{
// should actually use the index...
FString str = s;
if (i==0) mSelections.Clear();
mSelections.Push(str);
return true;
}
//=============================================================================
//
//
//
//=============================================================================
bool DValueTextItem::SetValue(int i, int value)
{
if (i == 0)
{
mSelection = value;
return true;
}
return false;
}
bool DValueTextItem::GetValue(int i, int *pvalue)
{
if (i == 0)
{
*pvalue = mSelection;
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
bool DValueTextItem::MenuEvent (int mkey, bool fromcontroller)
{
if (mSelections.Size() > 1)
{
if (mkey == MKEY_Left)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
if (--mSelection < 0) mSelection = mSelections.Size() - 1;
return true;
}
else if (mkey == MKEY_Right || mkey == MKEY_Enter)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
if (++mSelection >= (int)mSelections.Size()) mSelection = 0;
return true;
}
}
return (mkey == MKEY_Enter); // needs to eat enter keys so that Activate won't get called
}
//=============================================================================
//
//
//
//=============================================================================
void DValueTextItem::Drawer(bool selected)
{
const char *text = mText;
if (*text == '$') text = GStrings(text+1);
screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
int x = mXpos + mFont->StringWidth(text) + 8;
if (mSelections.Size() > 0)
{
const char *mOptValue = mSelections[mSelection];
if (*mOptValue == '$') mOptValue = GStrings(mOptValue + 1);
screen->DrawText(mFont, mFontColor2, x, mYpos, mOptValue, DTA_Clean, true, TAG_DONE);
}
}
//=============================================================================
//
// items for the player menu
//
//=============================================================================
IMPLEMENT_CLASS(DSliderItem, false, false)
DSliderItem::DSliderItem(int x, int y, int height, const char *text, FFont *font, EColorRange color, FName action, int min, int max, int step)
: DListMenuItemSelectable(x, y, height, action)
{
mText = text;
mFont = font;
mFontColor = color;
mSelection = 0;
mMinrange = min;
mMaxrange = max;
mStep = step;
}
//=============================================================================
//
//
//
//=============================================================================
bool DSliderItem::SetValue(int i, int value)
{
if (i == 0)
{
mSelection = value;
return true;
}
return false;
}
bool DSliderItem::GetValue(int i, int *pvalue)
{
if (i == 0)
{
*pvalue = mSelection;
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
bool DSliderItem::MenuEvent (int mkey, bool fromcontroller)
{
if (mkey == MKEY_Left)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
if ((mSelection -= mStep) < mMinrange) mSelection = mMinrange;
return true;
}
else if (mkey == MKEY_Right || mkey == MKEY_Enter)
{
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
if ((mSelection += mStep) > mMaxrange) mSelection = mMaxrange;
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
bool DSliderItem::MouseEvent(int type, int x, int y)
{
DListMenu *lm = static_cast<DListMenu*>(DMenu::CurrentMenu);
if (type != DMenu::MOUSE_Click)
{
if (!lm->CheckFocus(this)) return false;
}
if (type == DMenu::MOUSE_Release)
{
lm->ReleaseFocus();
}
int slide_left = SmallFont->StringWidth ("Green") + 8 + mXpos;
int slide_right = slide_left + 12*8; // 12 char cells with 8 pixels each.
if (type == DMenu::MOUSE_Click)
{
if (x < slide_left || x >= slide_right) return true;
}
x = clamp(x, slide_left, slide_right);
int v = mMinrange + Scale(x - slide_left, mMaxrange - mMinrange, slide_right - slide_left);
if (v != mSelection)
{
mSelection = v;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
}
if (type == DMenu::MOUSE_Click)
{
lm->SetFocus(this);
}
return true;
}
//=============================================================================
//
//
//
//=============================================================================
void DSliderItem::DrawSlider (int x, int y)
{
int range = mMaxrange - mMinrange;
int cur = mSelection - mMinrange;
x = (x - 160) * CleanXfac + screen->GetWidth() / 2;
y = (y - 100) * CleanYfac + screen->GetHeight() / 2;
screen->DrawText (ConFont, CR_WHITE, x, y,
"\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac,
TAG_DONE);
screen->DrawText (ConFont, CR_ORANGE, x + (5 + (int)((cur * 78) / range)) * CleanXfac, y,
"\x13",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac,
TAG_DONE);
}
//=============================================================================
//
//
//
//=============================================================================
void DSliderItem::Drawer(bool selected)
{
const char *text = mText;
if (*text == '$') text = GStrings(text+1);
screen->DrawText(mFont, selected? OptionSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true, TAG_DONE);
int x = SmallFont->StringWidth ("Green") + 8 + mXpos;
int x2 = SmallFont->StringWidth (text) + 8 + mXpos;
DrawSlider (MAX(x2, x), mYpos);
}
//=============================================================================
//
//
@ -524,6 +102,14 @@ IMPLEMENT_CLASS(DPlayerMenu, false, false)
//
//
//=============================================================================
enum EPDFlags
{
ListMenuItemPlayerDisplay_PDF_ROTATION = 0x10001,
ListMenuItemPlayerDisplay_PDF_SKIN = 0x10002,
ListMenuItemPlayerDisplay_PDF_CLASS = 0x10003,
ListMenuItemPlayerDisplay_PDF_MODE = 0x10004,
ListMenuItemPlayerDisplay_PDF_TRANSLATE = 0x10005,
};
void DPlayerMenu::Init(DMenu *parent, DListMenuDescriptor *desc)
{
@ -536,14 +122,14 @@ void DPlayerMenu::Init(DMenu *parent, DListMenuDescriptor *desc)
li = GetItem(NAME_Playerdisplay);
if (li != NULL)
{
li->SetValue(DListMenuItemPlayerDisplay::PDF_ROTATION, 0);
li->SetValue(DListMenuItemPlayerDisplay::PDF_MODE, 1);
li->SetValue(DListMenuItemPlayerDisplay::PDF_TRANSLATE, 1);
li->SetValue(DListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum());
li->SetValue(ListMenuItemPlayerDisplay_PDF_ROTATION, 0);
li->SetValue(ListMenuItemPlayerDisplay_PDF_MODE, 1);
li->SetValue(ListMenuItemPlayerDisplay_PDF_TRANSLATE, 1);
li->SetValue(ListMenuItemPlayerDisplay_PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum());
if (PlayerClass != NULL && !(GetDefaultByType (PlayerClass->Type)->flags4 & MF4_NOSKIN) &&
players[consoleplayer].userinfo.GetPlayerClassNum() != -1)
{
li->SetValue(DListMenuItemPlayerDisplay::PDF_SKIN, players[consoleplayer].userinfo.GetSkin());
li->SetValue(ListMenuItemPlayerDisplay_PDF_SKIN, players[consoleplayer].userinfo.GetSkin());
}
}
@ -658,7 +244,7 @@ bool DPlayerMenu::Responder (event_t *ev)
DMenuItemBase *li = GetItem(NAME_Playerdisplay);
if (li != NULL)
{
li->SetValue(DListMenuItemPlayerDisplay::PDF_ROTATION, mRotation);
li->SetValue(ListMenuItemPlayerDisplay_PDF_ROTATION, mRotation);
}
return true;
}
@ -812,7 +398,7 @@ void DPlayerMenu::UpdateSkins()
li = GetItem(NAME_Playerdisplay);
if (li != NULL)
{
li->SetValue(DListMenuItemPlayerDisplay::PDF_SKIN, skin);
li->SetValue(ListMenuItemPlayerDisplay_PDF_SKIN, skin);
}
}
UpdateTranslation();
@ -908,7 +494,7 @@ void DPlayerMenu::ClassChanged (DMenuItemBase *li)
li = GetItem(NAME_Playerdisplay);
if (li != NULL)
{
li->SetValue(DListMenuItemPlayerDisplay::PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum());
li->SetValue(ListMenuItemPlayerDisplay_PDF_CLASS, players[consoleplayer].userinfo.GetPlayerClassNum());
}
}
}
@ -939,7 +525,7 @@ void DPlayerMenu::SkinChanged (DMenuItemBase *li)
li = GetItem(NAME_Playerdisplay);
if (li != NULL)
{
li->SetValue(DListMenuItemPlayerDisplay::PDF_SKIN, sel);
li->SetValue(ListMenuItemPlayerDisplay_PDF_SKIN, sel);
}
}
}

View file

@ -54,10 +54,6 @@
#include "sbar.h"
#include "hardware.h"
#define NO_IMP
#include "optionmenuitems.h"
/*=======================================
*
* Video Modes Menu
@ -101,19 +97,21 @@ CUSTOM_CVAR (Int, menu_screenratios, -1, CVAR_ARCHIVE)
CUSTOM_CVAR (Bool, vid_tft, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
const int OptionMenuItemOptionBase_OP_VALUES = 0x11001;
DOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL)
{
DOptionMenuItem *it = opt->GetItem("menu_screenratios");
DMenuItemBase *it = opt->GetItem("menu_screenratios");
if (it != NULL)
{
if (self)
{
it->SetString(DOptionMenuItemOptionBase::OP_VALUES, "RatiosTFT");
it->SetString(OptionMenuItemOptionBase_OP_VALUES, "RatiosTFT");
}
else
{
it->SetString(DOptionMenuItemOptionBase::OP_VALUES, "Ratios");
it->SetString(OptionMenuItemOptionBase_OP_VALUES, "Ratios");
}
}
}
@ -131,61 +129,16 @@ CUSTOM_CVAR (Bool, vid_tft, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//
//=============================================================================
class DVideoModeMenu : public DOptionMenu
struct OptionMenuItemScreenResolution // temporary workaround
{
DECLARE_CLASS(DVideoModeMenu, DOptionMenu)
public:
DVideoModeMenu()
enum EValues
{
SetModesMenu (screen->VideoWidth, screen->VideoHeight, DisplayBits);
}
bool MenuEvent(int mkey, bool fromcontroller)
{
if ((mkey == MKEY_Up || mkey == MKEY_Down) && mDesc->mSelectedItem >= 0 &&
mDesc->mSelectedItem < (int)mDesc->mItems.Size())
{
int sel;
bool selected = mDesc->mItems[mDesc->mSelectedItem]->GetValue(DOptionMenuScreenResolutionLine::SRL_SELECTION, &sel);
bool res = Super::MenuEvent(mkey, fromcontroller);
if (selected) mDesc->mItems[mDesc->mSelectedItem]->SetValue(DOptionMenuScreenResolutionLine::SRL_SELECTION, sel);
return res;
}
return Super::MenuEvent(mkey, fromcontroller);
}
bool Responder(event_t *ev)
{
if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_KeyDown &&
(ev->data1 == 't' || ev->data1 == 'T'))
{
if (!GetSelectedSize (&NewWidth, &NewHeight))
{
NewWidth = screen->VideoWidth;
NewHeight = screen->VideoHeight;
}
else
{
OldWidth = screen->VideoWidth;
OldHeight = screen->VideoHeight;
OldBits = DisplayBits;
NewBits = BitTranslate[DummyDepthCvar];
setmodeneeded = true;
testingmode = I_GetTime(false) + 5 * TICRATE;
S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE);
SetModesMenu (NewWidth, NewHeight, NewBits);
return true;
}
}
return Super::Responder(ev);
}
SRL_INDEX = 0x30000,
SRL_SELECTION = 0x30003,
SRL_HIGHLIGHT = 0x30004,
};
};
IMPLEMENT_CLASS(DVideoModeMenu, false, false)
//=============================================================================
//
//
@ -236,10 +189,10 @@ static void BuildModesList (int hiwidth, int hiheight, int hi_bits)
{
for (i = NAME_res_0; i<= NAME_res_9; i++)
{
DOptionMenuItem *it = opt->GetItem((ENamedName)i);
DMenuItemBase *it = opt->GetItem((ENamedName)i);
if (it != NULL)
{
it->SetValue(DOptionMenuScreenResolutionLine::SRL_HIGHLIGHT, -1);
it->SetValue(OptionMenuItemScreenResolution::SRL_HIGHLIGHT, -1);
for (c = 0; c < 3; c++)
{
bool haveMode = false;
@ -260,16 +213,16 @@ static void BuildModesList (int hiwidth, int hiheight, int hi_bits)
{
if (width == hiwidth && height == hiheight)
{
it->SetValue(DOptionMenuScreenResolutionLine::SRL_SELECTION, c);
it->SetValue(DOptionMenuScreenResolutionLine::SRL_HIGHLIGHT, c);
it->SetValue(OptionMenuItemScreenResolution::SRL_SELECTION, c);
it->SetValue(OptionMenuItemScreenResolution::SRL_HIGHLIGHT, c);
}
mysnprintf (strtemp, countof(strtemp), "%dx%d%s", width, height, letterbox?TEXTCOLOR_BROWN" LB":"");
it->SetString(DOptionMenuScreenResolutionLine::SRL_INDEX+c, strtemp);
it->SetString(OptionMenuItemScreenResolution::SRL_INDEX+c, strtemp);
}
else
{
it->SetString(DOptionMenuScreenResolutionLine::SRL_INDEX+c, "");
it->SetString(OptionMenuItemScreenResolution::SRL_INDEX+c, "");
}
}
}
@ -359,12 +312,12 @@ static bool GetSelectedSize (int *width, int *height)
{
int line = opt->mSelectedItem;
int hsel;
DOptionMenuItem *it = opt->mItems[line];
if (it->GetValue(DOptionMenuScreenResolutionLine::SRL_SELECTION, &hsel))
DMenuItemBase *it = opt->mItems[line];
if (it->GetValue(OptionMenuItemScreenResolution::SRL_SELECTION, &hsel))
{
char buffer[32];
char *breakpt;
if (it->GetString(DOptionMenuScreenResolutionLine::SRL_INDEX+hsel, buffer, sizeof(buffer)))
if (it->GetString(OptionMenuItemScreenResolution::SRL_INDEX+hsel, buffer, sizeof(buffer)))
{
*width = (int)strtoll (buffer, &breakpt, 10);
*height = (int)strtoll (breakpt+1, NULL, 10);
@ -375,6 +328,27 @@ static bool GetSelectedSize (int *width, int *height)
return false;
}
DEFINE_ACTION_FUNCTION(DVideoModeMenu, SetSelectedSize)
{
if (!GetSelectedSize (&NewWidth, &NewHeight))
{
NewWidth = screen->VideoWidth;
NewHeight = screen->VideoHeight;
ACTION_RETURN_BOOL(false);
}
else
{
OldWidth = screen->VideoWidth;
OldHeight = screen->VideoHeight;
OldBits = DisplayBits;
NewBits = BitTranslate[DummyDepthCvar];
setmodeneeded = true;
testingmode = I_GetTime(false) + 5 * TICRATE;
SetModesMenu (NewWidth, NewHeight, NewBits);
ACTION_RETURN_BOOL(true);
}
}
//=============================================================================
//
//
@ -397,6 +371,11 @@ void M_SetVideoMode()
SetModesMenu (NewWidth, NewHeight, NewBits);
}
DEFINE_ACTION_FUNCTION(DMenu, SetVideoMode)
{
M_SetVideoMode();
return 0;
}
//=============================================================================
//
//
@ -423,7 +402,7 @@ static void SetModesMenu (int w, int h, int bits)
DOptionMenuDescriptor *opt = GetVideoModeMenu();
if (opt != NULL)
{
DOptionMenuItem *it;
DMenuItemBase *it;
if (testingmode <= 1)
{
it = opt->GetItem(NAME_VMEnterText);
@ -448,3 +427,8 @@ static void SetModesMenu (int w, int h, int bits)
}
BuildModesList (w, h, bits);
}
void M_InitVideoModes()
{
SetModesMenu (screen->VideoWidth, screen->VideoHeight, DisplayBits);
}

View file

@ -51,6 +51,40 @@ FStateLabelStorage StateLabels;
// actor. States are archived by recording the actor they belong
// to and the index into that actor's list of states.
//==========================================================================
//
// This wraps everything needed to get a current sprite from a state into
// one single script function.
//
//==========================================================================
DEFINE_ACTION_FUNCTION(FState, GetSpriteTexture)
{
PARAM_SELF_STRUCT_PROLOGUE(FState);
PARAM_INT(rotation);
PARAM_INT_DEF(skin);
PARAM_FLOAT_DEF(scalex);
PARAM_FLOAT_DEF(scaley);
spriteframe_t *sprframe;
if (skin == 0)
{
sprframe = &SpriteFrames[sprites[self->sprite].spriteframes + self->GetFrame()];
}
else
{
sprframe = &SpriteFrames[sprites[skins[skin].sprite].spriteframes + self->GetFrame()];
scalex = skins[skin].Scale.X;
scaley = skins[skin].Scale.Y;
}
if (numret > 0) ret[0].SetInt(sprframe->Texture[rotation].GetIndex());
if (numret > 1) ret[1].SetInt(!!(sprframe->Flip & (1 << rotation)));
if (numret > 2) ret[2].SetVector2(DVector2(scalex, scaley));
return MIN(3, numret);
}
//==========================================================================
//
// Find the actor that a state belongs to.

View file

@ -60,6 +60,7 @@
#include "p_spec.h"
#include "virtual.h"
#include "g_levellocals.h"
#include "r_data/r_translate.h"
static FRandom pr_skullpop ("SkullPop");
@ -142,6 +143,13 @@ bool FPlayerClass::CheckSkin (int skin)
return false;
}
DEFINE_ACTION_FUNCTION(FPlayerClass, CheckSkin)
{
PARAM_SELF_STRUCT_PROLOGUE(FPlayerClass);
PARAM_INT(skin);
ACTION_RETURN_BOOL(self->CheckSkin(skin));
}
//===========================================================================
//
// GetDisplayName
@ -3342,3 +3350,7 @@ DEFINE_FIELD_X(PlayerInfo, player_t, cmd)
DEFINE_FIELD_X(PlayerInfo, player_t, original_cmd)
DEFINE_FIELD_X(PlayerInfo, player_t, userinfo)
DEFINE_FIELD_X(PlayerInfo, player_t, weapons)
DEFINE_FIELD(FPlayerClass, Type)
DEFINE_FIELD(FPlayerClass, Flags)
DEFINE_FIELD(FPlayerClass, Skins)

View file

@ -740,8 +740,6 @@ void R_InitTranslationTables ()
}
// The menu player also gets a separate translation table
PushIdentityTable(TRANSLATION_Players);
// This one is for the backdrop in the menu
PushIdentityTable(TRANSLATION_Players);
// The three standard translations from Doom or Heretic (seven for Strife),
// plus the generic ice translation.
@ -1200,6 +1198,33 @@ void R_GetPlayerTranslation (int color, const FPlayerColorSet *colorset, FPlayer
R_CreatePlayerTranslation (h, s, v, colorset, skin, table, NULL, NULL);
}
DEFINE_ACTION_FUNCTION(_Translation, SetPlayerTranslation)
{
PARAM_PROLOGUE;
PARAM_UINT(tgroup);
PARAM_UINT(tnum);
PARAM_UINT(pnum);
PARAM_POINTER(cls, FPlayerClass);
if (pnum >= MAXPLAYERS || tgroup >= NUM_TRANSLATION_TABLES || tnum >= translationtables[tgroup].Size())
{
ACTION_RETURN_BOOL(false);
}
auto self = &players[pnum];
int PlayerColor = self->userinfo.GetColor();
int PlayerSkin = self->userinfo.GetSkin();
int PlayerColorset = self->userinfo.GetColorSet();
if (cls != nullptr)
{
PlayerSkin = R_FindSkin(skins[PlayerSkin].name, int(cls - &PlayerClasses[0]));
R_GetPlayerTranslation(PlayerColor, GetColorSet(cls->Type, PlayerColorset),
&skins[PlayerSkin], translationtables[tgroup][tnum]);
}
ACTION_RETURN_BOOL(true);
}
//----------------------------------------------------------------------------
//
//
@ -1307,3 +1332,29 @@ void R_ParseTrnslate()
}
}
}
//----------------------------------------------------------------------------
//
//
//
//----------------------------------------------------------------------------
struct FTranslation
{
PalEntry colors[256];
};
DEFINE_ACTION_FUNCTION(_Translation, AddTranslation)
{
PARAM_SELF_STRUCT_PROLOGUE(FTranslation);
FRemapTable NewTranslation;
memcpy(&NewTranslation.Palette[0], self->colors, 256 * sizeof(PalEntry));
for (int i = 0; i < 256; i++)
{
NewTranslation.Remap[i] = ColorMatcher.Pick(self->colors[i]);
}
int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom);
ACTION_RETURN_INT(trans);
}

View file

@ -142,8 +142,6 @@ std2:
'true' { RET(TK_True); }
'false' { RET(TK_False); }
'none' { RET(TK_None); }
'new' { RET(TK_New); }
'instanceof' { RET(TK_InstanceOf); }
'auto' { RET(TK_Auto); }
'exec' { RET(TK_Exec); }
'property' { RET(TK_Property); }

View file

@ -81,7 +81,6 @@ xx(TK_ForEach, "'foreach'")
xx(TK_True, "'true'")
xx(TK_False, "'false'")
xx(TK_None, "'none'")
xx(TK_New, "'new'")
xx(TK_InstanceOf, "'instanceof'")
xx(TK_Auto, "'auto'")
xx(TK_Exec, "'exec'")

View file

@ -154,6 +154,7 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
{
if (ReturnProto->ReturnTypes[i] != proto->ReturnTypes[i])
{ // Incompatible
Printf("Return type %s mismatch with %s\n", ReturnProto->ReturnTypes[i]->DescriptiveName(), proto->ReturnTypes[i]->DescriptiveName());
fail = true;
break;
}
@ -2455,7 +2456,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
{
static const BYTE loadops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP };
assert(ValueType->GetRegType() == Right->ValueType->GetRegType());
assert(Base->ValueType->GetRegType() == Right->ValueType->GetRegType());
ExpEmit pointer = Base->Emit(build);
Address = pointer;
@ -2973,6 +2974,12 @@ FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
delete this;
return nullptr;
}
if (!left->ValueType || !right->ValueType)
{
ScriptPosition.Message(MSG_ERROR, "ValueType not set");
delete this;
return nullptr;
}
if (left->IsVector() || right->IsVector())
{
@ -3551,6 +3558,16 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
goto error;
}
}
else if (left->IsPointer() && static_cast<PPointer*>(left->ValueType)->PointedType == right->ValueType)
{
bool writable;
if (!right->RequestAddress(ctx, &writable)) goto error;
}
else if (right->IsPointer() && static_cast<PPointer*>(right->ValueType)->PointedType == left->ValueType)
{
bool writable;
if (!left->RequestAddress(ctx, &writable)) goto error;
}
else
{
goto error;
@ -5052,7 +5069,6 @@ FxExpression *FxNew::Resolve(FCompileContext &ctx)
ExpEmit FxNew::Emit(VMFunctionBuilder *build)
{
assert(ValueType == val->ValueType);
ExpEmit from = val->Emit(build);
from.Free(build);
ExpEmit to(build, REGT_POINTER);
@ -10150,6 +10166,8 @@ FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
ScriptPosition.Message(MSG_OPTERROR,
"Unknown class name '%s' of type '%s'",
clsname.GetChars(), desttype->TypeName.GetChars());
delete this;
return nullptr;
}
else
{

View file

@ -55,6 +55,7 @@
#include "r_sky.h"
#include "v_font.h"
#include "v_video.h"
#include "c_bind.h"
#include "menu/menu.h"
static TArray<FPropertyInfo*> properties;
@ -754,6 +755,10 @@ void InitThingdef()
sectorportalstruct->Size = sizeof(FSectorPortal);
sectorportalstruct->Align = alignof(FSectorPortal);
auto playerclassstruct = NewNativeStruct("PlayerClass", nullptr);
playerclassstruct->Size = sizeof(FPlayerClass);
playerclassstruct->Align = alignof(FPlayerClass);
// set up the lines array in the sector struct. This is a bit messy because the type system is not prepared to handle a pointer to an array of pointers to a native struct even remotely well...
// As a result, the size has to be set to something large and arbritrary because it can change between maps. This will need some serious improvement when things get cleaned up.
sectorstruct->AddNativeField("lines", NewPointer(NewResizableArray(NewPointer(linestruct, false)), false), myoffsetof(sector_t, Lines), VARF_Native);
@ -789,6 +794,16 @@ void InitThingdef()
PField *aacf = new PField("AllActorClasses", aact, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PClassActor::AllActorClasses);
Namespaces.GlobalNamespace->Symbols.AddSymbol(aacf);
auto plrcls = NewPointer(NewResizableArray(playerclassstruct), false);
PField *plrclsf = new PField("PlayerClasses", plrcls, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&PlayerClasses);
Namespaces.GlobalNamespace->Symbols.AddSymbol(plrclsf);
auto bindcls = NewNativeStruct("KeyBindings", nullptr);
PField *binding = new PField("Bindings", bindcls, VARF_Native | VARF_Static, (intptr_t)&Bindings);
Namespaces.GlobalNamespace->Symbols.AddSymbol(binding);
binding = new PField("AutomapBindings", bindcls, VARF_Native | VARF_Static, (intptr_t)&AutomapBindings);
Namespaces.GlobalNamespace->Symbols.AddSymbol(binding);
// set up a variable for the DEH data
PStruct *dstruct = NewNativeStruct("DehInfo", nullptr);
PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh);
@ -867,6 +882,9 @@ void InitThingdef()
fieldptr = new PField("CleanHeight_1", TypeSInt32, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&CleanHeight_1);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("menuactive", TypeSInt32, VARF_Native | VARF_Static, (intptr_t)&menuactive);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
fieldptr = new PField("OptionMenuSettings", NewStruct("FOptionMenuSettings", nullptr), VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&OptionSettings);
Namespaces.GlobalNamespace->Symbols.AddSymbol(fieldptr);
@ -994,7 +1012,7 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Replace)
return 0;
}
static FString FStringFormat(VM_ARGS)
FString FStringFormat(VM_ARGS)
{
assert(param[0].Type == REGT_STRING);
FString fmtstring = param[0].s().GetChars();

View file

@ -1213,6 +1213,6 @@ class PFunction;
VMFunction *FindVMFunction(PClass *cls, const char *name);
#define DECLARE_VMFUNC(cls, name) static VMFunction *name; if (name == nullptr) name = FindVMFunction(RUNTIME_CLASS(cls), #name);
FString FStringFormat(VM_ARGS);
#endif

View file

@ -785,8 +785,11 @@ begin:
OP(NEW_K):
OP(NEW):
{
PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[C] : konsta[C].v);
reg.a[B] = cls->CreateNew();
b = B;
PClass *cls = (PClass*)(pc->op == OP_NEW ? reg.a[b] : konsta[b].v);
if (cls->ObjectFlags & OF_Abstract) ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
reg.a[a] = cls->CreateNew();
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
}

View file

@ -70,8 +70,8 @@ xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string
xx(SS_R, ss, RPRSRI, NOP, 0, 0),
xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer
xx(SP_R, sp, RPRPRI, NOP, 0, 0),
xx(SO, sp, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types
xx(SO_R, sp, RPRPRI, NOP, 0, 0),
xx(SO, so, RPRPKI, SO_R, 4, REGT_INT), // store object pointer with write barrier (only needed for non thinkers and non types)
xx(SO_R, so, RPRPRI, NOP, 0, 0),
xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2
xx(SV2_R, sv2, RPRVRI, NOP, 0, 0),
xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3

View file

@ -112,7 +112,7 @@ public:
}
else
{ // Move hanging ( characters to the new line
Str.Truncate(long(Str.Len() - ConsecOpens));
Str.Truncate(Str.Len() - ConsecOpens);
NestDepth -= ConsecOpens;
}
Str << '\n';

View file

@ -12,6 +12,10 @@ static void SetNodeLine(ZCC_TreeNode *name, ZCCToken &tok)
static void SetNodeLine(ZCC_TreeNode *name, ZCC_TreeNode *node)
{
if (name == nullptr || node == nullptr)
{
I_Error("Fatal parse error");
}
name->SourceLoc = node->SourceLoc;
}

View file

@ -589,6 +589,7 @@ void ZCCCompiler::CreateClassTypes()
{
Error(c->cls, "Class name %s already exists", c->NodeName().GetChars());
}
else DPrintf(DMSG_SPAMMY, "Created class %s with parent %s\n", c->Type()->TypeName.GetChars(), c->Type()->ParentClass->TypeName.GetChars());
}
catch (CRecoverableError &err)
{
@ -597,6 +598,10 @@ void ZCCCompiler::CreateClassTypes()
c->cls->Type = nullptr;
}
}
if (c->cls->Flags & ZCC_Abstract)
{
c->Type()->ObjectFlags |= OF_Abstract;
}
if (c->Type() == nullptr) c->cls->Type = parent->FindClassTentative(c->NodeName());
c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.)
c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type());
@ -2593,7 +2598,7 @@ void ZCCCompiler::CompileStates()
statename << FName(part->Id) << '.';
part = static_cast<decltype(part)>(part->SiblingNext);
} while (part != sg->Label);
statename.Truncate((long)statename.Len() - 1); // remove the last '.' in the label name
statename.Truncate(statename.Len() - 1); // remove the last '.' in the label name
if (sg->Offset != nullptr)
{
int offset = IntConstFromNode(sg->Offset, c->Type());

View file

@ -1189,6 +1189,40 @@ int FTextureManager::CountLumpTextures (int lumpnum)
return 0;
}
//==========================================================================
//
//
//
//==========================================================================
DEFINE_ACTION_FUNCTION(_TexMan, GetSize)
{
PARAM_PROLOGUE;
PARAM_INT(texid);
auto tex = TexMan[FSetTextureID(texid)];
int x, y;
if (tex != nullptr)
{
x = tex->GetWidth();
y = tex->GetHeight();
}
else x = y = -1;
if (numret > 0) ret[0].SetInt(x);
if (numret > 1) ret[1].SetInt(x);
return MIN(numret, 2);
}
DEFINE_ACTION_FUNCTION(_TexMan, GetScaledSize)
{
PARAM_PROLOGUE;
PARAM_INT(texid);
auto tex = TexMan[FSetTextureID(texid)];
if (tex != nullptr)
{
ACTION_RETURN_VEC2(DVector2(tex->GetScaledWidthDouble(), tex->GetScaledHeightDouble()));
}
ACTION_RETURN_VEC2(DVector2(-1, -1));
}
//==========================================================================
//

View file

@ -1752,6 +1752,17 @@ void V_DrawFrame (int left, int top, int width, int height)
screen->DrawTexture (TexMan[border->br], left+width, top+height, TAG_DONE);
}
DEFINE_ACTION_FUNCTION(_Screen, DrawFrame)
{
PARAM_PROLOGUE;
PARAM_INT(x);
PARAM_INT(y);
PARAM_INT(w);
PARAM_INT(h);
V_DrawFrame(x, y, w, h);
return 0;
}
//==========================================================================
//
// V_DrawBorder

View file

@ -2741,3 +2741,8 @@ void V_ClearFonts()
SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL;
}
DEFINE_ACTION_FUNCTION(FFont, GetCursor)
{
PARAM_SELF_STRUCT_PROLOGUE(FFont);
ACTION_RETURN_STRING(FString(self->GetCursor()));
}

View file

@ -141,6 +141,8 @@ void DCanvas::DrawTextCommon(FFont *font, int normalcolor, double x, double y, c
int kerning;
FTexture *pic;
assert(string[0] != '$');
if (parms.celly == 0) parms.celly = font->GetHeight() + 1;
parms.celly *= parms.scaley;
@ -240,7 +242,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawText)
PARAM_STRING(chr);
VMVa_List args = { param + 5, 0, numparam - 5 };
const char *txt = chr[0] == '$' ? GStrings(chr) : chr.GetChars();
const char *txt = chr[0] == '$' ? GStrings(&chr[1]) : chr.GetChars();
screen->DrawText(font, cr, x, y, txt, args);
return 0;
}

View file

@ -22,7 +22,7 @@ inline unsigned GetVirtualIndex(PClass *cls, const char *funcname)
#define IFVIRTUALPTRNAME(self, cls, funcname) \
static unsigned VIndex = ~0u; \
if (VIndex == ~0u) { \
VIndex = GetVirtualIndex(PClass::FindActor(cls), #funcname); \
VIndex = GetVirtualIndex(PClass::FindClass(cls), #funcname); \
assert(VIndex != ~0u); \
} \
auto clss = self->GetClass(); \

View file

@ -368,15 +368,15 @@ FString &FString::CopyCStrPart(const char *tail, size_t tailLen)
return *this;
}
void FString::Truncate(long newlen)
void FString::Truncate(size_t newlen)
{
if (newlen <= 0)
if (newlen == 0)
{
Data()->Release();
NullString.RefCount++;
Chars = &NullString.Nothing[0];
}
else if (newlen < (long)Len())
else if (newlen < Len())
{
ReallocBuffer (newlen);
Chars[newlen] = '\0';

View file

@ -301,7 +301,7 @@ public:
bool IsEmpty() const { return Len() == 0; }
bool IsNotEmpty() const { return Len() != 0; }
void Truncate (long newlen);
void Truncate (size_t newlen);
void Remove(size_t index, size_t remlen);
int Compare (const FString &other) const { return strcmp (Chars, other.Chars); }

View file

@ -6,9 +6,17 @@
#include "zscript/actor.txt"
#include "zscript/actor_checks.txt"
#include "zscript/menu/menuitembase.txt"
#include "zscript/menu/menu.txt"
//#include "zscript/menu/menuitembase.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/playerdisplay.txt"
#include "zscript/menu/playermenu.txt"
#include "zscript/menu/textentermenu.txt"
#include "zscript/menu/videomenu.txt"
#include "zscript/inventory/inventory.txt"
#include "zscript/inventory/inv_misc.txt"

View file

@ -1,3 +1,55 @@
struct InputEvent native
{
native uint8 type;
native uint8 subtype;
native int16 data1; // keys / mouse/joystick buttons
native int16 data2;
native int16 data3;
native int x; // mouse/joystick x move
native int y; // mouse/joystick y move
enum EGenericEvent
{
NoEvent,
KeyDown, // data1: scan code, data2: Qwerty ASCII code
KeyUp, // same
Mouse, // x, y: mouse movement deltas
GUI_Event, // subtype specifies actual event
DeviceChange,// a device has been connected or removed
}
enum EGUIEvent
{
GUI_None,
GUI_KeyDown, // data1: unshifted ASCII, data2: shifted ASCII, data3: modifiers
GUI_KeyRepeat, // same
GUI_KeyUp, // same
GUI_Char, // data1: translated character (for user text input), data2: alt down?
GUI_FirstMouseEvent,
GUI_MouseMove,
GUI_LButtonDown,
GUI_LButtonUp,
GUI_LButtonDblClick,
GUI_MButtonDown,
GUI_MButtonUp,
GUI_MButtonDblClick,
GUI_RButtonDown,
GUI_RButtonUp,
GUI_RButtonDblClick,
GUI_WheelUp, // data3: shift/ctrl/alt
GUI_WheelDown, // "
GUI_WheelRight, // "
GUI_WheelLeft, // "
GUI_BackButtonDown,
GUI_BackButtonUp,
GUI_FwdButtonDown,
GUI_FwdButtonUp,
GUI_LastMouseEvent,
};
const KEY_ESCAPE = 0x01;
}
struct TexMan
{
enum EUseTypes
@ -42,6 +94,8 @@ struct TexMan
native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny);
native static void ReplaceTextures(String from, String to, int flags);
native static int, int GetSize(TextureID tex);
native static Vector2 GetScaledSize(TextureID tex);
}
enum DrawTextureTags
@ -118,7 +172,7 @@ struct Screen native
native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...);
native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...);
native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
native static void DrawFrame(int x, int y, int w, int h);
}
class BrokenLines : Object native
@ -158,10 +212,42 @@ struct Font native
CR_CYAN,
NUM_TEXT_COLORS
};
const TEXTCOLOR_BRICK = "\034A";
const TEXTCOLOR_TAN = "\034B";
const TEXTCOLOR_GRAY = "\034C";
const TEXTCOLOR_GREY = "\034C";
const TEXTCOLOR_GREEN = "\034D";
const TEXTCOLOR_BROWN = "\034E";
const TEXTCOLOR_GOLD = "\034F";
const TEXTCOLOR_RED = "\034G";
const TEXTCOLOR_BLUE = "\034H";
const TEXTCOLOR_ORANGE = "\034I";
const TEXTCOLOR_WHITE = "\034J";
const TEXTCOLOR_YELLOW = "\034K";
const TEXTCOLOR_UNTRANSLATED = "\034L";
const TEXTCOLOR_BLACK = "\034M";
const TEXTCOLOR_LIGHTBLUE = "\034N";
const TEXTCOLOR_CREAM = "\034O";
const TEXTCOLOR_OLIVE = "\034P";
const TEXTCOLOR_DARKGREEN = "\034Q";
const TEXTCOLOR_DARKRED = "\034R";
const TEXTCOLOR_DARKBROWN = "\034S";
const TEXTCOLOR_PURPLE = "\034T";
const TEXTCOLOR_DARKGRAY = "\034U";
const TEXTCOLOR_CYAN = "\034V";
const TEXTCOLOR_NORMAL = "\034-";
const TEXTCOLOR_BOLD = "\034+";
const TEXTCOLOR_CHAT = "\034*";
const TEXTCOLOR_TEAMCHAT = "\034!";
native int GetCharWidth(int code);
native int StringWidth(String code);
native int GetHeight();
native String GetCursor();
native static int FindFontColor(Name color);
native static Font FindFont(Name fontname);
@ -169,10 +255,24 @@ struct Font native
native static BrokenLines BreakLines(String text, int maxlen);
}
struct Translation
{
Color colors[256];
native int AddTranslation();
native static bool SetPlayerTranslation(int group, int num, int plrnum, PlayerClass pclass);
static int MakeID(int group, int num)
{
return (group << 16) + num;
}
}
struct Console native
{
native static void HideConsole();
native static void MidPrint(Font fontname, string textlabel, bool bold = false);
native static vararg void Printf(string fmt, ...);
native static void DoCommand(String cmd);
}
struct DamageTypeDefinition native
@ -182,9 +282,24 @@ struct DamageTypeDefinition native
struct CVar native
{
enum ECVarType
{
CVAR_Bool,
CVAR_Int,
CVAR_Float,
CVAR_String,
CVAR_Color,
};
native static CVar FindCVar(Name name);
native int GetInt();
native double GetFloat();
native String GetString();
native void SetInt(int v);
native void SetFloat(double v);
native void SetString(String s);
native int GetRealType();
native int ResetToDefault();
}
struct GameInfoStruct native
@ -347,7 +462,7 @@ struct LevelLocals native
struct StringTable native
{
native static String Localize(String val, bool prefixed = false);
native static String Localize(String val, bool prefixed = true);
}
// a few values of this need to be readable by the play code.
@ -382,6 +497,7 @@ struct State native
native int DistanceTo(state other);
native bool ValidateSpriteFrame();
native TextureID, bool, Vector2 GetSpriteTexture(int rotation, int skin = 0, Vector2 scale = (0,0));
}
struct F3DFloor native
@ -476,7 +592,7 @@ class Floor : Thinker native
floorRaiseInstant,
floorMoveToValue,
floorRaiseToLowestCeiling,
floorRaiseByTexture,
floorRaiseuint8xture,
floorLowerAndChange,
floorRaiseAndChange,
@ -484,7 +600,7 @@ class Floor : Thinker native
floorRaiseToLowest,
floorRaiseToCeiling,
floorLowerToLowestCeiling,
floorLowerByTexture,
floorLoweruint8xture,
floorLowerToCeiling,
donutRaise,
@ -493,7 +609,7 @@ class Floor : Thinker native
waitStair,
resetStair,
// Not to be used as parameters to EV_DoFloor()
// Not to be used as parameters to DoFloor()
genFloorChg0,
genFloorChgT,
genFloorChg
@ -527,8 +643,8 @@ class Ceiling : Thinker native
ceilLowerToNearest,
ceilRaiseToHighestFloor,
ceilRaiseToFloor,
ceilRaiseByTexture,
ceilLowerByTexture,
ceilRaiseuint8xture,
ceilLoweruint8xture,
genCeilingChg0,
genCeilingChgT,

View file

@ -1,6 +1,7 @@
// for flag changer functions.
const FLAG_NO_CHANGE = -1;
const MAXPLAYERS = 8;
const MAXPLAYERNAME = 15;
enum EStateUseFlags
{

View file

@ -32,18 +32,93 @@
**
*/
class ColorpickerMenu : Menu native
//=============================================================================
//
// This is only used by the color picker
//
//=============================================================================
class OptionMenuSliderVar : OptionMenuSliderBase
{
native float mRed;
native float mGreen;
native float mBlue;
int mIndex;
native int mGridPosX;
native int mGridPosY;
OptionMenuSliderVar Init(String label, int index, double min, double max, double step, int showval)
{
Super.Init(label, min, max, step, showval);
mIndex = index;
return self;
}
native int mStartItem;
override double GetSliderValue()
{
return ColorpickerMenu(Menu.GetCurrentMenu()).GetColor(mIndex);
}
native CVar mCVar;
override void SetSliderValue(double val)
{
ColorpickerMenu(Menu.GetCurrentMenu()).setColor(mIndex, val);
}
}
class ColorpickerMenu : OptionMenu
{
float mRed;
float mGreen;
float mBlue;
int mGridPosX;
int mGridPosY;
int mStartItem;
CVar mCVar;
double GetColor(int index)
{
double v = index == 0? mRed : index == 1? mGreen : mBlue;
return v;
}
void SetColor(int index, double val)
{
if (index == 0) mRed = val;
else if (index == 1) mGreen = val;
else mBlue = val;
}
//=============================================================================
//
//
//
//=============================================================================
void Init(Menu parent, String name, OptionMenuDescriptor desc, CVar cv)
{
Super.Init(parent, desc);
mStartItem = mDesc.mItems.Size();
mCVar = cv;
ResetColor();
mGridPosX = 0;
mGridPosY = 0;
// This menu uses some features that are hard to implement in an external control lump
// so it creates its own list of menu items.
mDesc.mItems.Resize(mStartItem+8);
mDesc.mItems[mStartItem+0] = new ("OptionMenuItemStaticText").Init(name, false);
mDesc.mItems[mStartItem+1] = new ("OptionMenuItemStaticText").Init(" ", false);
mDesc.mItems[mStartItem+2] = new ("OptionMenuSliderVar").Init("Red", 0, 0, 255, 15, 0);
mDesc.mItems[mStartItem+3] = new ("OptionMenuSliderVar").Init("Green", 1, 0, 255, 15, 0);
mDesc.mItems[mStartItem+4] = new ("OptionMenuSliderVar").Init("Blue", 2, 0, 255, 15, 0);
mDesc.mItems[mStartItem+5] = new ("OptionMenuItemStaticText").Init(" ", false);
mDesc.mItems[mStartItem+6] = new ("OptionMenuItemCommand").Init("Undo changes", "undocolorpic");
mDesc.mItems[mStartItem+7] = new ("OptionMenuItemStaticText").Init(" ", false);
mDesc.mSelectedItem = mStartItem + 2;
mDesc.mIndent = 0;
mDesc.CalcIndent();
}
//=============================================================================
//
@ -256,5 +331,24 @@ class ColorpickerMenu : Menu native
screen.DrawText (SmallFont, Font.CR_WHITE, x+(48+24-SmallFont.StringWidth("New")/2)*CleanXfac_1, y, "New", DTA_CleanNoMove_1, true);
}
override void OnDestroy()
{
if (mStartItem >= 0)
{
mDesc.mItems.Resize(mStartItem);
if (mCVar != null) mCVar.SetInt(Color(int(mRed), int(mGreen), int(mBlue)));
mStartItem = -1;
}
}
override void ResetColor()
{
if (mCVar != null)
{
Color clr = Color(mCVar.GetInt());
mRed = clr.r;
mGreen = clr.g;
mBlue = clr.b;
}
}
}

View file

@ -0,0 +1,225 @@
/*
** joystickmenu.cpp
** The joystick configuration menus
**
**---------------------------------------------------------------------------
** 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 OptionMenuSliderJoySensitivity : OptionMenuSliderBase
{
void Init(String label, double min, double max, double step, int showval)
{
Super.Init(label, min, max, step, showval);
}
override double GetSliderValue()
{
return Menu.GetCurrentJoystickConfig().GetSensitivity();
}
override void SetSliderValue(double val)
{
Menu.GetCurrentJoystickConfig().SetSensitivity(val);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuSliderJoyScale : OptionMenuSliderBase
{
int mAxis;
int mNeg;
void Init(String label, int axis, double min, double max, double step, int showval)
{
Super.Init(label, min, max, step, showval);
mAxis = axis;
mNeg = 1;
}
override double GetSliderValue()
{
double d = Menu.GetCurrentJoystickConfig().GetAxisScale(mAxis);
mNeg = d < 0? -1:1;
return d;
}
override void SetSliderValue(double val)
{
Menu.GetCurrentJoystickConfig().SetAxisScale(mAxis, val * mNeg);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuSliderJoyDeadZone : OptionMenuSliderBase
{
int mAxis;
int mNeg;
void Init(String label, int axis, double min, double max, double step, int showval)
{
Super.Init(label, min, max, step, showval);
mAxis = axis;
mNeg = 1;
}
override double GetSliderValue()
{
double d = Menu.GetCurrentJoystickConfig().GetAxisDeadZone(mAxis);
mNeg = d < 0? -1:1;
return d;
}
override void SetSliderValue(double val)
{
Menu.GetCurrentJoystickConfig().SetAxisDeadZone(mAxis, val * mNeg);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemJoyMap : OptionMenuItemOptionBase
{
int mAxis;
void Init(String label, int axis, Name values, int center)
{
Super.Init(label, 'none', values, null, center);
mAxis = axis;
}
override int GetSelection()
{
double f = Menu.GetCurrentJoystickConfig().GetAxisMap(mAxis);
let opt = OptionValues.GetCount(mValues);
if (opt > 0)
{
// Map from joystick axis to menu selection.
for(int i = 0; i < opt; i++)
{
if (f ~== OptionValues.GetValue(mValues, i))
{
return i;
}
}
}
return -1;
}
override void SetSelection(int selection)
{
let opt = OptionValues.GetCount(mValues);
// Map from menu selection to joystick axis.
if (opt == 0 || selection >= opt)
{
selection = JoystickConfig.JOYAXIS_None;
}
else
{
selection = int(OptionValues.GetValue(mValues, selection));
}
Menu.GetCurrentJoystickConfig().SetAxisMap(mAxis, selection);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemInverter : OptionMenuItemOptionBase
{
int mAxis;
void Init(String label, int axis, int center)
{
Super.Init(label, "none", "YesNo", NULL, center);
mAxis = axis;
}
override int GetSelection()
{
float f = Menu.GetCurrentJoystickConfig().GetAxisScale(mAxis);
return f > 0? 0:1;
}
override void SetSelection(int Selection)
{
let f = abs(Menu.GetCurrentJoystickConfig().GetAxisScale(mAxis));
if (Selection) f*=-1;
Menu.GetCurrentJoystickConfig().SetAxisScale(mAxis, f);
}
}
//=============================================================================
//
// Executes a CCMD, action is a CCMD name
//
//=============================================================================
class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu
{
JoystickConfig mJoy;
void Init(String label = "", JoystickConfig joy = null)
{
Super.Init(label, "JoystickConfigMenu");
mJoy = joy;
}
override bool Activate()
{
//UpdateJoystickConfigMenu(mJoy);
return Super.Activate();
}
}

View file

@ -0,0 +1,309 @@
/*
** listmenu.cpp
** A simple menu consisting of a list of items
**
**---------------------------------------------------------------------------
** 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 ListMenuItem : MenuItemBase
{
void DrawSelector(int xofs, int yofs, TextureID tex)
{
if (tex.isNull())
{
if ((Menu.MenuTime() % 8) < 6)
{
screen.DrawText(ConFont, OptionMenuSettings.mFontColorSelection,
(mXpos + xofs - 160) * CleanXfac + screen.GetWidth() / 2,
(mYpos + yofs - 100) * CleanYfac + screen.GetHeight() / 2,
"\xd",
DTA_CellX, 8 * CleanXfac,
DTA_CellY, 8 * CleanYfac
);
}
}
else
{
screen.DrawTexture (tex, mXpos + xofs, mYpos + yofs, DTA_Clean, true);
}
}
}
//=============================================================================
//
// static patch
//
//=============================================================================
class ListMenuItemStaticPatch : ListMenuItem
{
TextureID mTexture;
bool mCentered;
void Init(int x, int y, TextureID patch, bool centered = false)
{
Super.Init(x, y);
mTexture = patch;
mCentered = centered;
}
override void Drawer(bool selected)
{
if (!mTexture.Exists())
{
return;
}
int x = mXpos;
Vector2 vec = TexMan.GetScaledSize(mTexture);
if (mYpos >= 0)
{
if (mCentered) x -= int(vec.X) / 2;
screen.DrawTexture (mTexture, true, x, mYpos, DTA_Clean, true);
}
else
{
int x = (mXpos - 160) * CleanXfac + (Screen.GetWidth()>>1);
if (mCentered) x -= (int(vec.X) * CleanXfac)/2;
screen.DrawTexture (mTexture, true, x, -mYpos*CleanYfac, DTA_CleanNoMove, true);
}
}
}
class ListMenuItemStaticPatchCentered : ListMenuItemStaticPatch
{
void Init(int x, int y, TextureID patch)
{
Super.Init(x, y, patch, true);
}
}
//=============================================================================
//
// static text
//
//=============================================================================
class ListMenuItemStaticText : ListMenuItem
{
String mText;
Font mFont;
int mColor;
bool mCentered;
void Init(ListMenuDescriptor desc, int x, int y, String text, int color = Font.CR_UNTRANSLATED)
{
Super.Init(x, y);
mText = text;
mFont = desc.mFont;
mColor = color >= 0? color : desc.mFontColor;
mCentered = false;
}
void InitDirect(int x, int y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false)
{
Super.Init(x, y);
mText = text;
mFont = font;
mColor = color;
mCentered = centered;
}
override void Drawer(bool selected)
{
if (mText.Length() != 0)
{
String text = Stringtable.Localize(mText);
if (mYpos >= 0)
{
int x = mXpos;
if (mCentered) x -= mFont.StringWidth(text)/2;
screen.DrawText(mFont, mColor, x, mYpos, text, DTA_Clean, true);
}
else
{
int x = (mXpos - 160) * CleanXfac + (Screen.GetWidth() >> 1);
if (mCentered) x -= (mFont.StringWidth(text) * CleanXfac)/2;
screen.DrawText (mFont, mColor, x, -mYpos*CleanYfac, text, DTA_CleanNoMove, true);
}
}
}
}
class ListMenuItemStaticTextCentered : ListMenuItemStaticText
{
void Init(ListMenuDescriptor desc, int x, int y, String text, int color = -1)
{
Super.Init(desc, x, y, text, color);
mCentered = true;
}
}
//=============================================================================
//
// selectable items
//
//=============================================================================
class ListMenuItemSelectable : ListMenuItem
{
int mHotkey;
int mHeight;
int mParam;
protected void Init(int x, int y, int height, Name childmenu, int param = -1)
{
Super.Init(x, y, childmenu);
mHeight = height;
mParam = param;
mHotkey = 0;
}
override bool CheckCoordinate(int x, int y)
{
return mEnabled && y >= mYpos && y < mYpos + mHeight; // no x check here
}
override bool Selectable()
{
return mEnabled;
}
override bool CheckHotkey(int c)
{
return c == mHotkey;
}
override bool Activate()
{
Menu.SetMenu(mAction, mParam);
return true;
}
override bool MouseEvent(int type, int x, int y)
{
if (type == Menu.MOUSE_Release)
{
let m = Menu.GetCurrentMenu();
if (m != NULL && m.MenuEvent(Menu.MKEY_Enter, true))
{
return true;
}
}
return false;
}
override Name, int GetAction()
{
return mAction, mParam;
}
}
//=============================================================================
//
// text item
//
//=============================================================================
class ListMenuItemTextItem : ListMenuItemSelectable
{
String mText;
Font mFont;
int mColor;
int mColorSelected;
void Init(ListMenuDescriptor desc, String text, String hotkey, Name child, int param = 0)
{
Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param);
mText = text;
mFont = desc.mFont;
mColor = desc.mFontColor;
mColorSelected = desc.mFontcolor2;
mHotkey = hotkey.CharCodeAt(0);
}
void InitDirect(int x, int y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0)
{
Super.Init(x, y, height, child, param);
mText = text;
mFont = font;
mColor = color;
mColorSelected = color2;
mHotkey = hotkey.CharCodeAt(0);
}
override void Drawer(bool selected)
{
screen.DrawText(mFont, selected ? mColorSelected : mColor, mXpos, mYpos, mText, DTA_Clean, true);
}
override int GetWidth()
{
return min(1, mFont.StringWidth(StringTable.Localize(mText)));
}
}
//=============================================================================
//
// patch item
//
//=============================================================================
class ListMenuItemPatchItem : ListMenuItemSelectable
{
TextureID mTexture;
void Init(ListMenuDescriptor desc, TextureID patch, String hotkey, Name child, int param = 0)
{
Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param);
mHotkey = hotkey.CharCodeAt(0);
mTexture = patch;
}
void InitDirect(int x, int y, int height, TextureID patch, String hotkey, Name child, int param = 0)
{
Super.Init(x, y, height, child, param);
mHotkey = hotkey.CharCodeAt(0);
mTexture = patch;
}
override void Drawer(bool selected)
{
screen.DrawTexture (mTexture, true, mXpos, mYpos, DTA_Clean, true);
}
override int GetWidth()
{
return TexMan.GetSize(mTexture);
}
}

View file

@ -1,4 +1,48 @@
struct KeyBindings native
{
native static String NameKeys(int k1, int k2);
native int, int GetKeysForCommand(String cmd);
native void SetBind(int key, String cmd);
native void UnbindACommand (String str);
}
struct OptionValues native
{
native static int GetCount(Name group);
native static String GetText(Name group, int index);
native static double GetValue(Name group, int index);
native static String GetTextValue(Name group, int index);
}
struct JoystickConfig native
{
enum EJoyAxis
{
JOYAXIS_None = -1,
JOYAXIS_Yaw,
JOYAXIS_Pitch,
JOYAXIS_Forward,
JOYAXIS_Side,
JOYAXIS_Up,
// JOYAXIS_Roll, // Ha ha. No roll for you.
NUM_JOYAXIS,
};
native float GetSensitivity();
native void SetSensitivity(float scale);
native float GetAxisScale(int axis);
native void SetAxisScale(int axis, float scale);
native float GetAxisDeadZone(int axis);
native void SetAxisDeadZone(int axis, float zone);
native int GetAxisMap(int axis);
native void SetAxisMap(int axis, int gameaxis);
}
class Menu : Object native
{
enum EMenuKey
@ -29,17 +73,53 @@ class Menu : Object native
MOUSE_Release
};
//native static int MenuTime();
enum EMenuState
{
Off, // Menu is closed
On, // Menu is opened
WaitKey, // Menu is opened and waiting for a key in the controls menu
OnNoPause, // Menu is opened but does not pause the game
};
native Menu mParentMenu;
void Init(Menu parent)
{
mParentMenu = parent;
}
native static int MenuTime();
native static void SetVideoMode();
native static Menu GetCurrentMenu();
native static JoystickConfig GetCurrentJoystickConfig();
native static void SetMenu(Name mnu, int param = 0);
native static void StartMessage(String msg, int mode = 0, Name command = 'none');
virtual bool TranslateKeyboardEvents() { return true; }
virtual void SetFocus(MenuItemBase fc) {}
virtual bool CheckFocus(MenuItemBase fc) { return false; }
virtual void ReleaseFocus() {}
virtual void ResetColor() {}
native virtual bool Responder(InputEvent ev);
native virtual bool MenuEvent (int mkey, bool fromcontroller);
native virtual bool MouseEvent(int type, int mx, int my);
native virtual void Ticker();
native virtual void Drawer();
native void Close();
native MenuItemBase GetItem(Name n);
native void ActivateMenu();
void MenuSound(Sound snd)
static void MenuSound(Sound snd)
{
S_Sound (snd, CHAN_VOICE | CHAN_UI, snd_menuvolume, ATTN_NONE);
}
static void DrawConText (int color, int x, int y, String str)
{
screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 8 * CleanXfac_1, DTA_CellY, 8 * CleanYfac_1);
}
}
class MenuDescriptor : Object native
@ -47,17 +127,42 @@ class MenuDescriptor : Object native
native Name mMenuName;
native String mNetgameMessage;
native Class<Menu> mClass;
native static MenuDescriptor GetDescriptor(Name n);
}
class MenuItemBase : object native
class ListMenuDescriptor : MenuDescriptor native
{
native Array<ListMenuItem> mItems;
native int mSelectedItem;
native int mSelectOfsX;
native int mSelectOfsY;
native TextureID mSelector;
native int mDisplayTop;
native int mXpos, mYpos;
native Name mAction;
native bool mEnabled;
// making this virtual now would require exporting all classes at once.
native /*virtual*/ bool MenuEvent (int mkey, bool fromcontroller);
native int mWLeft, mWRight;
native int mLinespacing; // needs to be stored for dynamically created menus
native int mAutoselect; // this can only be set by internal menu creation functions
native Font mFont;
native int mFontColor;
native int mFontColor2;
native bool mCenter;
void Reset()
{
// Reset the default settings (ignore all other values in the struct)
mSelectOfsX = 0;
mSelectOfsY = 0;
mSelector.SetInvalid();
mDisplayTop = 0;
mXpos = 0;
mYpos = 0;
mLinespacing = 0;
mNetgameMessage = "";
mFont = NULL;
mFontColor = Font.CR_UNTRANSLATED;
mFontColor2 = Font.CR_UNTRANSLATED;
}
}
struct FOptionMenuSettings
@ -84,7 +189,7 @@ class OptionMenuDescriptor : MenuDescriptor native
native int mPosition;
native bool mDontDim;
//native void CalcIndent();
native void CalcIndent();
//native OptionMenuItem GetItem(Name iname);
void Reset()
{
@ -96,20 +201,3 @@ class OptionMenuDescriptor : MenuDescriptor native
}
}
class OptionMenuItem : MenuItemBase native
{
native String mLabel;
native bool mCentered;
//native void drawLabel(int indent, int y, EColorRange color, bool grayed = false);
}
class OptionMenu : Menu native
{
native bool CanScrollUp;
native bool CanScrollDown;
native int VisBottom;
native OptionMenuItem mFocusControl;
native OptionMenuDescriptor mDesc;
}

View file

@ -6,12 +6,11 @@
class MenuItemBase : Object native
{
protected int mXpos, mYpos;
protected Name mAction;
protected native int mXpos, mYpos;
protected native Name mAction;
native bool mEnabled;
bool mEnabled;
protected void Init(int xpos = 0, int ypos = 0, Name actionname = 'None')
void Init(int xpos = 0, int ypos = 0, Name actionname = 'None')
{
mXpos = xpos;
mYpos = ypos;
@ -34,33 +33,17 @@ class MenuItemBase : Object native
virtual bool MouseEvent(int type, int x, int y) { return false; }
virtual bool CheckHotkey(int c) { return false; }
virtual int GetWidth() { return 0; }
virtual void OffsetPositionY(int ydelta) { mYpos += ydelta; }
virtual int GetY() { return mYpos; }
virtual int GetX() { return mXpos; }
virtual void SetX(int x) { mXpos = x; }
/*
virtual void DrawSelector(int xofs, int yofs, TextureID tex)
{
if (tex.isNull())
{
if ((Menu.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 (tex, mXpos + xofs, mYpos + yofs, DTA_Clean, true, TAG_DONE);
}
}
*/
virtual int GetIndent() { return 0; }
virtual int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { return indent; }
void OffsetPositionY(int ydelta) { mYpos += ydelta; }
int GetY() { return mYpos; }
int GetX() { return mXpos; }
void SetX(int x) { mXpos = x; }
}
// this is only used to parse font color ranges in MENUDEF
enum MenudefColorRange
{
NO_COLOR = -1
}

View file

@ -0,0 +1,469 @@
/*
** optionmenu.cpp
** Handler class for the option menus and associated items
**
**---------------------------------------------------------------------------
** 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 OptionMenu : Menu
{
OptionMenuDescriptor mDesc;
bool CanScrollUp;
bool CanScrollDown;
int VisBottom;
OptionMenuItem mFocusControl;
//=============================================================================
//
//
//
//=============================================================================
virtual void Init(Menu parent, OptionMenuDescriptor desc)
{
mParentMenu = parent;
mDesc = desc;
if (mDesc != NULL && mDesc.mSelectedItem == -1) mDesc.mSelectedItem = FirstSelectable();
}
//=============================================================================
//
//
//
//=============================================================================
int FirstSelectable()
{
if (mDesc != NULL)
{
// Go down to the first selectable item
int i = -1;
do
{
i++;
}
while (i < mDesc.mItems.Size() && !mDesc.mItems[i].Selectable());
if (i>=0 && i < mDesc.mItems.Size()) return i;
}
return -1;
}
//=============================================================================
//
//
//
//=============================================================================
override bool Responder (InputEvent ev)
{
if (ev.type == InputEvent.GUI_Event)
{
if (ev.subtype == InputEvent.GUI_WheelUp)
{
int scrollamt = MIN(2, mDesc.mScrollPos);
mDesc.mScrollPos -= scrollamt;
return true;
}
else if (ev.subtype == InputEvent.GUI_WheelDown)
{
if (CanScrollDown)
{
if (VisBottom >= 0 && VisBottom < (mDesc.mItems.Size()-2))
{
mDesc.mScrollPos += 2;
VisBottom += 2;
}
else
{
mDesc.mScrollPos++;
VisBottom++;
}
}
return true;
}
}
return Super.Responder(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
int startedAt = mDesc.mSelectedItem;
switch (mkey)
{
case MKEY_Up:
if (mDesc.mSelectedItem == -1)
{
mDesc.mSelectedItem = FirstSelectable();
break;
}
do
{
--mDesc.mSelectedItem;
if (mDesc.mScrollPos > 0 &&
mDesc.mSelectedItem <= mDesc.mScrollTop + mDesc.mScrollPos)
{
mDesc.mScrollPos = MAX(mDesc.mSelectedItem - mDesc.mScrollTop - 1, 0);
}
if (mDesc.mSelectedItem < 0)
{
// Figure out how many lines of text fit on the menu
int y = mDesc.mPosition;
if (y <= 0)
{
if (BigFont && mDesc.mTitle.Length() > 0)
{
y = -y + BigFont.GetHeight();
}
else
{
y = -y;
}
}
y *= CleanYfac_1;
int rowheight = OptionMenuSettings.mLinespacing * CleanYfac_1;
int maxitems = (screen.GetHeight() - rowheight - y) / rowheight + 1;
mDesc.mScrollPos = MAX (0, mDesc.mItems.Size() - maxitems + mDesc.mScrollTop);
mDesc.mSelectedItem = mDesc.mItems.Size()-1;
}
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
break;
case MKEY_Down:
if (mDesc.mSelectedItem == -1)
{
mDesc.mSelectedItem = FirstSelectable();
break;
}
do
{
++mDesc.mSelectedItem;
if (CanScrollDown && mDesc.mSelectedItem == VisBottom)
{
mDesc.mScrollPos++;
VisBottom++;
}
if (mDesc.mSelectedItem >= mDesc.mItems.Size())
{
if (startedAt == -1)
{
mDesc.mSelectedItem = -1;
mDesc.mScrollPos = -1;
break;
}
else
{
mDesc.mSelectedItem = 0;
mDesc.mScrollPos = 0;
}
}
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
break;
case MKEY_PageUp:
if (mDesc.mScrollPos > 0)
{
mDesc.mScrollPos -= VisBottom - mDesc.mScrollPos - mDesc.mScrollTop;
if (mDesc.mScrollPos < 0)
{
mDesc.mScrollPos = 0;
}
if (mDesc.mSelectedItem != -1)
{
mDesc.mSelectedItem = mDesc.mScrollTop + mDesc.mScrollPos + 1;
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable())
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size())
{
mDesc.mSelectedItem = 0;
}
}
if (mDesc.mScrollPos > mDesc.mSelectedItem)
{
mDesc.mScrollPos = mDesc.mSelectedItem;
}
}
}
break;
case MKEY_PageDown:
if (CanScrollDown)
{
int pagesize = VisBottom - mDesc.mScrollPos - mDesc.mScrollTop;
mDesc.mScrollPos += pagesize;
if (mDesc.mScrollPos + mDesc.mScrollTop + pagesize > mDesc.mItems.Size())
{
mDesc.mScrollPos = mDesc.mItems.Size() - mDesc.mScrollTop - pagesize;
}
if (mDesc.mSelectedItem != -1)
{
mDesc.mSelectedItem = mDesc.mScrollTop + mDesc.mScrollPos;
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable())
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size())
{
mDesc.mSelectedItem = 0;
}
}
if (mDesc.mScrollPos > mDesc.mSelectedItem)
{
mDesc.mScrollPos = mDesc.mSelectedItem;
}
}
}
break;
case MKEY_Enter:
if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate())
{
return true;
}
// fall through to default
default:
if (mDesc.mSelectedItem >= 0 &&
mDesc.mItems[mDesc.mSelectedItem].MenuEvent(mkey, fromcontroller)) return true;
return Super.MenuEvent(mkey, fromcontroller);
}
if (mDesc.mSelectedItem != startedAt)
{
MenuSound ("menu/cursor");
}
return true;
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
y = (y / CleanYfac_1) - mDesc.mDrawTop;
if (mFocusControl)
{
mFocusControl.MouseEvent(type, x, y);
return true;
}
else
{
int yline = (y / OptionMenuSettings.mLinespacing);
if (yline >= mDesc.mScrollTop)
{
yline += mDesc.mScrollPos;
}
if (yline >= 0 && yline < mDesc.mItems.Size() && mDesc.mItems[yline].Selectable())
{
if (yline != mDesc.mSelectedItem)
{
mDesc.mSelectedItem = yline;
//S_Sound (CHAN_VOICE | CHAN_UI, "menu/cursor", snd_menuvolume, ATTN_NONE);
}
mDesc.mItems[yline].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 ()
{
int y = mDesc.mPosition;
if (y <= 0)
{
if (BigFont && mDesc.mTitle.Length() > 0)
{
let tt = Stringtable.Localize(mDesc.mTitle);
screen.DrawText (BigFont, OptionMenuSettings.mTitleColor,
(screen.GetWidth() - BigFont.StringWidth(tt) * CleanXfac_1) / 2, 10*CleanYfac_1,
tt, DTA_CleanNoMove_1, true);
y = -y + BigFont.GetHeight();
}
else
{
y = -y;
}
}
mDesc.mDrawTop = y;
int fontheight = OptionMenuSettings.mLinespacing * CleanYfac_1;
y *= CleanYfac_1;
int indent = mDesc.mIndent;
if (indent > 280)
{ // kludge for the compatibility options with their extremely long labels
if (indent + 40 <= CleanWidth_1)
{
indent = (screen.GetWidth() - ((indent + 40) * CleanXfac_1)) / 2 + indent * CleanXfac_1;
}
else
{
indent = screen.GetWidth() - 40 * CleanXfac_1;
}
}
else
{
indent = (indent - 160) * CleanXfac_1 + screen.GetWidth() / 2;
}
int ytop = y + mDesc.mScrollTop * 8 * CleanYfac_1;
int lastrow = screen.GetHeight() - SmallFont.GetHeight() * CleanYfac_1;
int i;
for (i = 0; i < mDesc.mItems.Size() && y <= lastrow; i++)
{
// Don't scroll the uppermost items
if (i == mDesc.mScrollTop)
{
i += mDesc.mScrollPos;
if (i >= mDesc.mItems.Size()) break; // skipped beyond end of menu
}
bool isSelected = mDesc.mSelectedItem == i;
int cur_indent = mDesc.mItems[i].Draw(mDesc, y, indent, isSelected);
if (cur_indent >= 0 && isSelected && mDesc.mItems[i].Selectable())
{
if (((MenuTime() % 8) < 6) || GetCurrentMenu() != self)
{
DrawConText(OptionMenuSettings.mFontColorSelection, cur_indent + 3 * CleanXfac_1, y+fontheight-9*CleanYfac_1, "\xd");
}
}
y += fontheight;
}
CanScrollUp = (mDesc.mScrollPos > 0);
CanScrollDown = (i < mDesc.mItems.Size());
VisBottom = i - 1;
if (CanScrollUp)
{
DrawConText(Font.CR_ORANGE, 3 * CleanXfac_1, ytop, "\x1a");
}
if (CanScrollDown)
{
DrawConText(Font.CR_ORANGE, 3 * CleanXfac_1, y - 8*CleanYfac_1, "\x1b");
}
Super.Drawer();
}
//=============================================================================
//
//
//
//=============================================================================
override void SetFocus(MenuItemBase fc)
{
mFocusControl = OptionMenuItem(fc);
}
override bool CheckFocus(MenuItemBase fc)
{
return mFocusControl == fc;
}
override void ReleaseFocus()
{
mFocusControl = NULL;
}
}
class GameplayMenu : OptionMenu
{
override void Drawer ()
{
Super.Drawer();
String s = String.Format("dmflags = %d dmflags2 = %d", dmflags, dmflags2);
screen.DrawText (SmallFont, OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - SmallFont.StringWidth (s) * CleanXfac_1) / 2, 0, s,
DTA_CleanNoMove_1, true);
}
}
class CompatibilityMenu : OptionMenu
{
override void Drawer ()
{
Super.Drawer();
String s = String.Format("compatflags = %d compatflags2 = %d", compatflags, compatflags2);
screen.DrawText (SmallFont, OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - SmallFont.StringWidth (s) * CleanXfac_1) / 2, 0, s,
DTA_CleanNoMove_1, true);
}
}
class JoystickConfigMenu : OptionMenu
{
// This is not really needed anymore but needs to be kept for old MENUDEFs that keep the entry
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,290 @@
/*
** playerdisplay.cpp
** The player display for the player setup and class selection screen
**
**---------------------------------------------------------------------------
** 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.
**---------------------------------------------------------------------------
**
*/
//=============================================================================
//
// the player sprite window
//
//=============================================================================
class ListMenuItemPlayerDisplay : ListMenuItem
{
ListMenuDescriptor mOwner;
TextureID mBackdrop;
PlayerClass mPlayerClass;
State mPlayerState;
int mPlayerTics;
bool mNoportrait;
int8 mRotation;
int8 mMode; // 0: automatic (used by class selection), 1: manual (used by player setup)
int8 mTranslate;
int mSkin;
int mRandomClass;
int mRandomTimer;
int mClassNum;
int mTranslation;
enum EPDFlags
{
PDF_ROTATION = 0x10001,
PDF_SKIN = 0x10002,
PDF_CLASS = 0x10003,
PDF_MODE = 0x10004,
PDF_TRANSLATE = 0x10005,
};
//=============================================================================
//
//
//
//=============================================================================
void Init(ListMenuDescriptor menu, int x, int y, Color c1, Color c2, bool np = false, Name command = 'None' )
{
Super.Init(x, y, command);
mOwner = menu;
Translation trans;
for (int i = 0; i < 256; i++)
{
int r = c1.r + c2.r * i / 255;
int g = c1.g + c2.g * i / 255;
int b = c1.b + c2.b * i / 255;
trans.colors[i] = Color(255, r, g, b);
}
mTranslation = trans.AddTranslation();
mBackdrop = TexMan.CheckForTexture("PlayerBackdrop", TexMan.Type_MiscPatch);
mPlayerClass = NULL;
mPlayerState = NULL;
mNoportrait = np;
mMode = 0;
mRotation = 0;
mTranslate = false;
mSkin = 0;
mRandomClass = 0;
mRandomTimer = 0;
mClassNum = -1;
}
private void UpdatePlayer(int classnum)
{
mPlayerClass = PlayerClasses[classnum];
mPlayerState = GetDefaultByType (mPlayerClass.Type).SeeState;
if (mPlayerState == NULL)
{ // No see state, so try spawn state.
mPlayerState = GetDefaultByType (mPlayerClass.Type).SpawnState;
}
mPlayerTics = mPlayerState != NULL ? mPlayerState.Tics : -1;
}
//=============================================================================
//
//
//
//=============================================================================
private void UpdateRandomClass()
{
if (--mRandomTimer < 0)
{
if (++mRandomClass >= PlayerClasses.Size ()) mRandomClass = 0;
UpdatePlayer(mRandomClass);
mPlayerTics = mPlayerState != NULL ? mPlayerState.Tics : -1;
mRandomTimer = 6;
// Since the newly displayed class may use a different translation
// range than the old one, we need to update the translation, too.
Translation.SetPlayerTranslation(TRANSLATION_Players, MAXPLAYERS, consoleplayer, mPlayerClass);
}
}
//=============================================================================
//
//
//
//=============================================================================
void SetPlayerClass(int classnum, bool force = false)
{
if (classnum < 0 || classnum >= PlayerClasses.Size ())
{
if (mClassNum != -1)
{
mClassNum = -1;
mRandomTimer = 0;
UpdateRandomClass();
}
}
else if (mPlayerClass != PlayerClasses[classnum] || force)
{
UpdatePlayer(classnum);
mClassNum = classnum;
}
}
//=============================================================================
//
//
//
//=============================================================================
bool UpdatePlayerClass()
{
if (mOwner.mSelectedItem >= 0)
{
int classnum;
Name seltype;
[seltype, classnum] = mOwner.mItems[mOwner.mSelectedItem].GetAction();
if (seltype != 'Episodemenu') return false;
if (PlayerClasses.Size() == 0) return false;
SetPlayerClass(classnum);
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override bool SetValue(int i, int value)
{
switch (i)
{
case PDF_MODE:
mMode = value;
return true;
case PDF_ROTATION:
mRotation = value;
return true;
case PDF_TRANSLATE:
mTranslate = value;
case PDF_CLASS:
SetPlayerClass(value, true);
break;
case PDF_SKIN:
mSkin = value;
break;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override void Ticker()
{
if (mClassNum < 0) UpdateRandomClass();
if (mPlayerState != NULL && mPlayerState.Tics != -1 && mPlayerState.NextState != NULL)
{
if (--mPlayerTics <= 0)
{
mPlayerState = mPlayerState.NextState;
mPlayerTics = mPlayerState.Tics;
}
}
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer(bool selected)
{
if (mMode == 0 && !UpdatePlayerClass())
{
return;
}
let playdef = GetDefaultByType((class<PlayerPawn>)(mPlayerClass.Type));
Name portrait = playdef.Portrait;
if (portrait != 'None' && !mNoportrait)
{
TextureID texid = TexMan.CheckForTexture(portrait, TexMan.Type_MiscPatch);
screen.DrawTexture (texid, true, mXpos, mYpos, DTA_Clean, true);
}
else
{
int x = (mXpos - 160) * CleanXfac + (screen.GetWidth() >> 1);
int y = (mYpos - 100) * CleanYfac + (screen.GetHeight() >> 1);
screen.DrawTexture(mBackdrop, false, x, y - 1,
DTA_DestWidth, 72 * CleanXfac,
DTA_DestHeight, 80 * CleanYfac,
DTA_TranslationIndex, mTranslation,
DTA_Masked, true);
Screen.DrawFrame (x, y, 72*CleanXfac, 80*CleanYfac-1);
if (mPlayerState != NULL)
{
Vector2 Scale;
TextureID sprite;
bool flip;
[sprite, flip, Scale] = mPlayerState.GetSpriteTexture(mRotation, mSkin, playdef.Scale);
if (sprite.IsValid())
{
int trans = mTranslate? Translation.MakeID(TRANSLATION_Players, MAXPLAYERS) : 0;
let tscale = TexMan.GetScaledSize(sprite);
Scale.X *= CleanXfac * tscale.X;
Scale.Y *= CleanYfac * tscale.Y;
screen.DrawTexture (sprite, false,
x + 36*CleanXfac, y + 71*CleanYfac,
DTA_DestWidthF, Scale.X, DTA_DestHeightF, Scale.Y,
DTA_TranslationIndex, trans,
DTA_FlipX, flip);
}
}
}
}
}

View file

@ -0,0 +1,522 @@
/*
** playermenu.txt
** The player setup menu
**
**---------------------------------------------------------------------------
** 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.
**---------------------------------------------------------------------------
**
*/
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class ListMenuItemPlayerNameBox : ListMenuItemSelectable
{
String mText;
Font mFont;
int mFontColor;
int mFrameSize;
String mPlayerName;
TextEnterMenu mEnter;
//=============================================================================
//
// Player's name
//
//=============================================================================
void Init(ListMenuDescriptor desc, String text, int frameofs, Name command)
{
Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, command);
mText = text;
mFont = desc.mFont;
mFontColor = desc.mFontColor;
mFrameSize = frameofs;
mPlayerName = "";
mEnter = null;
}
//=============================================================================
//
// Player's name
//
//=============================================================================
void InitDirect(int x, int y, int height, int frameofs, String text, Font font, int color, Name command)
{
Super.Init(x, y, height, command);
mText = text;
mFont = font;
mFontColor = color;
mFrameSize = frameofs;
mPlayerName = "";
mEnter = null;
}
//=============================================================================
//
//
//
//=============================================================================
override bool SetString(int i, String s)
{
if (i == 0)
{
mPlayerName = s.Mid(0, MAXPLAYERNAME);
return true;
}
return false;
}
override bool, String GetString(int i)
{
if (i == 0)
{
return true, mPlayerName;
}
return false, "";
}
//=============================================================================
//
// [RH] Width of the border is variable
//
//=============================================================================
protected void DrawBorder (int x, int y, int len)
{
let left = TexMan.CheckForTexture("M_LSLEFT", TexMan.Type_MiscPatch);
let mid = TexMan.CheckForTexture("M_LSCNTR", TexMan.Type_MiscPatch);
let right = TexMan.CheckForTexture("M_LSRGHT", TexMan.Type_MiscPatch);
if (left.IsValid() && right.IsValid() && mid.IsValid())
{
int i;
screen.DrawTexture (left, false, x-8, y+7, DTA_Clean, true);
for (i = 0; i < len; i++)
{
screen.DrawTexture (mid, false, x, y+7, DTA_Clean, true);
x += 8;
}
screen.DrawTexture (right, false, x, y+7, DTA_Clean, true);
}
else
{
let slot = TexMan.CheckForTexture("M_FSLOT", TexMan.Type_MiscPatch);
if (slot.IsValid())
{
screen.DrawTexture (slot, false, x, y+1, DTA_Clean, true);
}
else
{
screen.Clear(x, y, x + len, y + SmallFont.GetHeight() * 3/2, 0);
}
}
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer(bool selected)
{
String text = StringTable.Localize(mText);
if (text.Length() > 0)
{
screen.DrawText(mFont, selected? OptionMenuSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true);
}
// Draw player name box
int x = mXpos + mFont.StringWidth(text) + 16 + mFrameSize;
DrawBorder (x, mYpos - mFrameSize, MAXPLAYERNAME+1);
if (!mEnter)
{
screen.DrawText (SmallFont, Font.CR_UNTRANSLATED, x + mFrameSize, mYpos, mPlayerName, DTA_Clean, true);
}
else
{
let printit = mEnter.GetText() .. SmallFont.GetCursor();
screen.DrawText (SmallFont, Font.CR_UNTRANSLATED, x + mFrameSize, mYpos, printit, DTA_Clean, true);
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == Menu.MKEY_Enter)
{
Menu.MenuSound ("menu/choose");
mEnter = TextEnterMenu.Open(Menu.GetCurrentMenu(), mPlayerName, MAXPLAYERNAME, 2, fromcontroller);
return true;
}
else if (mkey == Menu.MKEY_Input)
{
mPlayerName = mEnter.GetText();
mEnter = null;
return true;
}
else if (mkey == Menu.MKEY_Abort)
{
mEnter = null;
return true;
}
return false;
}
}
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class ListMenuItemValueText : ListMenuItemSelectable
{
Array<String> mSelections;
String mText;
int mSelection;
Font mFont;
int mFontColor;
int mFontColor2;
//=============================================================================
//
// items for the player menu
//
//=============================================================================
void Init(ListMenuDescriptor desc, String text, Name command, Name values = 'None')
{
Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, command);
mText = text;
mFont = desc.mFont;
mFontColor = desc.mFontColor;
mFontColor2 = desc.mFontColor2;
mSelection = 0;
let cnt = OptionValues.GetCount(values);
for(int i = 0; i < cnt; i++)
{
SetString(i, OptionValues.GetText(values, i));
}
}
//=============================================================================
//
// items for the player menu
//
//=============================================================================
void InitDirect(int x, int y, int height, String text, Font font, int color, int valuecolor, Name command, Name values)
{
Super.Init(x, y, height, command);
mText = text;
mFont = font;
mFontColor = color;
mFontColor2 = valuecolor;
mSelection = 0;
let cnt = OptionValues.GetCount(values);
for(int i = 0; i < cnt; i++)
{
SetString(i, OptionValues.GetText(values, i));
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool SetString(int i, String s)
{
// should actually use the index...
if (i==0) mSelections.Clear();
mSelections.Push(s);
return true;
}
//=============================================================================
//
//
//
//=============================================================================
override bool SetValue(int i, int value)
{
if (i == 0)
{
mSelection = value;
return true;
}
return false;
}
override bool, int GetValue(int i)
{
if (i == 0)
{
return true, mSelection;
}
return false, 0;
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (mSelections.Size() > 1)
{
if (mkey == Menu.MKEY_Left)
{
Menu.MenuSound("menu/change");
if (--mSelection < 0) mSelection = mSelections.Size() - 1;
return true;
}
else if (mkey == Menu.MKEY_Right || mkey == Menu.MKEY_Enter)
{
Menu.MenuSound("menu/change");
if (++mSelection >= mSelections.Size()) mSelection = 0;
return true;
}
}
return (mkey == Menu.MKEY_Enter); // needs to eat enter keys so that Activate won't get called
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer(bool selected)
{
String text = Stringtable.Localize(mText);
screen.DrawText(mFont, selected? OptionMenuSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true);
int x = mXpos + mFont.StringWidth(text) + 8;
if (mSelections.Size() > 0)
{
screen.DrawText(mFont, mFontColor2, x, mYpos, mSelections[mSelection], DTA_Clean, true);
}
}
}
//=============================================================================
//
// items for the player menu
//
//=============================================================================
class ListMenuItemSlider : ListMenuItemSelectable
{
String mText;
Font mFont;
int mFontColor;
int mMinrange, mMaxrange;
int mStep;
int mSelection;
//=============================================================================
//
// items for the player menu
//
//=============================================================================
void Init(ListMenuDescriptor desc, String text, Name command, int min, int max, int step)
{
Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, command);
mText = text;
mFont = desc.mFont;
mFontColor = desc.mFontColor;
mSelection = 0;
mMinrange = min;
mMaxrange = max;
mStep = step;
}
//=============================================================================
//
// items for the player menu
//
//=============================================================================
void InitDirect(int x, int y, int height, String text, Font font, int color, Name command, int min, int max, int step)
{
Super.Init(x, y, height, command);
mText = text;
mFont = font;
mFontColor = color;
mSelection = 0;
mMinrange = min;
mMaxrange = max;
mStep = step;
}
//=============================================================================
//
//
//
//=============================================================================
override bool SetValue(int i, int value)
{
if (i == 0)
{
mSelection = value;
return true;
}
return false;
}
override bool, int GetValue(int i)
{
if (i == 0)
{
return true, mSelection;
}
return false, 0;
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (mkey == Menu.MKEY_Left)
{
Menu.MenuSound("menu/change");
if ((mSelection -= mStep) < mMinrange) mSelection = mMinrange;
return true;
}
else if (mkey == Menu.MKEY_Right || mkey == Menu.MKEY_Enter)
{
Menu.MenuSound("menu/change");
if ((mSelection += mStep) > mMaxrange) mSelection = mMaxrange;
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
let lm = Menu.GetCurrentMenu();
if (type != Menu.MOUSE_Click)
{
if (!lm.CheckFocus(self)) return false;
}
if (type == Menu.MOUSE_Release)
{
lm.ReleaseFocus();
}
int slide_left = SmallFont.StringWidth ("Green") + 8 + mXpos;
int slide_right = slide_left + 12*8; // 12 char cells with 8 pixels each.
if (type == Menu.MOUSE_Click)
{
if (x < slide_left || x >= slide_right) return true;
}
x = clamp(x, slide_left, slide_right);
int v = mMinrange + (x - slide_left) * (mMaxrange - mMinrange) / (slide_right - slide_left);
if (v != mSelection)
{
mSelection = v;
Menu.MenuSound("menu/change");
}
if (type == Menu.MOUSE_Click)
{
lm.SetFocus(self);
}
return true;
}
//=============================================================================
//
//
//
//=============================================================================
protected void DrawSlider (int x, int y)
{
int range = mMaxrange - mMinrange;
int cur = mSelection - mMinrange;
x = (x - 160) * CleanXfac + screen.GetWidth() / 2;
y = (y - 100) * CleanYfac + screen.GetHeight() / 2;
screen.DrawText (ConFont, Font.CR_WHITE, x, y, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac);
screen.DrawText (ConFont, Font.CR_ORANGE, x + (5 + (int)((cur * 78) / range)) * CleanXfac, y, "\x13", DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac);
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer(bool selected)
{
String text = StringTable.Localize(mText);
screen.DrawText(mFont, selected? OptionMenuSettings.mFontColorSelection : mFontColor, mXpos, mYpos, text, DTA_Clean, true);
int x = SmallFont.StringWidth ("Green") + 8 + mXpos;
int x2 = SmallFont.StringWidth (text) + 8 + mXpos;
DrawSlider (MAX(x2, x), mYpos);
}
}

View file

@ -0,0 +1,15 @@
// This is only the parts that are needed to make the menu fully work right now. More to come later.
class TextEnterMenu : Menu native
{
native bool mInputGridOkay;
native static TextEnterMenu Open(Menu parent, String text, int maxlen, int sizemode, bool fromcontroller);
native String GetText();
override bool TranslateKeyboardEvents()
{
return mInputGridOkay;
}
}

View file

@ -0,0 +1,73 @@
/*
** videomenu.txt
** The video modes menu
**
**---------------------------------------------------------------------------
** 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.
**---------------------------------------------------------------------------
**
*/
//=============================================================================
//
//
//
//=============================================================================
class VideoModeMenu : OptionMenu
{
native static bool SetSelectedSize();
override bool MenuEvent(int mkey, bool fromcontroller)
{
if ((mkey == MKEY_Up || mkey == MKEY_Down) && mDesc.mSelectedItem >= 0 && mDesc.mSelectedItem < mDesc.mItems.Size())
{
int sel;
bool selected;
[selected, sel] = mDesc.mItems[mDesc.mSelectedItem].GetValue(OptionMenuItemScreenResolution.SRL_SELECTION);
bool res = Super.MenuEvent(mkey, fromcontroller);
if (selected) mDesc.mItems[mDesc.mSelectedItem].SetValue(OptionMenuItemScreenResolution.SRL_SELECTION, sel);
return res;
}
return Super.MenuEvent(mkey, fromcontroller);
}
override bool Responder(InputEvent ev)
{
if (ev.type == InputEvent.GUI_Event && ev.subtype == InputEvent.GUI_KeyDown && (ev.data1 == 0x54 || ev.data1 == 0x74))
{
if (SetSelectedSize())
{
MenuSound ("menu/choose");
return true;
}
}
return Super.Responder(ev);
}
}

View file

@ -315,3 +315,12 @@ userinfo_t userinfo;
native void BringUpWeapon();
}
struct PlayerClass native
{
native class<Actor> Type;
native uint Flags;
native Array<int> Skins;
native bool CheckSkin(int skin);
}

View file

@ -31,7 +31,7 @@ class Coin : Inventory
}
else
{
String msg = StringTable.Localize("TXT_XGOLD");
String msg = StringTable.Localize("$TXT_XGOLD");
msg.Replace("%d", "" .. Amount);
return msg;
}

View file

@ -27,7 +27,7 @@ extend class Actor
}
}
String msgid = "TXT_QUEST_" .. questitem;
String msgid = "$TXT_QUEST_" .. questitem;
String msg = StringTable.Localize(msgid);
if (msg != msgid) // if both are identical there was no message of this name in the stringtable.