swwmgz_m/zscript/menu/swwm_menus.zsc
2022-01-13 15:40:17 +01:00

997 lines
32 KiB
Text

// Menu stuff
// voice selector
Class OptionMenuItemSWWMVoiceOption : OptionMenuItemOptionBase
{
CVar mCVar;
Array<String> types;
OptionMenuItemSWWMVoiceOption Init( String label, Name command, CVar graycheck = null, int center = 0 )
{
Super.Init(label,command,'',graycheck,center);
mCVar = CVar.FindCVar(mAction);
int lmp;
for ( lmp = Wads.FindLump("swwmvoicepack.txt"); lmp > 0; lmp = Wads.FindLump("swwmvoicepack.txt",lmp+1) )
{
Array<String> lst;
lst.Clear();
String dat = Wads.ReadLump(lmp);
dat.Split(lst,"\n",0);
for ( int i=0; i<lst.Size(); i++ )
{
if ( (lst[i].Length() <= 0) || (lst[i].GetNextCodePoint(0) == 0) || (lst[i].Left(1) == "\n") || (lst[i].Left(1) == "#") ) continue;
types.Push(lst[i]);
}
}
return self;
}
override bool SetString( int i, String newtext )
{
if ( i == OP_VALUES )
{
int cnt = types.Size();
if ( cnt >= 0 )
{
mValues = newtext;
int s = GetSelection();
if ( (s >= cnt) || (s < 0) ) s = 0;
SetSelection(s);
return true;
}
}
return false;
}
override int GetSelection()
{
int Selection = -1;
int cnt = types.Size();
if ( (cnt > 0) && mCVar )
{
String cv = mCVar.GetString();
for( int i=0; i<cnt; i++ )
{
if ( cv ~== types[i] )
{
Selection = i;
break;
}
}
}
return Selection;
}
override void SetSelection( int Selection )
{
int cnt = types.Size();
if ( (cnt > 0) && mCVar )
mCVar.SetString(types[Selection]);
}
override int Draw( OptionMenuDescriptor desc, int y, int indent, bool selected )
{
if ( mCenter ) indent = (screen.GetWidth()/2);
drawLabel(indent,y,selected?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor,isGrayed());
int Selection = GetSelection();
String loc;
if ( Selection == -1 ) loc = "Unknown";
else
{
String uptxt = types[Selection];
uptxt.MakeUpper();
String str = String.Format("SWWM_VOICENAME_%s",uptxt);
loc = StringTable.Localize(str,false);
if ( str == loc ) loc = types[Selection];
}
drawValue(indent,y,OptionMenuSettings.mFontColorValue,loc,isGrayed());
return indent;
}
override bool MenuEvent( int mkey, bool fromcontroller )
{
int cnt = types.Size();
if ( cnt > 0 )
{
int Selection = GetSelection();
if ( mkey == Menu.MKEY_Left )
{
if ( Selection == -1 ) Selection = 0;
else if ( --Selection < 0 ) Selection = cnt-1;
}
else if ( (mkey == Menu.MKEY_Right) || (mkey == Menu.MKEY_Enter) )
{
if ( ++Selection >= cnt ) Selection = 0;
}
else return OptionMenuItem.MenuEvent(mkey,fromcontroller);
SetSelection(Selection);
Menu.MenuSound("menu/change");
}
else return OptionMenuItem.MenuEvent(mkey,fromcontroller);
return true;
}
}
Class OptionMenuItemSWWMPlayTime : OptionMenuItem
{
CVar mCVar;
bool dformat; // switch between short form and long form time display
OptionMenuItemSWWMPlayTime Init( String label, Name command )
{
Super.Init(label,command);
return self;
}
override bool MenuEvent( int mkey, bool fromcontroller )
{
if ( (mkey == Menu.MKEY_Left) || (mkey == Menu.MKEY_Right) || (mkey == Menu.MKEY_Enter) )
dformat = !dformat;
else return Super.MenuEvent(mkey,fromcontroller);
Menu.MenuSound("menu/change");
return true;
}
override int Draw( OptionMenuDescriptor desc, int y, int indent, bool selected )
{
drawLabel(indent,y,selected?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor);
int val = swwm_playtime;
int sec = (val%60);
int min = ((val/60)%60);
int hour = ((val/3600)%24);
int day = val/86400;
String str = "";
if ( dformat )
{
if ( day ) str.AppendFormat("%d %s",day,StringTable.Localize((day!=1)?"$SWWM_TIME_DAYS":"$SWWM_TIME_DAY"));
if ( hour )
{
if ( str != "" ) str = str..", ";
str.AppendFormat("%d %s",hour,StringTable.Localize((hour!=1)?"$SWWM_TIME_HOURS":"$SWWM_TIME_HOUR"));
}
if ( min )
{
if ( str != "" ) str = str..", ";
str.AppendFormat("%d %s",min,StringTable.Localize((min!=1)?"$SWWM_TIME_MINUTES":"$SWWM_TIME_MINUTE"));
}
if ( sec )
{
if ( str != "" ) str = str..", ";
str.AppendFormat("%d %s",sec,StringTable.Localize((sec!=1)?"$SWWM_TIME_SECONDS":"$SWWM_TIME_SECOND"));
}
if ( str == "" ) str.AppendFormat("0 %s",StringTable.Localize("$SWWM_TIME_SECONDS"));
}
else
{
if ( day ) str = String.Format("%d:%02d:%02d:%02d",day,hour,min,sec);
else if ( hour ) str = String.Format("%d:%02d:%02d",hour,min,sec);
else str = String.Format("%d:%02d",min,sec);
}
drawValue(indent,y,OptionMenuSettings.mFontColorValue,str);
return indent;
}
}
// option menu /w tooltips
Class SWWMOptionMenu : OptionMenu
{
private String ttip;
override void Init( Menu parent, OptionMenuDescriptor desc )
{
Super.Init(parent,desc);
// remove voicepack selector if there's only one voice
for ( int i=0; i<mDesc.mItems.Size(); i++ )
{
if ( !(mDesc.mItems[i] is 'OptionMenuItemSWWMVoiceOption')
|| (OptionMenuItemSWWMVoiceOption(mDesc.mItems[i]).types.Size() > 1) ) continue;
mDesc.mItems[i].Destroy();
mDesc.mItems.Delete(i);
if ( mDesc.mSelectedItem > i ) mDesc.mSelectedItem--;
i--;
}
}
override void Ticker()
{
Super.Ticker();
// fetch the tooltip for whatever's selected (if any)
if ( mDesc.mSelectedItem == -1 ) return;
String mcvar = mDesc.mItems[mDesc.mSelectedItem].GetAction();
mcvar.Replace(" ","_"); // need to strip whitespace for command actions
String locstr = String.Format("TOOLTIP_%s",mcvar);
ttip = StringTable.Localize(locstr,false);
if ( ttip == locstr ) ttip = "";
}
override void Drawer()
{
Super.Drawer();
if ( ttip == "" ) return;
// re-evaluate y to check where the cursor is
int cy = 0;
int y = mDesc.mPosition;
if ( y <= 0 )
{
let font = generic_ui||!mDesc.mFont?NewSmallFont:mDesc.mFont;
if ( font && (mDesc.mTitle.Length() > 0) )
y = -y+font.GetHeight();
else y = -y;
}
int fontheight = OptionMenuSettings.mLinespacing*CleanYfac_1;
y *= CleanYfac_1;
int lastrow = Screen.GetHeight()-OptionHeight()*CleanYfac_1;
for ( int 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
}
y += fontheight;
if ( mDesc.mSelectedItem == i )
{
cy = y+fontheight;
break;
}
}
let lines = smallfont.BreakLines(ttip,CleanWidth_1-8);
int height = (4+smallfont.GetHeight()*lines.Count())*CleanYFac_1;
// draw at the bottom unless the selected option could be covered by the tooltip
int ypos = Screen.GetHeight()-height;
if ( cy > ypos ) ypos = 0;
Screen.Dim("Black",.75,0,ypos,Screen.GetWidth(),height);
ypos += 2*CleanYFac_1;
for ( int i=0; i<lines.Count(); i++ )
{
Screen.DrawText(smallfont,Font.CR_WHITE,4*CleanXFac_1,ypos,lines.StringAt(i),DTA_CleanNoMove_1,true);
ypos += smallfont.GetHeight()*CleanYFac_1;
}
}
}
// main menu w/ version info
Class SWWMCleanMenu : ListMenu
{
override bool MouseEvent( int type, int x, int y )
{
if ( mDesc.DisplayWidth() != ListMenuDescriptor.CleanScale )
return Super.MouseEvent(type,x,y);
int sel = -1;
double sx, sy;
// this menu uses the OTHER clean scale
x = ((x-(screen.GetWidth()/2))/CleanXfac_1)+160;
y = ((y-(screen.GetHeight()/2))/CleanYfac_1)+100;
if ( mFocusControl != NULL )
{
mFocusControl.MouseEvent(type,x,y);
return true;
}
else if ( ((mDesc.mWLeft <= 0) || (x > mDesc.mWLeft)) && ((mDesc.mWRight <= 0) || (x < mDesc.mWRight)) )
{
for( int i=0;i<mDesc.mItems.Size(); i++ )
{
if ( !mDesc.mItems[i].CheckCoordinate(x,y) )
continue;
mDesc.mSelectedItem = i;
mDesc.mItems[i].MouseEvent(type,x,y);
return true;
}
}
mDesc.mSelectedItem = -1;
return Menu.MouseEvent(type,x,y);
}
}
Class SWWMMainMenu : SWWMCleanMenu
{
TextureID demotex, gradtex;
double demopos;
transient uint prevms;
private TextureID GetDemoTex()
{
if ( swwm_oldlogo ) return TexMan.CheckForTexture("graphics/M_DEMOCHAN.png",TexMan.Type_Any);
Array<String> done;
Array<int> candidates;
let c = CVar.FindCVar('swwm_menuposehistory');
String str = c.GetString();
if ( str != "" ) str.Split(done,";");
else
{
c.SetString("2");
return TexMan.CheckForTexture(StringTable.Localize("$SWWM_MENUPOSE2"),TexMan.Type_Any);
}
int npose = StringTable.Localize("$SWWM_NMENUPOSE").ToInt();
for ( int i=1; i<=npose; i++ )
{
String sn = String.Format("%d",i);
if ( done.Find(sn) < done.Size() ) continue;
candidates.Push(i);
}
if ( candidates.Size() == 0 )
{
c.SetString("2");
return TexMan.CheckForTexture(StringTable.Localize("$SWWM_MENUPOSE2"),TexMan.Type_Any);
}
int which = candidates[Random[UIStuff](0,candidates.Size()-1)];
c.SetString(str..";"..which);
return TexMan.CheckForTexture(StringTable.Localize("$SWWM_MENUPOSE"..which),TexMan.Type_Any);
}
override void Init( Menu parent, ListMenuDescriptor desc )
{
Super.Init(parent,desc);
demotex = GetDemoTex();
demopos = 120;
prevms = MSTime();
}
override void OnReturn()
{
demotex = GetDemoTex();
demopos = 120;
prevms = MSTime();
}
private int GetMenuYOffset()
{
int mofs = CleanHeight_1/2-160;
return mofs;
}
override void Drawer()
{
double frametime = (MSTime()-prevms)/1000.;
double theta = clamp(2.*frametime,0.,1.); // naive, but whatever
if ( prevms ) demopos = demopos*(1.-theta)-40*theta;
double alph = clamp(1.-(demopos/100),0.,1.);
if ( !swwm_oldlogo )
{
if ( !gradtex ) gradtex = TexMan.CheckForTexture("graphics/M_GRAD.png",TexMan.Type_Any);
double scl = Screen.GetHeight()/960.;
Screen.DrawTexture(gradtex,false,0,Screen.GetHeight(),DTA_DestWidth,Screen.GetWidth(),DTA_DestHeight,256*CleanYFac_1,DTA_LegacyRenderStyle,STYLE_Shaded,DTA_FillColor,Color(0,0,0),DTA_TopOffset,256,DTA_Alpha,.35);
Screen.DrawTexture(gradtex,false,Screen.GetWidth()/2,Screen.GetHeight(),DTA_Rotate,90,DTA_DestHeight,Screen.GetHeight(),DTA_DestWidthF,600*scl*alph,DTA_LegacyRenderStyle,STYLE_Shaded,DTA_FillColor,Color(0,0,0),DTA_TopOffset,256,DTA_Alpha,alph*.5);
Screen.DrawTexture(gradtex,false,Screen.GetWidth()/2,0,DTA_Rotate,270,DTA_DestHeight,Screen.GetHeight(),DTA_DestWidthF,600*scl*alph,DTA_LegacyRenderStyle,STYLE_Shaded,DTA_FillColor,Color(0,0,0),DTA_TopOffset,256,DTA_Alpha,alph*.5);
Screen.DrawTexture(gradtex,false,Screen.GetWidth()/2,Screen.GetHeight(),DTA_Rotate,90,DTA_DestHeight,Screen.GetHeight(),DTA_DestWidthF,500*scl*alph,DTA_LegacyRenderStyle,STYLE_AddShaded,DTA_FillColor,Color(40,80,120),DTA_TopOffset,256,DTA_Alpha,alph);
Screen.DrawTexture(gradtex,false,Screen.GetWidth()/2,0,DTA_Rotate,270,DTA_DestHeight,Screen.GetHeight(),DTA_DestWidthF,500*scl*alph,DTA_LegacyRenderStyle,STYLE_AddShaded,DTA_FillColor,Color(40,80,120),DTA_TopOffset,256,DTA_Alpha,alph);
Screen.DrawTexture(demotex,false,Screen.GetWidth()/2,0,DTA_ScaleX,scl,DTA_ScaleY,scl,DTA_Alpha,alph,DTA_ColorOverlay,Color(int(255*(1.-(alph**2))),0,0,0));
}
else Screen.DrawTexture(demotex,false,(demopos-160)*CleanXFac_1+(Screen.GetWidth()*.5),(Screen.GetHeight()-400*CleanYFac_1)/2 + sin(gametic*GameTicRate*.1)*CleanYFac_1*8*(alph**2),DTA_CleanNoMove_1,true,DTA_Alpha,alph,DTA_ColorOverlay,Color(64+int(191*(1.-(alph**2))),0,0,0));
if ( !swwm_oldlogo ) for ( int i=0; i<mDesc.mItems.Size(); i++ )
mDesc.mItems[i].OffsetPositionY(GetMenuYOffset());
Super.Drawer();
if ( !swwm_oldlogo ) for ( int i=0; i<mDesc.mItems.Size(); i++ )
mDesc.mItems[i].OffsetPositionY(-GetMenuYOffset());
int xx, yy;
String str = StringTable.Localize("$SWWM_MODVER");
int width = smallfont.StringWidth(str)+8;
int height = smallfont.GetHeight()+4;
xx = CleanWidth_1-width;
yy = CleanHeight_1-height;
Screen.Dim("Black",.75,int(xx*CleanXFac_1),int(yy*CleanYFac_1),int(width*CleanXFac_1),int(height*CleanYFac_1));
Screen.DrawText(smallfont,Font.CR_GOLD,(xx+4)*CleanXFac_1,(yy+2)*CleanYFac_1,str,DTA_CleanNoMove_1,true);
prevms = MSTime();
}
override bool MouseEvent( int type, int x, int y )
{
if ( !swwm_oldlogo ) for ( int i=0; i<mDesc.mItems.Size(); i++ )
mDesc.mItems[i].OffsetPositionY(GetMenuYOffset());
let res = Super.MouseEvent(type,x,y);
if ( !swwm_oldlogo ) for ( int i=0; i<mDesc.mItems.Size(); i++ )
mDesc.mItems[i].OffsetPositionY(-GetMenuYOffset());
return res;
}
}
// skill/episode menu hack
Class SWWMBigMenuHack : SWWMCleanMenu
{
const BIGMENUSPACING = 36;
bool longlist; // more than 10 entries, scrolls
int ofs;
override void Init( Menu parent, ListMenuDescriptor desc )
{
Super.Init(parent,desc);
for ( int i=0; i<mDesc.mItems.Size(); i++ )
{
let itm = mDesc.mItems[i];
// replace text/patch items with our own
if ( itm.GetClass() == 'ListMenuItemTextItem' )
{
let ti = ListMenuItemTextItem(itm);
let rep = new("ListMenuItemSWWMTextItemM");
Name c;
int p;
[c, p] = ti.GetAction();
rep.InitDirect(ti.GetX(),ti.GetY(),BIGMENUSPACING,ti.mHotkey,ti.mText,ti.mFont,ti.mColor,ti.mColorSelected,c,p);
mDesc.mItems[i] = rep;
ti.Destroy();
}
else if ( itm.GetClass() == 'ListMenuItemPatchItem' )
{
let pi = ListMenuItemPatchItem(itm);
let rep = new("ListMenuItemSWWMPatchItemM");
Name c;
int p;
[c, p] = pi.GetAction();
rep.InitDirect(pi.GetX(),pi.GetY(),BIGMENUSPACING,pi.mHotkey,pi.mTexture,c,p);
mDesc.mItems[i] = rep;
pi.Destroy();
}
}
// realign everything to be vertically centered
int ntext = 0;
for ( int i=0; i<mDesc.mItems.Size(); i++ )
{
let itm = mDesc.mItems[i];
if ( (itm.GetClass() == 'ListMenuItemSWWMTextItemM') || (itm.GetClass() == 'ListMenuItemSWWMPatchItemM') )
ntext++;
}
if ( ntext > 7 )
{
longlist = true;
ntext = 7;
}
double theight = ntext*BIGMENUSPACING+56;
int h = mDesc.DisplayHeight();
if ( h == -1 ) h = 200;
double oy = int((h-theight)/2);
// apply offsets
for ( int i=0, j=0; i<mDesc.mItems.Size(); i++ )
{
let itm = mDesc.mItems[i];
if ( (itm.GetClass() == 'ListMenuItemSWWMTextItemM') || (itm.GetClass() == 'ListMenuItemSWWMPatchItemM') )
{
itm.OffsetPositionY(oy+56); // offset from static text header
itm.OffsetPositionY(BIGMENUSPACING*(j++)); // offset from other entries
ListMenuItemSelectable(itm).mHeight = BIGMENUSPACING; // also need to set the height so mouse selection works
}
else
{
// GROSS HACK statictext will for whatever reason INCREASE in offset every time Init is called
if ( itm.GetClass() == 'ListMenuItemSWWMStaticTextM' )
itm.OffsetPositionY(-itm.GetY());
itm.OffsetPositionY(oy);
}
}
}
override void Ticker()
{
Super.Ticker();
// update selection offset
if ( longlist ) ofs = clamp(mDesc.mSelectedItem-4,0,mDesc.mItems.Size()-8);
}
override void Drawer()
{
if ( !longlist )
{
Super.Drawer();
return;
}
// LOTS OF HACK
int w = mDesc.DisplayWidth();
int h = mDesc.DisplayHeight();
bool isclean = false;
if ( w == -1 )
{
w = 320;
h = 200;
isclean = true;
}
String str = "⌃ ⌃ ⌃";
double x = (w-smallfont.StringWidth(str))/2;
double y = (h-280)/2;
if ( isclean ) SWWMUtility.AdjustClean_1(x,y);
if ( ofs > 0 )
{
if ( isclean ) Screen.DrawText(smallfont,Font.CR_FIRE,x,y+30*CleanYFac_1,str,DTA_CleanNoMove_1,true);
else Screen.DrawText(smallfont,Font.CR_FIRE,x,y+30,str,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43);
}
if ( ofs < (mDesc.mItems.Size()-8) )
{
str = "⌄ ⌄ ⌄";
if ( isclean ) Screen.DrawText(smallfont,Font.CR_FIRE,x,y+296*CleanYFac_1,str,DTA_CleanNoMove_1,true);
else Screen.DrawText(smallfont,Font.CR_FIRE,x,y+296,str,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43);
}
for ( int i=0; i<mDesc.mItems.Size(); i++ )
{
if ( !mDesc.mItems[i].mEnabled ) continue;
bool offsetme = false;
if ( (mDesc.mItems[i].GetClass() == 'ListMenuItemSWWMTextItemM') || (mDesc.mItems[i].GetClass() == 'ListMenuItemSWWMPatchItemM') )
{
if ( (i <= ofs) || (i > ofs+7) )
continue;
offsetme = true;
}
if ( offsetme ) mDesc.mItems[i].OffsetPositionY(-ofs*BIGMENUSPACING);
mDesc.mItems[i].Draw((mDesc.mSelectedItem==i),mDesc);
if ( mDesc.mSelectedItem == i ) mDesc.mItems[i].DrawSelector(mDesc.mSelectOfsX,mDesc.mSelectOfsY,mDesc.mSelector,mDesc);
if ( offsetme ) mDesc.mItems[i].OffsetPositionY(ofs*BIGMENUSPACING);
}
Menu.Drawer();
}
// mouse input is also a hack
override bool MouseEvent( int type, int x, int y )
{
// set offsets
for ( int i=0; i<mDesc.mItems.Size(); i++ )
{
if ( !mDesc.mItems[i].mEnabled ) continue;
bool offsetme = false;
if ( (mDesc.mItems[i].GetClass() == 'ListMenuItemSWWMTextItemM') || (mDesc.mItems[i].GetClass() == 'ListMenuItemSWWMPatchItemM') )
{
if ( (i <= ofs) || (i > ofs+7) )
continue;
offsetme = true;
}
if ( offsetme ) mDesc.mItems[i].OffsetPositionY(-ofs*BIGMENUSPACING);
else mDesc.mItems[i].OffsetPositionY(-65536);
}
bool res = Super.MouseEvent(type,x,y);
// unset offsets
for ( int i=0; i<mDesc.mItems.Size(); i++ )
{
if ( !mDesc.mItems[i].mEnabled ) continue;
bool offsetme = false;
if ( (mDesc.mItems[i].GetClass() == 'ListMenuItemSWWMTextItemM') || (mDesc.mItems[i].GetClass() == 'ListMenuItemSWWMPatchItemM') )
{
if ( (i <= ofs) || (i > ofs+7) )
continue;
offsetme = true;
}
if ( offsetme ) mDesc.mItems[i].OffsetPositionY(ofs*BIGMENUSPACING);
else mDesc.mItems[i].OffsetPositionY(65536);
}
return res;
}
}
Class ListMenuItemSWWMStaticTextM : ListMenuItem
{
String mText;
Font mFont;
int mColor;
void Init( ListMenuDescriptor desc, double x, double y, String text, int color = -1 )
{
Super.Init(x,y);
mText = text;
mFont = desc.mFont;
mColor = (color>=0)?color:desc.mFontColor;
}
void InitDirect( double x, double y, String text, Font font, int color = Font.CR_UNTRANSLATED )
{
Super.Init(x,y);
mText = text;
mFont = font;
mColor = color;
}
override void Draw( bool selected, ListMenuDescriptor desc )
{
if ( mText.Length() == 0 ) return;
String text = Stringtable.Localize(mText);
int w = desc?desc.DisplayWidth():ListMenuDescriptor.CleanScale;
int h = desc?desc.DisplayHeight():-1;
if ( w == ListMenuDescriptor.CleanScale )
{
double x = (320-mFont.StringWidth(text))/2;
double y = mYpos;
SWWMUtility.AdjustClean_1(x,y);
Screen.DrawText(mFont,mColor,x,y,text,DTA_CleanNoMove_1,true);
}
else
{
double x = (w-mFont.StringWidth(text))/2;
Screen.DrawText(mFont,mColor,x,mYpos,text,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43);
}
}
}
// scaled SWWM GZ logo
class ListMenuItemSWWMLogo : ListMenuItem
{
TextureID mTexture, mOldTexture;
void Init( ListMenuDescriptor desc )
{
Super.Init(desc.mXpos,desc.mYpos);
mTexture = TexMan.CheckForTexture("graphics/M_DEMOLITIONIST.png",TexMan.Type_Any);
mOldTexture = TexMan.CheckForTexture("graphics/M_SWWM.png",TexMan.Type_Any);
}
private int GetMenuYOffset()
{
int mofs = CleanHeight_1/2-160;
return mofs;
}
override void Draw( bool selected, ListMenuDescriptor desc )
{
let tex = swwm_oldlogo?mOldTexture:mTexture;
if ( !tex.Exists() )
return;
int w = desc?desc.DisplayWidth():ListMenuDescriptor.CleanScale;
int h = desc?desc.DisplayHeight():-1;
Vector2 vs = TexMan.GetScaledSize(tex);
double scl = swwm_oldlogo?(256./vs.x):(2./3.);
double x;
if ( w == ListMenuDescriptor.CleanScale )
{
x = (320-vs.x*scl)/2;
double y = swwm_oldlogo?(-48):(-24+GetMenuYOffset());
SWWMUtility.AdjustClean_1(x,y);
Screen.DrawTexture(tex,false,x,y,DTA_ScaleX,CleanXFac_1*scl,DTA_ScaleY,CleanYFac_1*scl);
}
else
{
x = (w-vs.x*scl)/2;
Screen.DrawTexture(tex,false,x,swwm_oldlogo?(-48):(-24+GetMenuYOffset()),DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43,DTA_ScaleX,scl,DTA_ScaleY,scl);
}
}
}
// message box that changes text color to match menus and applies special scaling
Class SWWMMessageBox : MessageBoxMenu
{
override void Init( Menu parent, String message, int messagemode, bool playsound, Name cmd, voidptr native_handler )
{
Super.Init(parent,message,messagemode,playsound,cmd,native_handler);
if ( generic_ui )
{
destWidth = CleanWidth_1;
destHeight = CleanHeight_1;
textfont = newsmallfont;
mMessage = textfont.BreakLines(Stringtable.Localize(message),480);
}
else
{
destWidth = CleanWidth_1*3;
destHeight = CleanHeight_1*3;
textfont = bigfont;
mMessage = textfont.BreakLines(Stringtable.Localize(message),640);
}
}
override void Drawer()
{
let fontheight = textfont.GetHeight()-2;
double y = destHeight/2;
int c = mMessage.Count();
int theight = 0;
int l1 = c;
int l2 = c-1;
for ( int i=0; i<c; i++ )
{
if ( mMessage.StringWidth(i) != 0 ) continue;
if ( l1 == c ) l1 = i;
else
{
l2 = i;
break;
}
}
for ( int i=0; i<c; i++ )
{
int scl;
if ( generic_ui ) scl = ((i>=l2)||(mMessage.StringWidth(i)==0))?1:(i>l1)?1:2;
else scl = ((i>=l2)||(mMessage.StringWidth(i)==0))?2:(i>l1)?1:3;
theight += fontheight*scl;
}
y -= theight/2;
for ( int i=0; i<c; i++ )
{
double scl;
if ( generic_ui ) scl = ((i>=l2)||(mMessage.StringWidth(i)==0))?1.:(i>l1)?1.:2.;
else scl = ((i>=l2)||(mMessage.StringWidth(i)==0))?2.:(i>l1)?1.:3.;
Screen.DrawText(textfont,OptionMenuSettings.mFontColorValue,int(destWidth/2-mMessage.StringWidth(i)*(scl/2.)),y,mMessage.StringAt(i),DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true,DTA_ScaleX,scl,DTA_ScaleY,scl);
y += fontheight*scl;
}
if ( mMessageMode != 0 ) return;
y += fontheight;
mMouseY = int(y);
String stryes = Stringtable.Localize("$TXT_YES");
String strno = Stringtable.Localize("$TXT_NO");
if ( generic_ui )
{
Screen.DrawText(textfont,messageSelection==0?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor,(destWidth-textfont.StringWidth(stryes))/2,y,stryes, DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true);
Screen.DrawText(textfont,messageSelection==1?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor,(destWidth-textfont.StringWidth(strno))/2,y+fontheight,strno,DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true);
if ( (messageSelection < 0) || ((MenuTime()%8) >= 4) ) return;
Screen.DrawText(textfont,OptionMenuSettings.mFontColorSelection,(destWidth-textfont.StringWidth(messageSelection?strno:stryes))/2-16,y+fontheight*messageSelection,"►",DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true);
Screen.DrawText(textfont,OptionMenuSettings.mFontColorSelection,(destWidth+textfont.StringWidth(messageSelection?strno:stryes))/2+8,y+fontheight*messageSelection,"◄",DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true);
}
else
{
Screen.DrawText(textfont,messageSelection==0?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor,(destWidth-2*textfont.StringWidth(stryes))/2,y,stryes, DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true,DTA_ScaleX,2.,DTA_ScaleY,2.);
Screen.DrawText(textfont,messageSelection==1?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor,(destWidth-2*textfont.StringWidth(strno))/2,y+fontheight*2,strno,DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true,DTA_ScaleX,2.,DTA_ScaleY,2.);
if ( (messageSelection < 0) || ((MenuTime()%8) >= 4) ) return;
Screen.DrawText(textfont,OptionMenuSettings.mFontColorSelection,(destWidth-2*textfont.StringWidth(messageSelection?strno:stryes))/2-72,y+fontheight*2*messageSelection,"►",DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true,DTA_ScaleX,2.,DTA_ScaleY,2.);
Screen.DrawText(textfont,OptionMenuSettings.mFontColorSelection,(destWidth+2*textfont.StringWidth(messageSelection?strno:stryes))/2+24,y+fontheight*2*messageSelection,"◄",DTA_VirtualWidth,destWidth,DTA_VirtualHeight,destHeight,DTA_KeepRatio,true,DTA_ScaleX,2.,DTA_ScaleY,2.);
}
}
override bool MouseEvent( int type, int x, int y )
{
if ( mMessageMode == 1 )
{
if ( type == MOUSE_Click )
return MenuEvent(MKEY_Enter,true);
return false;
}
else
{
int sel = -1;
int fh = (textfont.GetHeight()-2)*(generic_ui?1:2);
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = x*destWidth/screen.GetWidth();
y = y*destHeight/screen.GetHeight();
if ( (y >= mMouseY) && (y < mMouseY+(generic_ui?1:2)*fh) )
{
sel = (y >= mMouseY+fh);
// are we actually selecting the text?
String txt = sel?Stringtable.Localize("$TXT_NO"):Stringtable.Localize("$TXT_YES");
int txtln = textfont.StringWidth(txt);
int minx = (destWidth-txtln);
if ( (x < (destWidth-txtln)) && (x > (destWidth+txtln)) )
sel = -1;
}
messageSelection = sel;
if ( type == MOUSE_Release ) return MenuEvent(MKEY_Enter,true);
return true;
}
}
}
Mixin Class SWWMSelector
{
override void DrawSelector( double xofs, double yofs, TextureID tex, ListMenuDescriptor desc )
{
if ( tex.isNull() ) return;
int w = desc?desc.DisplayWidth():ListMenuDescriptor.CleanScale;
int h = desc?desc.DisplayHeight():-1;
double y = mYpos+mHeight/2;
if ( w == ListMenuDescriptor.CleanScale )
{
xofs *= CleanXFac_1;
yofs *= CleanYFac_1;
double x = (320-GetWidth())/2;
SWWMUtility.AdjustClean_1(x,y);
Screen.DrawTexture(tex,true,x+xofs,y+yofs,DTA_ScaleX,CleanXFac_1/4.,DTA_ScaleY,CleanYFac_1/4.,DTA_Rotate,15.*sin(8*Menu.MenuTime()));
x = (320+GetWidth())/2;
SWWMUtility.AdjustClean_1x(x);
Screen.DrawTexture(tex,true,x-xofs,y+yofs,DTA_ScaleX,CleanXFac_1/4.,DTA_ScaleY,CleanYFac_1/4.,DTA_Rotate,-15.*sin(8*Menu.MenuTime()));
}
else
{
double x = (w-GetWidth())/2;
Screen.DrawTexture(tex,true,x+xofs,y+yofs,DTA_ScaleX,.25,DTA_ScaleY,.25,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43,DTA_Rotate,15.*sin(8*Menu.MenuTime()));
x = (w+GetWidth())/2;
Screen.DrawTexture(tex,true,x-xofs,y+yofs,DTA_ScaleX,.25,DTA_ScaleY,.25,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43,DTA_Rotate,-15.*sin(8*Menu.MenuTime()));
}
}
}
// main menu item with wiggly text when selected and Demo face selectors on both sides
class ListMenuItemSWWMTextItemM : ListMenuItemSelectable
{
Mixin SWWMSelector;
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.GetNextCodePoint(0);
}
void InitDirect( double x, double y, int height, int 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;
}
override int GetWidth()
{
let font = menuDelegate.PickFont(mFont);
return max(1,font.StringWidth(StringTable.Localize(mText)));
}
override void Draw( bool selected, ListMenuDescriptor desc )
{
int w = desc?desc.DisplayWidth():ListMenuDescriptor.CleanScale;
int h = desc?desc.DisplayHeight():-1;
String text = StringTable.Localize(mText);
let font = menuDelegate.PickFont(mFont);
double x;
// centered
if ( w == ListMenuDescriptor.CleanScale ) x = (320-font.StringWidth(text))/2;
else x = (w-font.StringWidth(text))/2;
double y = mYpos;
// offset text so it's centered
y += (mHeight-font.GetHeight())/2;
if ( selected )
{
double xx = x;
SWWMUtility.StripColor(text);
int tlen = text.CodePointCount();
int kern = font.GetDefaultKerning();
if ( w == ListMenuDescriptor.CleanScale )
{
SWWMUtility.AdjustClean_1(xx,y);
for ( int i=0, pos=0; i<tlen; i++ )
{
int ch;
[ch, pos] = text.GetNextCodePoint(pos);
double yy = y+4*sin(32*i+8*Menu.MenuTime())*CleanYFac_1;
Screen.DrawChar(font,mColorSelected,xx,yy,ch,DTA_CleanNoMove_1,true);
xx += (font.GetCharWidth(ch)+kern)*CleanXFac_1;
}
}
else
{
for ( int i=0, pos=0; i<tlen; i++ )
{
int ch;
[ch, pos] = text.GetNextCodePoint(pos);
double yy = y+4*sin(32*i+8*Menu.MenuTime());
Screen.DrawChar(mFont,mColorSelected,xx,yy,ch,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43);
xx += (font.GetCharWidth(ch)+kern);
}
}
}
else if ( w == ListMenuDescriptor.CleanScale )
{
SWWMUtility.AdjustClean_1(x,y);
Screen.DrawText(font,mColor,x,y,text,DTA_CleanNoMove_1,true);
}
else Screen.DrawText(font,mColor,x,y,text,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43);
}
}
// for compat with non-text episodes (no longer used?)
Class ListMenuItemSWWMPatchItemM : ListMenuItemSelectable
{
Mixin SWWMSelector;
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.GetNextCodePoint(0);
mTexture = patch;
}
void InitDirect( double x, double y, int height, int hotkey, TextureID patch, Name child, int param = 0 )
{
Super.Init(x,y,height,child,param);
mHotkey = hotkey;
mTexture = patch;
}
override int GetWidth()
{
Vector2 vs = TexMan.GetScaledSize(mTexture);
return int(vs.x);
}
override void Draw( bool selected, ListMenuDescriptor desc )
{
int w = desc?desc.DisplayWidth():ListMenuDescriptor.CleanScale;
int h = desc?desc.DisplayHeight():-1;
if ( w == ListMenuDescriptor.CleanScale )
{
double x = (320-GetWidth())/2;
Screen.DrawTexture(mTexture,true,x,mYpos,DTA_Clean,true);
}
else
{
double x = (w-GetWidth())/2;
screen.DrawTexture(mTexture,true,x,mYpos,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43);
}
}
}
Class OptionMenuItemTrapOption : OptionMenuItem
{
int cdown;
OptionMenuItemTrapOption Init( String label, Name command )
{
Super.Init(label,command);
return self;
}
override int Draw( OptionMenuDescriptor desc, int y, int indent, bool selected )
{
drawLabel(indent,y,selected?OptionMenuSettings.mFontColorSelection:OptionMenuSettings.mFontColor);
String text = StringTable.Localize(OptionValues.GetText('OnOff',(cdown==0)));
if ( text.Length() == 0 ) text = "Unknown";
drawValue(indent,y,OptionMenuSettings.mFontColorValue,text);
return indent;
}
override bool MenuEvent( int mkey, bool fromcontroller )
{
if ( (mkey == Menu.MKEY_Left) || (mkey == Menu.MKEY_Right) || (mkey == Menu.MKEY_Enter) )
{
Activate();
return true;
}
return Super.MenuEvent(mkey,fromcontroller);
}
override void Ticker()
{
Super.Ticker();
if ( cdown <= 0 ) return;
cdown--;
if ( cdown > 0 ) return;
// haha more crimes
Menu.SetMenu('QuitMenu');
let m = MessageBoxMenu(Menu.GetCurrentMenu());
if ( m ) m.HandleResult(true);
}
override bool Activate()
{
Menu.MenuSound("bruh");
cdown = int(S_GetLength("bruh")*GameTicRate)+4;
return true;
}
}
// this is kind of a fucky
// scalesliders kinda fuck up keyboard input if the step is not 1,
// so I'll fix that for my super special use cases
Class OptionMenuItemScaleSliderFix : OptionMenuItemScaleSlider
{
override bool MenuEvent ( int mkey, bool fromcontroller )
{
double value = GetSliderValue();
if ( mkey == Menu.MKEY_Left )
{
if ( value <= 0 ) value--;
else value = max(0,value-mStep);
}
else if ( mkey == Menu.MKEY_Right )
{
if ( value < 0 ) value++;
else value += mStep;
}
else return OptionMenuItem.MenuEvent(mkey,fromcontroller);
if ( value ~== 0 ) value = 0; // This is to prevent formatting anomalies with very small values
SetSliderValue(clamp(value,mMin,mMax));
Menu.MenuSound("menu/change");
return true;
}
}
Class SWWMMenuDelegate : DoomMenuDelegate
{
// we've got our own fonts 'round here
override Font PickFont( Font fnt )
{
if ( generic_ui ) return NewSmallFont;
if ( !fnt ) return SmallFont;
if ( (fnt == AlternativeBigFont) || (fnt == OriginalBigFont) || (fnt == IntermissionFont) ) return BigFont;
if ( (fnt == AlternativeSmallFont) || (fnt == NewSmallFont) ) return SmallFont;
return fnt;
}
}