swwmgz_m/zscript/menu/swwm_menus.zsc
Marisa the Magician f78b747ff7 Add secret difficulty for a dragon.
Remove 2x speed mult from hardest skill(s) (causes glitches).
Allow moths to still attack while following the lamp.
(Still do not know what causes moths to print "asin domain error" to terminal).
2023-10-16 14:00:46 +02:00

1081 lines
34 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.FindLumpFullName("swwmvoicepack.txt"); lmp != -1; lmp = Wads.FindLumpFullName("swwmvoicepack.txt",lmp+1) )
{
Array<String> lst;
lst.Clear();
String dat = Wads.ReadLump(lmp);
dat.Split(lst,"\n",0);
foreach ( l:lst )
{
if ( (l.Length() <= 0) || (l.GetNextCodePoint(0) == 0) || (l.Left(1) == "\n") || (l.Left(1) == "#") ) continue;
types.Push(l);
}
}
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;
String str = "";
if ( dformat )
{
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 ( 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, olttip;
private Font mTipFont;
private BrokenLines ttlines;
override void Init( Menu parent, OptionMenuDescriptor desc )
{
Super.Init(parent,desc);
mTipFont = Font.GetFont('TewiFont');
}
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);
olttip = ttip;
ttip = StringTable.Localize(locstr,false);
if ( ttip == locstr ) ttip = "";
if ( (ttip != olttip) && ttlines ) ttlines.Destroy();
if ( !ttlines ) ttlines = mTipFont.BreakLines(ttip,CleanWidth_1-8);
}
override void Drawer()
{
Super.Drawer();
if ( (ttip == "") || !ttlines ) 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;
}
}
int height = (4+mTipFont.GetHeight()*ttlines.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<ttlines.Count(); i++ )
{
Screen.DrawText(mTipFont,Font.CR_WHITE,4*CleanXFac_1,ypos,ttlines.StringAt(i),DTA_CleanNoMove_1,true);
ypos += mTipFont.GetHeight()*CleanYFac_1;
}
}
}
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);
}
}
// main menu w/ version info
Class SWWMMainMenu : SWWMCleanMenu
{
TextureID demotex, gradtex;
int fadetime;
Font mSmallFont;
private TextureID GetDemoTex()
{
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"));
}
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"));
}
int which = candidates[Random[UIStuff](0,candidates.Size()-1)];
c.SetString(str..";"..which);
return TexMan.CheckForTexture(StringTable.Localize("$SWWM_MENUPOSE"..which));
}
override void Init( Menu parent, ListMenuDescriptor desc )
{
Super.Init(parent,desc);
mSmallFont = Font.GetFont('TewiFont');
demotex = GetDemoTex();
fadetime = MenuTime()+1;
}
override void OnReturn()
{
demotex = GetDemoTex();
fadetime = MenuTime()+1;
}
private int GetMenuYOffset()
{
int mofs = CleanHeight_1/2-160;
return mofs;
}
override void Drawer()
{
double alph = clamp(((MenuTime()+System.GetTimeFrac())-fadetime)/(GameTicRate/3.),0.,1.);
if ( !gradtex ) gradtex = TexMan.CheckForTexture("graphics/M_GRAD.png");
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));
foreach ( itm:mDesc.mItems )
itm.OffsetPositionY(GetMenuYOffset());
Super.Drawer();
foreach ( itm:mDesc.mItems )
itm.OffsetPositionY(-GetMenuYOffset());
int xx, yy;
String str = StringTable.Localize("$SWWM_MODVER");
int width = mSmallFont.StringWidth(str)+8;
int height = mSmallFont.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(mSmallFont,Font.CR_GOLD,(xx+4)*CleanXFac_1,(yy+2)*CleanYFac_1,str,DTA_CleanNoMove_1,true);
}
override bool MouseEvent( int type, int x, int y )
{
foreach ( itm:mDesc.mItems )
itm.OffsetPositionY(GetMenuYOffset());
let res = Super.MouseEvent(type,x,y);
foreach ( itm:mDesc.mItems )
itm.OffsetPositionY(-GetMenuYOffset());
return res;
}
}
// skill/episode menu, featuring scrolling
Class SWWMScrollMenu : SWWMCleanMenu
{
bool longlist; // more than 10 entries, scrolls
int ofs;
Font mSmallFont;
override void Init( Menu parent, ListMenuDescriptor desc )
{
Super.Init(parent,desc);
mSmallFont = Font.GetFont('TewiFont');
uint tntfix = 0; // HACKFIX: TUTNT Supportive Edition uses one patch graphic for all episode names, this breaks our menus
static const string tutnt_ep[] =
{
"Opening Abyss", "Armory of Pain", "Damnation's Keep", "Havoc", "Fury of Fire"
};
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");
let [c, p] = ti.GetAction();
rep.InitDirect(ti.GetX(),ti.GetY(),mDesc.mLineSpacing,ti.mHotkey,ti.mText,ti.mFont,ti.mColor,ti.mColorSelected,c,p);
if ( (ti.mText == "$M_EPITNT") || (tntfix && (tntfix < 5)) )
rep.mText = tutnt_ep[tntfix++];
mDesc.mItems[i] = rep;
ti.Destroy();
}
else if ( itm.GetClass() == 'ListMenuItemPatchItem' )
{
let pi = ListMenuItemPatchItem(itm);
let rep = new("ListMenuItemSWWMPatchItemM");
let [c, p] = pi.GetAction();
rep.InitDirect(pi.GetX(),pi.GetY(),mDesc.mLineSpacing,pi.mHotkey,pi.mTexture,c,p);
mDesc.mItems[i] = rep;
pi.Destroy();
}
}
// realign everything to be vertically centered
int ntext = 0;
foreach ( itm:mDesc.mItems )
{
if ( (itm.GetClass() == 'ListMenuItemSWWMTextItemM') || (itm.GetClass() == 'ListMenuItemSWWMPatchItemM') )
ntext++;
}
if ( ntext > 7 )
{
longlist = true;
ntext = 7;
}
double theight = ntext*mDesc.mLineSpacing;
if ( mDesc.mItems[0] is 'ListMenuItemSWWMStaticTextM' )
theight += 56; // we take into account the static text as well for centering
int h = mDesc.DisplayHeight();
if ( h == -1 ) h = 200;
double oy = int((h-theight)/2);
// apply offsets
int j = 0;
foreach ( itm:mDesc.mItems )
{
// 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-mSmallFont.StringWidth(str))/2;
double y = (h-224)/2;
if ( isclean ) SWWMUtility.AdjustClean_1(x,y);
if ( ofs > 0 )
{
if ( isclean ) Screen.DrawText(mSmallFont,Font.CR_FIRE,x,y+16*CleanYFac_1,str,DTA_CleanNoMove_1,true);
else Screen.DrawText(mSmallFont,Font.CR_FIRE,x,y+16,str,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43);
}
if ( ofs < (mDesc.mItems.Size()-8) )
{
str = "⌄ ⌄ ⌄";
if ( isclean ) Screen.DrawText(mSmallFont,Font.CR_FIRE,x,y+256*CleanYFac_1,str,DTA_CleanNoMove_1,true);
else Screen.DrawText(mSmallFont,Font.CR_FIRE,x,y+256,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*mDesc.mLineSpacing);
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*mDesc.mLineSpacing);
}
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*mDesc.mLineSpacing);
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*mDesc.mLineSpacing);
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;
let font = menuDelegate.PickFont(mFont);
int scl;
if ( font != NewSmallFont ) scl = 3;
else scl = 2;
if ( w == ListMenuDescriptor.CleanScale )
{
double x = (320-font.StringWidth(text)*scl)/2;
double y = mYpos;
SWWMUtility.AdjustClean_1(x,y);
Screen.DrawText(font,mColor,x,y,text,DTA_ScaleX,CleanXFac_1*scl,DTA_ScaleY,CleanYFac_1*scl);
}
else
{
double x = (w-font.StringWidth(text)*scl)/2;
Screen.DrawText(font,mColor,x,mYpos,text,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43,DTA_ScaleX,scl,DTA_ScaleY,scl);
}
}
}
// scaled mod logo
class ListMenuItemSWWMLogo : ListMenuItem
{
TextureID mTexture;
void Init( ListMenuDescriptor desc )
{
Super.Init(desc.mXpos,desc.mYpos);
mTexture = TexMan.CheckForTexture("graphics/M_DEMOLITIONIST.png");
}
private int GetMenuYOffset()
{
int mofs = CleanHeight_1/2-160;
return mofs;
}
override void Draw( bool selected, ListMenuDescriptor desc )
{
int w = desc?desc.DisplayWidth():ListMenuDescriptor.CleanScale;
int h = desc?desc.DisplayHeight():-1;
Vector2 vs = TexMan.GetScaledSize(mTexture);
double scl = (2./3.);
double x;
if ( w == ListMenuDescriptor.CleanScale )
{
x = (320-vs.x*scl)/2;
double y = -24+GetMenuYOffset();
SWWMUtility.AdjustClean_1(x,y);
Screen.DrawTexture(mTexture,false,x,y,DTA_ScaleX,CleanXFac_1*scl,DTA_ScaleY,CleanYFac_1*scl);
}
else
{
x = (w-vs.x*scl)/2;
Screen.DrawTexture(mTexture,false,x,-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;
destHeight = CleanHeight_1;
textfont = Font.GetFont('TewiFontOutline');
mMessage = textfont.BreakLines(Stringtable.Localize(message),480);
}
}
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-26,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+12,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()+System.GetTimeFrac())));
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()+System.GetTimeFrac())));
}
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()+System.GetTimeFrac())));
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()+System.GetTimeFrac())));
}
}
}
// allow the player to skip skill confirmation message boxes
Mixin Class SWWMSkillConfirmSkippable
{
override bool Activate()
{
Menu.SetMenu(((mAction=='StartgameConfirm')&&swwm_skipskill)?'Startgame':mAction,mParam);
return true;
}
override Name, int GetAction()
{
return (((mAction=='StartgameConfirm')&&swwm_skipskill)?'Startgame':mAction),mParam;
}
}
// main menu item with wiggly text when selected and Demo face selectors on both sides
Class ListMenuItemSWWMTextItemM : ListMenuItemSelectable
{
Mixin SWWMSelector;
Mixin SWWMSkillConfirmSkippable;
String mText;
Font mFont;
int mColor;
int mColorSelected;
bool kyni;
double alph;
bool isSel;
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);
kyni = (text == "$SWWM_SKDRAGON");
if ( kyni ) alph = 0.;
else alph = 1.;
}
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;
kyni = (text == "$SWWM_SKDRAGON");
if ( kyni ) alph = 0.;
else alph = 1.;
}
override void Ticker()
{
Super.Ticker();
if ( !kyni ) return;
if ( isSel ) alph = min(1.,alph+.05);
else alph = 0.;
}
override int GetWidth()
{
let font = menuDelegate.PickFont(mFont);
int w = font.StringWidth(StringTable.Localize(mText));
if ( font != NewSmallFont ) w *= 2;
return max(1,w);
}
override void Draw( bool selected, ListMenuDescriptor desc )
{
isSel = selected;
if ( kyni && !isSel ) return;
int w = desc?desc.DisplayWidth():ListMenuDescriptor.CleanScale;
int h = desc?desc.DisplayHeight():-1;
String text = StringTable.Localize(mText);
let font = menuDelegate.PickFont(mFont);
int scl;
if ( font != NewSmallFont ) scl = 2;
else scl = 1;
double x;
// centered
if ( w == ListMenuDescriptor.CleanScale ) x = (320-font.StringWidth(text)*scl)/2;
else x = (w-font.StringWidth(text)*scl)/2;
double y = mYpos;
// offset text so it's centered
y += (mHeight-font.GetHeight()*scl)/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()+System.GetTimeFrac()))*CleanYFac_1;
Screen.DrawChar(font,kyni?Font.CR_BLACK:mColorSelected,xx,yy,ch,DTA_ScaleX,CleanXFac_1*scl,DTA_ScaleY,CleanYFac_1*scl,DTA_Alpha,alph);
xx += (font.GetCharWidth(ch)+kern)*CleanXFac_1*scl;
}
}
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()+System.GetTimeFrac()));
Screen.DrawChar(mFont,kyni?Font.CR_BLACK:mColorSelected,xx,yy,ch,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43,DTA_ScaleX,scl,DTA_ScaleY,scl,DTA_Alpha,alph);
xx += (font.GetCharWidth(ch)+kern)*scl;
}
}
}
else if ( w == ListMenuDescriptor.CleanScale )
{
SWWMUtility.AdjustClean_1(x,y);
Screen.DrawText(font,mColor,x,y,text,DTA_ScaleX,CleanXFac_1*scl,DTA_ScaleY,CleanYFac_1*scl);
}
else Screen.DrawText(font,mColor,x,y,text,DTA_VirtualWidth,w,DTA_VirtualHeight,h,DTA_FullscreenScale,FSMode_ScaleToFit43,DTA_ScaleX,scl,DTA_ScaleY,scl);
}
}
// for compat with non-text episodes (no longer used?)
Class ListMenuItemSWWMPatchItemM : ListMenuItemSelectable
{
Mixin SWWMSelector;
Mixin SWWMSkillConfirmSkippable;
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 hot mess
// scalesliders don't mesh well with 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;
}
}
// allows only positive numeric values, 0 optionally gets a special label in parentheses
Class OptionMenuItemSWWMScaleField : OptionMenuItemTextField
{
String mZeroHint;
OptionMenuItemSWWMScaleField Init( String label, Name command, String zerohint = "" )
{
Super.Init(label,command);
mZeroHint = zerohint;
return self;
}
override bool, String GetString( int i )
{
if ( i == 0 )
{
String str = mCVar?mCVar.GetString():"";
int val = mCVar?mCVar.GetInt():0;
if ( (val == 0) && (mZeroHint != "") )
str.AppendFormat(" (%s)",StringTable.Localize(mZeroHint));
return true, str;
}
return false,"";
}
override bool MenuEvent (int mkey, bool fromcontroller)
{
if ( mkey == Menu.MKEY_Enter )
{
Menu.MenuSound("menu/choose");
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(),Menu.OptionFont(),"",-1,fromcontroller);
mEnter.ActivateMenu();
return true;
}
if ( mkey == Menu.MKEY_Left )
{
int val = mCVar?mCVar.GetInt():0;
val = max(0,val-1);
if ( mCVar ) mCVar.SetInt(val);
Menu.MenuSound("menu/change");
return true;
}
if ( mkey == Menu.MKEY_Right )
{
int val = mCVar?mCVar.GetInt():0;
val++;
if ( mCVar ) mCVar.SetInt(val);
Menu.MenuSound("menu/change");
return true;
}
return Super.MenuEvent(mkey,fromcontroller);
}
override bool SetString( int i, String s )
{
if ( i == 0 )
{
int numval = max(s.ToInt(),0);
if ( mCVar ) mCVar.SetInt(numval);
return true;
}
return false;
}
}
// draw captions using our own font
Class SWWMMenuDelegate : DoomMenuDelegate
{
Font mBigFont;
override int DrawCaption( String title, Font fnt, int y, bool drawit )
{
if ( !mBigFont ) mBigFont = Font.GetFont('TewiFontOutline');
fnt = mBigFont;
if ( drawit ) Screen.DrawText(fnt,OptionMenuSettings.mTitleColor,(Screen.GetWidth()-fnt.StringWidth(title)*CleanXFac_1*2)/2,8*CleanYFac_1,title,DTA_ScaleX,CleanXFac_1*2,DTA_ScaleY,CleanYFac_1*2);
return (y+fnt.GetHeight()*2)*CleanYFac_1;
}
}