1216 lines
35 KiB
Text
1216 lines
35 KiB
Text
// additional hud things
|
|
|
|
// Press F to Pay Respects
|
|
Class PayRespects : HUDMessageBase
|
|
{
|
|
Vector2 basepos;
|
|
int lifespan, initialspan, starttic;
|
|
double scale;
|
|
double hs;
|
|
Vector2 ss;
|
|
int seed, seed2;
|
|
Font mSmallFont;
|
|
|
|
static PayRespects PressF()
|
|
{
|
|
let f = new("PayRespects");
|
|
f.basepos = (FRandom[FInTheChat](0.,1.),FRandom[FInTheChat](1.02,1.05));
|
|
f.scale = FRandom[FInTheChat](.5,2.);
|
|
f.lifespan = f.initialspan = Random[FInTheChat](20,80);
|
|
f.starttic = level.maptime;
|
|
f.seed = Random[FInTheChat]();
|
|
f.seed2 = Random[FInTheChat]();
|
|
f.ScreenSizeChanged();
|
|
f.mSmallFont = Font.GetFont('TewiFont');
|
|
return f;
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
lifespan--;
|
|
return (lifespan<=0);
|
|
}
|
|
|
|
override void ScreenSizeChanged()
|
|
{
|
|
hs = CleanXFac*scale;
|
|
ss = (Screen.GetWidth(),Screen.GetHeight())/hs;
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
Vector2 realpos = (basepos.x*ss.x,basepos.y*ss.y);
|
|
Vector2 fo = (mSmallFont.StringWidth("F")/2.,-mSmallFont.GetHeight());
|
|
// F rise up
|
|
int initspd = (128-seed);
|
|
if ( (initspd >= 0) && (initspd < 32) ) initspd = 32;
|
|
if ( (initspd < 0) && (initspd > -32) ) initspd = -32;
|
|
int boostup = 32+(seed2/4);
|
|
double fractic = System.GetTimeFrac();
|
|
fo.x += (.15*initspd)*((initialspan-(lifespan-fractic))**.6);
|
|
fo.y += ((initialspan-(lifespan-fractic))**1.6)-boostup*sin((90./initialspan)*(level.maptime+fractic-starttic));
|
|
double alph = clamp((lifespan+fractic)/double(initialspan),0.,1.);
|
|
Screen.DrawText(mSmallFont,Font.CR_GREEN,realpos.x-fo.x,realpos.y-fo.y,"F",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
}
|
|
}
|
|
|
|
// One-liners
|
|
Class SWWMOneLiner : HUDMessageBase
|
|
{
|
|
String whichline;
|
|
transient BrokenLines l;
|
|
int lifespan, curtime;
|
|
Font mSmallFont;
|
|
|
|
static SWWMOneLiner Make( String whichline, int lifespan )
|
|
{
|
|
let l = new("SWWMOneLiner");
|
|
if ( StringTable.Localize(whichline) == "" ) l.whichline = "";
|
|
else l.whichline = StringTable.Localize("$SWWM_LQUOTE")..StringTable.Localize(whichline)..StringTable.Localize("$SWWM_RQUOTE");
|
|
l.curtime = l.lifespan = lifespan;
|
|
l.mSmallFont = Font.GetFont('TewiFont');
|
|
return l;
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
if ( players[consoleplayer].Health <= 0 ) curtime = int.min;
|
|
curtime--;
|
|
return (curtime<-20);
|
|
}
|
|
|
|
override void ScreenSizeChanged()
|
|
{
|
|
if ( l ) l.Destroy();
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
int margin = swwm_hudmargin;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
|
|
}
|
|
if ( whichline == "" ) return; // don't draw empty strings
|
|
// split so it can fit
|
|
if ( !l ) l = mSmallFont.BreakLines(whichline,int(ss.x*.5));
|
|
int maxlen = 0;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
int len = mSmallFont.StringWidth(l.StringAt(i));
|
|
if ( len > maxlen ) maxlen = len;
|
|
}
|
|
int h = mSmallFont.GetHeight();
|
|
int fh = h*l.Count();
|
|
double fractic = System.GetTimeFrac();
|
|
double fcurtime = curtime-fractic;
|
|
double alph = clamp((fcurtime/20.)+1.,0.,1.);
|
|
alph *= clamp((lifespan-fcurtime)/10.,0.,1.);
|
|
Screen.Dim("Black",alph*.8,int((Screen.GetWidth()-(maxlen+12)*hs)/2.),int(bottom-(margin+2+fh)*hs),int((maxlen+12)*hs),int((fh+4)*hs));
|
|
int yy = margin+fh;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
int len = mSmallFont.StringWidth(l.StringAt(i));
|
|
Screen.DrawText(mSmallFont,Font.CR_GREEN,int((ss.x-len)/2.),(bottom/hs)-yy,l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
yy -= h;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Screen flashes from DT
|
|
Class GenericFlash : HUDMessageBase
|
|
{
|
|
Color col;
|
|
int duration;
|
|
double alpha;
|
|
Actor cam;
|
|
|
|
GenericFlash Setup( Actor camera, Color c, int d )
|
|
{
|
|
alpha = 1.0;
|
|
col = c;
|
|
duration = d;
|
|
cam = camera;
|
|
return self;
|
|
}
|
|
override bool Tick()
|
|
{
|
|
if ( duration > 0 ) alpha -= 1./duration;
|
|
return (alpha<=0)||(!cam);
|
|
}
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
if ( automapactive || (visibility != BaseStatusBar.HUDMSGLayer_UnderHUD) ) return;
|
|
if ( cam && (players[consoleplayer].camera != cam) ) return;
|
|
double fractic = System.GetTimeFrac();
|
|
double falpha = alpha-fractic*(1./duration);
|
|
Screen.Dim(col,(col.a/255.)*falpha*swwm_flashstrength,0,0,Screen.GetWidth(),Screen.GetHeight(),STYLE_Add);
|
|
}
|
|
}
|
|
|
|
Class QueuedFlash
|
|
{
|
|
Color c;
|
|
int duration;
|
|
int tic;
|
|
Actor cam;
|
|
}
|
|
|
|
// Achievement notification
|
|
Class SWWMAchievementNotification : HUDMessageBase
|
|
{
|
|
String tag, txt;
|
|
transient BrokenLines l;
|
|
TextureID icon, frame;
|
|
double tics, holdtics, fadeintics, fadeouttics;
|
|
Font mSmallFont, mTinyFont;
|
|
|
|
SWWMAchievementNotification Init( String bname, TextureID icon, int num = 0 )
|
|
{
|
|
tag = StringTable.Localize("$SWWM_ACHIEVEMENT_"..bname.."_TAG");
|
|
txt = StringTable.Localize("$SWWM_ACHIEVEMENT_"..bname.."_TXT");
|
|
if ( num ) txt = String.Format(txt,SWWMUtility.ThousandsNum(num));
|
|
self.icon = icon;
|
|
frame = TexMan.CheckForTexture("graphics/HUD/AchievementNotification.png");
|
|
holdtics = 150;
|
|
fadeintics = 20;
|
|
fadeouttics = 30;
|
|
tics = 0;
|
|
mSmallFont = Font.GetFont('TewiFont');
|
|
mTinyFont = Font.GetFont('MiniwiFont');
|
|
return self;
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
return (++tics > holdtics+fadeintics+fadeouttics);
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
double margin = swwm_hudmargin;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
|
|
}
|
|
double fractic = System.GetTimeFrac();
|
|
double ftics = tics+fractic;
|
|
double alpha = (ftics<fadeintics)?(ftics/fadeintics):(ftics<(fadeintics+holdtics))?1.:(1.-(ftics-(fadeintics+holdtics))/fadeouttics);
|
|
Vector2 pos = (int(ss.x-256)/2,(ss.y-(margin+36))+int(margin+40)*(1.-alpha));
|
|
if ( !l ) l = mTinyFont.BreakLines(txt,200);
|
|
int th = 14+(9*l.Count());
|
|
Screen.DrawTexture(frame,false,pos.x,pos.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
if ( icon.IsValid() ) Screen.DrawTexture(icon,false,pos.x+2,pos.y+2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
int yy = 2+(32-th)/2;
|
|
Screen.DrawText(mSmallFont,Font.CR_GREEN,pos.x+40,pos.y+yy,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
yy += 14;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
Screen.DrawText(mTinyFont,Font.CR_WHITE,pos.x+44,pos.y+yy,l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
yy += 9;
|
|
}
|
|
}
|
|
}
|
|
|
|
// weapon tooltips
|
|
Class SWWMWeaponTooltip : HUDMessageBase
|
|
{
|
|
String wpn, txt;
|
|
double tics, holdtics, fadeintics, fadeouttics;
|
|
transient BrokenLines l;
|
|
SWWMWeaponTooltip next;
|
|
Font mSmallFont, mTinyFont;
|
|
|
|
SWWMWeaponTooltip Init( Class<SWWMWeapon> weapon )
|
|
{
|
|
let def = GetDefaultByType(weapon);
|
|
wpn = def.GetTag();
|
|
txt = StringTable.Localize(def.tooltip);
|
|
holdtics = 150;
|
|
fadeintics = 5;
|
|
fadeouttics = 15;
|
|
tics = -10;
|
|
mSmallFont = Font.GetFont('TewiFont');
|
|
mTinyFont = Font.GetFont('MiniwiFont');
|
|
return self;
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
bool clearme = (++tics > holdtics+fadeintics+fadeouttics);
|
|
if ( clearme && next ) StatusBar.AttachMessage(next,-2910);
|
|
return clearme;
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
if ( tics <= 0 ) return;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
|
|
}
|
|
double fractic = System.GetTimeFrac();
|
|
double ftics = tics+fractic;
|
|
double alpha = (ftics<fadeintics)?(ftics/fadeintics):(ftics<(fadeintics+holdtics))?1.:(1.-(ftics-(fadeintics+holdtics))/fadeouttics);
|
|
int w = mSmallFont.StringWidth(wpn);
|
|
if ( !l ) l = mTinyFont.BreakLines(txt,600);
|
|
int w1 = w;
|
|
w = 0;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
let lw = mTinyFont.StringWidth(l.StringAt(i));
|
|
if ( lw > w ) w = lw;
|
|
}
|
|
int cw = int(ceil((max(w1,w)+8)/6.))*6;
|
|
int h = mSmallFont.GetHeight()+8+mTinyFont.GetHeight()*l.Count();
|
|
Vector2 pos = (int(ss.x/2),ss.y-(swwm_hudmargin+80+h));
|
|
Screen.Dim("Black",.5*alpha,int((pos.x-(cw+4)/2)*hs),int((pos.y-2)*hs),int((cw+4)*hs),int((h+4)*hs));
|
|
Screen.DrawText(mSmallFont,Font.CR_FIRE,pos.x-w1/2,pos.y,wpn,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
for ( int i=0; i<cw; i+=6 )
|
|
Screen.DrawChar(mSmallFont,Font.CR_FIRE,(pos.x-cw/2)+i,pos.y+6,0x5F,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
pos.y += mSmallFont.GetHeight()+8;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
Screen.DrawText(mTinyFont,Font.CR_WHITE,pos.x-w/2,pos.y,l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
pos.y += mTinyFont.GetHeight();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Used sparingly for some events
|
|
Class SWWMDirectMessage : HUDMessageBase
|
|
{
|
|
TextureID MessageBox, BG, Avatar, Blink[2], Talk[5], Noiz[4];
|
|
transient BrokenLines l;
|
|
String seqname, chrname, chrfullname;
|
|
bool znvspecial; // seqnum 2 string replacement
|
|
int seqnum, seqcnt, delay, charcnt, blinktics, talktics, talkframe;
|
|
int startdelay, enddelay, pausedelay, chardelay;
|
|
int rss;
|
|
int fadein, fadeout;
|
|
double hs;
|
|
Vector2 ss, origin;
|
|
SWWMDirectMessage nextmsg; // for chaining messages together from different characters
|
|
bool nextdirect; // skips directly to next message without delays or fades
|
|
Font mSmallFont;
|
|
SWWMHandler hnd;
|
|
transient bool bDontResetMe; // savegame safeguard
|
|
|
|
private int GetRandom()
|
|
{
|
|
return (rss = (rss<<1)*35447+(rss/87));
|
|
}
|
|
|
|
virtual SWWMDirectMessage Init( String chrn, String chrfn, String texn )
|
|
{
|
|
MessageBox = TexMan.CheckForTexture("graphics/HUD/DM/DirectMessageBox.png");
|
|
BG = TexMan.CheckForTexture("graphics/HUD/DM/"..texn.."AvatarBG.png");
|
|
Avatar = TexMan.CheckForTexture("graphics/HUD/DM/"..texn.."Avatar.png");
|
|
for ( int i=0; i<2; i++ )
|
|
Blink[i] = TexMan.CheckForTexture("graphics/HUD/DM/"..texn.."AvatarBlink"..i..".png");
|
|
for ( int i=0; i<5; i++ )
|
|
Talk[i] = TexMan.CheckForTexture("graphics/HUD/DM/"..texn.."AvatarTalk"..i..".png");
|
|
for ( int i=0; i<4; i++ )
|
|
Noiz[i] = TexMan.CheckForTexture("graphics/HUD/DM/DirectMessageStatic"..i..".png");
|
|
chrname = chrn;
|
|
chrfullname = chrfn;
|
|
seqnum = -1;
|
|
charcnt = 0;
|
|
blinktics = 30;
|
|
talktics = 0;
|
|
talkframe = -1;
|
|
startdelay = 30;
|
|
enddelay = 40;
|
|
pausedelay = 30;
|
|
chardelay = 1;
|
|
rss = 1232;
|
|
mSmallFont = Font.GetFont('TewiFont');
|
|
bDontResetMe = true;
|
|
return self;
|
|
}
|
|
|
|
private void SetText()
|
|
{
|
|
String txt;
|
|
if ( (seqnum == 2) && znvspecial )
|
|
{
|
|
// replace with number of years since 2010
|
|
int nyears = SystemTime.Format("%Y",SystemTime.Now()).ToInt()-2010;
|
|
txt = String.Format(StringTable.Localize("$SWWM_"..seqname..seqnum),nyears);
|
|
}
|
|
else txt = StringTable.Localize("$SWWM_"..seqname..seqnum);
|
|
if ( l ) l.Destroy();
|
|
l = mSmallFont.BreakLines(txt,220);
|
|
// if valid, append to the console so the player may re-read this if they want
|
|
if ( (seqnum < 1) || (seqnum > seqcnt) ) return;
|
|
// replace "normal" color reset escapes with chat color escapes
|
|
txt.Replace("\c-","\c*");
|
|
// some messages may have newlines in them, split them
|
|
Array<String> storemsg;
|
|
txt.Split(storemsg,"\n");
|
|
foreach ( msg:storemsg ) Console.PrintfEx(PRINT_CHAT|PRINT_NONOTIFY,chrname.."\c*: "..msg.."\c*");
|
|
}
|
|
|
|
private void DrawText()
|
|
{
|
|
if ( !l ) SetText();
|
|
int cur = charcnt;
|
|
Vector2 pos = origin+(47,3);
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
if ( cur <= 0 ) break;
|
|
String part = l.StringAt(i).Left(cur);
|
|
Screen.DrawText(mSmallFont,Font.CR_WHITE,pos.x,pos.y,part,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
pos.y += 13;
|
|
cur -= l.StringAt(i).Length();
|
|
}
|
|
}
|
|
|
|
private void DrawAvatar( double fractic )
|
|
{
|
|
int blinkframe = -1;
|
|
switch ( blinktics )
|
|
{
|
|
case -1:
|
|
case -3:
|
|
blinkframe = 0;
|
|
break;
|
|
case -2:
|
|
blinkframe = 1;
|
|
break;
|
|
}
|
|
Screen.DrawTexture(BG,false,origin.x+2,origin.y+2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawTexture(Avatar,false,origin.x+2,origin.y+2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
if ( (seqnum > 0) && (seqnum < (seqcnt+1)) )
|
|
{
|
|
if ( blinkframe >= 0 ) Screen.DrawTexture(Blink[blinkframe],false,origin.x+2,origin.y+2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
if ( talkframe >= 0 ) Screen.DrawTexture(Talk[talkframe],false,origin.x+2,origin.y+2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
Screen.DrawTexture(Noiz[int(((gametic+fractic)/GameTicRate)*15)%4],false,origin.x+2,origin.y+2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_LegacyRenderStyle,STYLE_Multiply);
|
|
}
|
|
|
|
private int TotalLength()
|
|
{
|
|
if ( !l ) SetText();
|
|
int len = 0;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
len += l.StringAt(i).Length();
|
|
return len;
|
|
}
|
|
|
|
private String GetChar( int pos )
|
|
{
|
|
if ( !l ) SetText();
|
|
int cur = pos;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
int len = l.StringAt(i).Length();
|
|
if ( cur < len )
|
|
return l.StringAt(i).Mid(cur,1);
|
|
cur -= len;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
private void AdvanceText()
|
|
{
|
|
String notalk = " \t\n,;:.-!?";
|
|
String punctuation = ",;:.";
|
|
if ( charcnt >= TotalLength() )
|
|
{
|
|
seqnum++;
|
|
charcnt = 0;
|
|
if ( (seqnum > seqcnt) && !nextdirect ) S_StartSound("menu/demochat",CHAN_VOICE,CHANF_UI,1.,0.);
|
|
else SetText();
|
|
return;
|
|
}
|
|
String ch = GetChar(charcnt);
|
|
// skip over color escapes
|
|
if ( ch == "\c" )
|
|
{
|
|
ch = GetChar(++charcnt);
|
|
if ( ch == "[" ) while ( (ch = GetChar(++charcnt)) != "]" );
|
|
charcnt++;
|
|
ch = GetChar(charcnt);
|
|
}
|
|
// speech
|
|
if ( notalk.IndexOf(ch) == -1 )
|
|
{
|
|
S_StartSound("misc/voice",CHAN_VOICE,CHANF_UI,.6,ATTN_NONE);
|
|
talktics = 5;
|
|
}
|
|
// delay relative to stuff
|
|
delay = chardelay;
|
|
int idx = punctuation.IndexOf(ch);
|
|
if ( idx >= 0 ) delay += (idx*2)+1;
|
|
charcnt++;
|
|
// utf-8 skipping (naive but works, as we don't have to EXPECT invalid sequences in the input)
|
|
if ( ch.ByteAt(0)&0xE0 == 0xC0 ) charcnt++;
|
|
else if ( ch.ByteAt(0)&0xF0 == 0xE0 ) charcnt += 2;
|
|
else if ( ch.ByteAt(0)&0xF8 == 0xF0 ) charcnt += 3;
|
|
if ( charcnt >= TotalLength() ) delay += (seqnum==seqcnt)?enddelay:pausedelay;
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
// reset when loading from a save, to avoid some wacky nonsense
|
|
if ( !bDontResetMe )
|
|
{
|
|
bDontResetMe = true;
|
|
seqnum = -1;
|
|
delay = 10;
|
|
fadein = fadeout = 0;
|
|
}
|
|
if ( seqnum < 0 )
|
|
{
|
|
// if there's a map message active, wait until it isn't
|
|
if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
if ( hnd.mapmsg ) return false;
|
|
delay--;
|
|
if ( delay <= 0 )
|
|
{
|
|
Console.Printf(StringTable.Localize("$SWWM_INCOMINGMSG"),chrfullname);
|
|
S_StartSound("menu/demochat",CHAN_VOICE,CHANF_UI,1.,0.);
|
|
seqnum++;
|
|
}
|
|
return false;
|
|
}
|
|
if ( blinktics <= 0 )
|
|
{
|
|
blinktics--;
|
|
if ( blinktics < -3 ) blinktics = (abs(GetRandom())%10)?(60+abs(GetRandom())%30):6;
|
|
}
|
|
else blinktics--;
|
|
if ( talktics > 0 )
|
|
{
|
|
if ( !(gametic%3) ) talkframe = (talkframe==-1)?(abs(GetRandom())%5):-1;
|
|
talktics--;
|
|
}
|
|
else talkframe = -1;
|
|
if ( seqnum > (seqcnt+1) )
|
|
{
|
|
if ( nextmsg ) StatusBar.AttachMessage(nextmsg,-1232);
|
|
return true;
|
|
}
|
|
if ( seqnum == 0 )
|
|
{
|
|
fadein++;
|
|
if ( fadein > 15 )
|
|
{
|
|
delay = startdelay;
|
|
seqnum++;
|
|
}
|
|
return false;
|
|
}
|
|
if ( seqnum == (seqcnt+1) )
|
|
{
|
|
if ( nextmsg && nextdirect )
|
|
{
|
|
nextmsg.seqnum = 1;
|
|
nextmsg.bDontResetMe = true;
|
|
StatusBar.AttachMessage(nextmsg,-1232);
|
|
return true;
|
|
}
|
|
fadeout++;
|
|
if ( fadeout > 30 ) seqnum++;
|
|
return false;
|
|
}
|
|
if ( delay > 0 )
|
|
{
|
|
delay--;
|
|
return false;
|
|
}
|
|
AdvanceText();
|
|
return false;
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
if ( (seqnum < 0) || (seqnum > (seqcnt+1)) ) return;
|
|
double alph = 1.;
|
|
double fractic = System.GetTimeFrac();
|
|
if ( seqnum == 0 ) alph = (fadein+fractic)/15.;
|
|
else if ( seqnum == (seqcnt+1) ) alph = 1.-(fadeout+fractic)/30.;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
|
|
}
|
|
origin = (int(ss.x-270)/2,swwm_hudmargin+70);
|
|
Screen.DrawTexture(MessageBox,false,origin.x,origin.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
if ( (seqnum < 1) || (seqnum > seqcnt) ) return;
|
|
DrawAvatar(fractic);
|
|
DrawText();
|
|
}
|
|
}
|
|
|
|
// used to manually trigger dialogues
|
|
// the AMBUSH flag means the dialogue only shows for the activator
|
|
Class SWWMDialogueTrigger : SWWMNonInteractiveActor
|
|
{
|
|
override void Activate( Actor activator )
|
|
{
|
|
if ( !bAMBUSH || (activator && (activator.player == players[consoleplayer])) )
|
|
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue",args[0]);
|
|
Destroy();
|
|
}
|
|
override void Tick() {}
|
|
}
|
|
|
|
// I'm just doing this as an experiment, don't mind me
|
|
|
|
Class DSMapTitle : HUDMessageBase
|
|
{
|
|
Struct FntGlyph
|
|
{
|
|
int x, y, width, height, xofs, yofs, advance;
|
|
};
|
|
|
|
TextureID atlas, atlas_sub;
|
|
FntGlyph glyphs[256], glyphs_sub[256];
|
|
int fheight, fheight_sub;
|
|
|
|
String txt, txtsub;
|
|
int tics, holdtics, fadeintics, fadeouttics;
|
|
int ultics;
|
|
|
|
transient bool bDontDeleteMe; // safeguard for savegames
|
|
|
|
// all the actual hard code
|
|
int MyStringWidth( String str )
|
|
{
|
|
int w = 0;
|
|
int lw = 0;
|
|
int len = str.CodePointCount();
|
|
for ( int i=0, pos=0; i<len; i++ )
|
|
{
|
|
int ch;
|
|
[ch, pos] = str.GetNextCodePoint(pos);
|
|
if ( ch > 255 ) continue;
|
|
lw += glyphs[ch].advance;
|
|
// newline, restart line width
|
|
if ( ch == 0x0a )
|
|
{
|
|
w = max(w,lw);
|
|
lw = 0;
|
|
}
|
|
}
|
|
w = max(w,lw);
|
|
return w;
|
|
}
|
|
int MySubStringWidth( String str )
|
|
{
|
|
int w = 0;
|
|
int lw = 0;
|
|
int len = str.CodePointCount();
|
|
for ( int i=0, pos=0; i<len; i++ )
|
|
{
|
|
int ch;
|
|
[ch, pos] = str.GetNextCodePoint(pos);
|
|
if ( ch > 255 ) continue;
|
|
lw += glyphs_sub[ch].advance;
|
|
// newline, restart line width
|
|
if ( ch == 0x0a )
|
|
{
|
|
w = max(w,lw);
|
|
lw = 0;
|
|
}
|
|
}
|
|
w = max(w,lw);
|
|
return w;
|
|
}
|
|
void MyDrawText( String str, double x, double y, Vector2 ss, double alpha = 1. )
|
|
{
|
|
int len = str.CodePointCount();
|
|
double xx = x;
|
|
double yy = y;
|
|
for ( int i=0, pos=0; i<len; i++ )
|
|
{
|
|
int ch;
|
|
[ch, pos] = str.GetNextCodePoint(pos);
|
|
if ( ch > 255 ) continue;
|
|
if ( glyphs[ch].width && glyphs[ch].height )
|
|
{
|
|
Screen.DrawTexture(atlas,false,xx-glyphs[ch].xofs,yy-glyphs[ch].yofs,
|
|
DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,
|
|
DTA_SrcX,glyphs[ch].x,DTA_SrcY,glyphs[ch].y,
|
|
DTA_SrcWidth,glyphs[ch].width,DTA_SrcHeight,glyphs[ch].height,
|
|
DTA_DestWidth,glyphs[ch].width,DTA_DestHeight,glyphs[ch].height,
|
|
DTA_Alpha,alpha);
|
|
}
|
|
xx += glyphs[ch].advance;
|
|
// newline
|
|
if ( ch == 0x0a )
|
|
{
|
|
xx = x;
|
|
yy += fheight;
|
|
}
|
|
}
|
|
}
|
|
void MySubDrawText( String str, double x, double y, Vector2 ss, double alpha = 1. )
|
|
{
|
|
int len = str.CodePointCount();
|
|
double xx = x;
|
|
double yy = y;
|
|
for ( int i=0, pos=0; i<len; i++ )
|
|
{
|
|
int ch;
|
|
[ch, pos] = str.GetNextCodePoint(pos);
|
|
if ( ch > 255 ) continue;
|
|
if ( glyphs_sub[ch].width && glyphs_sub[ch].height )
|
|
{
|
|
Screen.DrawTexture(atlas_sub,false,xx-glyphs_sub[ch].xofs,yy-glyphs_sub[ch].yofs,
|
|
DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,
|
|
DTA_SrcX,glyphs_sub[ch].x,DTA_SrcY,glyphs_sub[ch].y,
|
|
DTA_SrcWidth,glyphs_sub[ch].width,DTA_SrcHeight,glyphs_sub[ch].height,
|
|
DTA_DestWidth,glyphs_sub[ch].width,DTA_DestHeight,glyphs_sub[ch].height,
|
|
DTA_Alpha,alpha);
|
|
}
|
|
xx += glyphs_sub[ch].advance;
|
|
// newline
|
|
if ( ch == 0x0a )
|
|
{
|
|
xx = x;
|
|
yy += fheight_sub;
|
|
}
|
|
}
|
|
}
|
|
// stretches the "_" glyph over a specific width, center-aligned
|
|
void DrawUnderline( double x, double y, Vector2 ss, double width, double alpha = 1. )
|
|
{
|
|
double xx = x-width/2;
|
|
// l stem
|
|
Screen.DrawTexture(atlas,false,xx-4,y,
|
|
DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,
|
|
DTA_SrcX,glyphs[95].x,DTA_SrcY,glyphs[95].y,
|
|
DTA_SrcWidth,4,DTA_SrcHeight,glyphs[95].height,
|
|
DTA_DestWidthF,4,DTA_DestHeight,glyphs[95].height,
|
|
DTA_Alpha,alpha);
|
|
// long
|
|
Screen.DrawTexture(atlas,false,xx,y,
|
|
DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,
|
|
DTA_SrcX,glyphs[95].x+4,DTA_SrcY,glyphs[95].y,
|
|
DTA_SrcWidth,glyphs[95].width-8,DTA_SrcHeight,glyphs[95].height,
|
|
DTA_DestWidthF,width,DTA_DestHeight,glyphs[95].height,
|
|
DTA_Alpha,alpha);
|
|
// r stem
|
|
Screen.DrawTexture(atlas,false,xx+width,y,
|
|
DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,
|
|
DTA_SrcX,glyphs[95].x+(glyphs[95].width-4),DTA_SrcY,glyphs[95].y,
|
|
DTA_SrcWidth,4,DTA_SrcHeight,glyphs[95].height,
|
|
DTA_DestWidthF,4,DTA_DestHeight,glyphs[95].height,
|
|
DTA_Alpha,alpha);
|
|
}
|
|
|
|
DSMapTitle Init()
|
|
{
|
|
txt = level.levelname;
|
|
txtsub = level.authorname;
|
|
if ( txt.Left(1) == "$" ) txt = StringTable.Localize(txt);
|
|
if ( txtsub.Left(1) == "$" ) txtsub = StringTable.Localize(txtsub);
|
|
// level name may contain trailing whitespace due to DEHACKED nonsense, so strip it
|
|
txt.StripRight();
|
|
int sep;
|
|
if ( (sep = txt.RightIndexOf(" - by: ")) != -1 ) // 20 heretics, spooktober
|
|
{
|
|
txtsub = txt.Mid(sep+7);
|
|
txt.Truncate(sep);
|
|
}
|
|
else if ( (sep = txt.RightIndexOf(" - by ")) != -1 ) // variation seen in DOOMIUM
|
|
{
|
|
txtsub = txt.Mid(sep+6);
|
|
txt.Truncate(sep);
|
|
}
|
|
else if ( (sep = txt.RightIndexOf(" - ")) != -1 ) // hexmas and many others (may cause false positives?)
|
|
{
|
|
txtsub = txt.Mid(sep+3);
|
|
txt.Truncate(sep);
|
|
}
|
|
tics = -10;
|
|
holdtics = 140;
|
|
fadeintics = 20;
|
|
fadeouttics = 40;
|
|
ultics = 50;
|
|
atlas = TexMan.CheckForTexture("graphics/dsmapfont.png");
|
|
if ( !atlas.IsValid() || atlas.IsNull() ) ThrowAbortException("font atlas texture not found");
|
|
let lmp = Wads.CheckNumForFullname("graphics/dsmapfont.txt");
|
|
if ( lmp == -1 ) ThrowAbortException("font definition file not found");
|
|
String dat = Wads.ReadLump(lmp);
|
|
Array<String> list, ln;
|
|
// Windows pls
|
|
dat.Replace("\r","");
|
|
list.Clear();
|
|
dat.Split(list,"\n");
|
|
int ch = 0;
|
|
for ( int i=0; i<list.Size(); i++ )
|
|
{
|
|
if ( (list[i].Length() == 0) || (list[i].Left(2) == "//") || (list[i].Left(1) == "") )
|
|
continue;
|
|
if ( i == 0 )
|
|
{
|
|
// first line is always font height
|
|
fheight = list[i].ToInt();
|
|
continue;
|
|
}
|
|
ln.Clear();
|
|
list[i].Split(ln," ",0);
|
|
glyphs[ch].x = ln[0].ToInt();
|
|
glyphs[ch].y = ln[1].ToInt();
|
|
glyphs[ch].width = ln[2].ToInt();
|
|
glyphs[ch].height = ln[3].ToInt();
|
|
glyphs[ch].xofs = ln[4].ToInt();
|
|
glyphs[ch].yofs = ln[5].ToInt();
|
|
glyphs[ch].advance = ln[6].ToInt();
|
|
ch++;
|
|
}
|
|
if ( ch != 256 ) ThrowAbortException("font definition does not list all 256 glyphs");
|
|
atlas_sub = TexMan.CheckForTexture("graphics/dsmapfont_sub.png");
|
|
if ( !atlas_sub.IsValid() || atlas_sub.IsNull() ) ThrowAbortException("sub font atlas texture not found");
|
|
lmp = Wads.CheckNumForFullname("graphics/dsmapfont_sub.txt");
|
|
if ( lmp == -1 ) ThrowAbortException("sub font definition file not found");
|
|
dat = Wads.ReadLump(lmp);
|
|
// Windows pls
|
|
dat.Replace("\r","");
|
|
list.Clear();
|
|
dat.Split(list,"\n");
|
|
ch = 0;
|
|
for ( int i=0; i<list.Size(); i++ )
|
|
{
|
|
if ( (list[i].Length() == 0) || (list[i].Left(2) == "//") || (list[i].Left(1) == "") )
|
|
continue;
|
|
if ( i == 0 )
|
|
{
|
|
// first line is always font height
|
|
fheight_sub = list[i].ToInt();
|
|
continue;
|
|
}
|
|
ln.Clear();
|
|
list[i].Split(ln," ",0);
|
|
glyphs_sub[ch].x = ln[0].ToInt();
|
|
glyphs_sub[ch].y = ln[1].ToInt();
|
|
glyphs_sub[ch].width = ln[2].ToInt();
|
|
glyphs_sub[ch].height = ln[3].ToInt();
|
|
glyphs_sub[ch].xofs = ln[4].ToInt();
|
|
glyphs_sub[ch].yofs = ln[5].ToInt();
|
|
glyphs_sub[ch].advance = ln[6].ToInt();
|
|
ch++;
|
|
}
|
|
if ( ch != 256 ) ThrowAbortException("sub font definition does not list all 256 glyphs");
|
|
// this is for compat with the dialogues, and should not go into other mods
|
|
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
if ( hnd ) hnd.mapmsg = self;
|
|
bDontDeleteMe = true;
|
|
return self;
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
if ( !bDontDeleteMe ) return true;
|
|
if ( tics == 0 ) S_StartSound("misc/newarea",CHAN_VOICE,CHANF_UI,pitch:.75); // dunno why the source file is pitched up
|
|
return (++tics > holdtics+fadeintics+fadeouttics);
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
if ( tics <= 0 ) return;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
|
|
}
|
|
double fractic = System.GetTimeFrac();
|
|
double ftics = tics+fractic;
|
|
double alpha = (ftics<fadeintics)?(ftics/fadeintics):(ftics<(fadeintics+holdtics))?1.:(1.-(ftics-(fadeintics+holdtics))/fadeouttics);
|
|
int w = MyStringWidth(txt);
|
|
int w2 = MySubStringWidth(txtsub);
|
|
double xx = int(ss.x/2.);
|
|
double yy = int(ss.y/2.)-64.;
|
|
double wfact = clamp(ftics/double(ultics),0.,1.);
|
|
DrawUnderline(xx,yy+1,ss,(w+32)*wfact,alpha);
|
|
MyDrawText(txt,xx-w/2,yy,ss,alpha);
|
|
MySubDrawText(txtsub,xx-w2/2,yy+fheight_sub+12,ss,alpha);
|
|
}
|
|
}
|
|
|
|
// ez weapon selector
|
|
Class SWWMWeaponSelect : HUDMessageBase
|
|
{
|
|
Actor mo;
|
|
Array<Weapon> weaps;
|
|
int cursel;
|
|
double alph, olalph;
|
|
double curY, smoothY, olsmoothY;
|
|
int stage;
|
|
Font fnt;
|
|
|
|
private int CmpWeapon( Weapon a, Weapon b )
|
|
{
|
|
let [dummya, slota] = mo.player.weapons.LocateWeapon(a.GetClass());
|
|
if ( slota == 0 ) slota = 10;
|
|
let [dummyb, slotb] = mo.player.weapons.LocateWeapon(b.GetClass());
|
|
if ( slotb == 0 ) slotb = 10;
|
|
if ( slota == slotb )
|
|
return (a.SlotPriority <= b.SlotPriority);
|
|
return slota > slotb;
|
|
}
|
|
|
|
private int partition_weapons( int l, int h )
|
|
{
|
|
Weapon pv = weaps[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpWeapon(pv,weaps[j]) )
|
|
{
|
|
i++;
|
|
Weapon tmp = weaps[j];
|
|
weaps[j] = weaps[i];
|
|
weaps[i] = tmp;
|
|
}
|
|
}
|
|
Weapon tmp = weaps[h];
|
|
weaps[h] = weaps[i+1];
|
|
weaps[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_weapons( int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_weapons(l,h);
|
|
qsort_weapons(l,p-1);
|
|
qsort_weapons(p+1,h);
|
|
}
|
|
|
|
static clearscope bool PlayerHasWeapons( Actor mo )
|
|
{
|
|
for ( Inventory i=mo.inv; i; i=i.inv )
|
|
{
|
|
if ( !(i is 'Weapon') ) continue;
|
|
let w = Weapon(i);
|
|
if ( !mo.player.weapons.LocateWeapon(w.GetClass()) ) continue;
|
|
if ( (w is 'SWWMWeapon') && SWWMWeapon(w).bHIDEINMENU ) continue;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private double CalcHeight()
|
|
{
|
|
double th = 0.;
|
|
double cur = -1.;
|
|
for ( int i=0; i<weaps.Size(); i++ )
|
|
{
|
|
if ( !weaps[i] ) continue;
|
|
double h = 16.; // padding
|
|
TextureID ico = weaps[i].Icon;
|
|
if ( ico.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(ico);
|
|
if ( weaps[i] is 'SWWMWeapon' ) // SWWM weapon icons are larger
|
|
sz *= .125;
|
|
h += sz.y;
|
|
}
|
|
else h += fnt.GetHeight();
|
|
if ( i == cursel ) cur = th+(h*.5);
|
|
th += h;
|
|
}
|
|
return (cur<0.)?(th*.5):cur;
|
|
}
|
|
|
|
SWWMWeaponSelect Init( Actor mo )
|
|
{
|
|
self.mo = mo;
|
|
// enumerate all selectable weapons
|
|
for ( Inventory i=mo.inv; i; i=i.inv )
|
|
{
|
|
if ( !(i is 'Weapon') ) continue;
|
|
let w = Weapon(i);
|
|
if ( !mo.player.weapons.LocateWeapon(w.GetClass()) ) continue;
|
|
if ( (w is 'SWWMWeapon') && SWWMWeapon(w).bHIDEINMENU ) continue;
|
|
if ( weaps.Find(w) < weaps.Size() ) continue;
|
|
weaps.Push(w);
|
|
}
|
|
// sort weapons
|
|
qsort_weapons(0,weaps.Size()-1);
|
|
// find current selected
|
|
Weapon curweap = mo.player.ReadyWeapon;
|
|
if ( curweap is 'SWWMGesture' ) curweap = SWWMGesture(curweap).formerweapon;
|
|
else if ( curweap is 'SWWMItemGesture' ) curweap = SWWMItemGesture(curweap).gest.formerweapon;
|
|
for ( int i=0; i<weaps.Size(); i++ )
|
|
{
|
|
if ( (weaps[i] != curweap) && (weaps[i].SisterWeapon != curweap) )
|
|
continue;
|
|
cursel = i;
|
|
break;
|
|
}
|
|
// initial state
|
|
S_StartSound("menu/demotab",CHAN_AUTO,CHANF_UI);
|
|
stage = 0;
|
|
alph = 0.;
|
|
fnt = Font.FindFont("TewiFontOutline");
|
|
olsmoothY = smoothY = curY = CalcHeight();
|
|
return self;
|
|
}
|
|
|
|
private void ShowNameTag()
|
|
{
|
|
let bar = SWWMStatusBar(StatusBar);
|
|
if ( !bar ) return;
|
|
let sw = SWWMWeapon(weaps[cursel]);
|
|
if ( sw && sw.SisterWeapon && (sw.Amount > 1) && ((mo.player.ReadyWeapon == sw) || ((mo.player.ReadyWeapon != sw.SisterWeapon) && !swwm_singlefirst)) )
|
|
bar.ntagstr = sw.SisterWeapon.GetTag();
|
|
else bar.ntagstr = weaps[cursel].GetTag();
|
|
bar.ntagtic = level.totaltime;
|
|
bar.ntagcol = nametagcolor;
|
|
}
|
|
|
|
private bool CanScroll()
|
|
{
|
|
double ht = 20.; // extra padding
|
|
if ( weaps[cursel] )
|
|
{
|
|
if ( weaps[cursel].Icon.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(weaps[cursel].Icon);
|
|
if ( weaps[cursel] is 'SWWMWeapon' )
|
|
ht += sz.y*.0625;
|
|
else ht += sz.y*.5;
|
|
}
|
|
else ht += fnt.GetHeight()*.5;
|
|
}
|
|
return (abs(smoothY-curY) < ht);
|
|
}
|
|
|
|
private bool WeaponHasAmmo( Weapon w )
|
|
{
|
|
if ( SWWMWeapon(w) )
|
|
return SWWMWeapon(w).ReportHUDAmmo();
|
|
if ( (!w.Ammo1 || (w.Ammo1.Amount > 0) || w.bAMMO_OPTIONAL) || (w.Ammo2 && ((w.Ammo2.Amount > 0) || w.bALT_AMMO_OPTIONAL)) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void WeapPrev()
|
|
{
|
|
if ( (weaps.Size() <= 1) || !CanScroll() ) return;
|
|
for ( int i=0; i<weaps.Size(); i++ )
|
|
{
|
|
cursel--;
|
|
if ( cursel < 0 ) cursel = weaps.Size()-1;
|
|
if ( WeaponHasAmmo(weaps[cursel]) ) break;
|
|
}
|
|
curY = CalcHeight();
|
|
S_StartSound("menu/demoscroll",CHAN_AUTO,CHANF_UI);
|
|
if ( !weaps[cursel] || !(displaynametags&2) ) return;
|
|
ShowNameTag();
|
|
}
|
|
|
|
void WeapNext()
|
|
{
|
|
if ( (weaps.Size() <= 1) || !CanScroll() ) return;
|
|
for ( int i=0; i<weaps.Size(); i++ )
|
|
{
|
|
cursel++;
|
|
if ( cursel >= weaps.Size() ) cursel = 0;
|
|
if ( WeaponHasAmmo(weaps[cursel]) ) break;
|
|
}
|
|
curY = CalcHeight();
|
|
S_StartSound("menu/demoscroll",CHAN_AUTO,CHANF_UI);
|
|
if ( !weaps[cursel] || !(displaynametags&2) ) return;
|
|
ShowNameTag();
|
|
}
|
|
|
|
void WeapSel()
|
|
{
|
|
if ( !CanScroll() ) return;
|
|
stage = 2;
|
|
if ( !weaps[cursel] ) S_StartSound("menu/democlose",CHAN_AUTO,CHANF_UI|CHANF_OVERLAP);
|
|
else EventHandler.SendNetworkEvent(String.Format("swwmselweapon.%s",weaps[cursel].GetClassName()),mo.PlayerNumber());
|
|
}
|
|
|
|
void WeapCancel()
|
|
{
|
|
if ( !CanScroll() ) return;
|
|
stage = 2;
|
|
S_StartSound("menu/democlose",CHAN_AUTO,CHANF_UI|CHANF_OVERLAP);
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
int oldsiz = weaps.Size();
|
|
bool bChanged = false;
|
|
Weapon oldsel = (weaps.Size()<=0)?null:weaps[cursel];
|
|
for ( int i=0; i<weaps.Size(); i++ )
|
|
{
|
|
if ( weaps[i] && (weaps[i].Owner == mo) ) continue;
|
|
bChanged = true;
|
|
weaps.Delete(i);
|
|
if ( cursel > i ) cursel--;
|
|
i--;
|
|
}
|
|
for ( Inventory i=mo.inv; i; i=i.inv )
|
|
{
|
|
if ( !(i is 'Weapon') ) continue;
|
|
let w = Weapon(i);
|
|
if ( !mo.player.weapons.LocateWeapon(w.GetClass()) ) continue;
|
|
if ( (w is 'SWWMWeapon') && SWWMWeapon(w).bHIDEINMENU ) continue;
|
|
if ( weaps.Find(w) < weaps.Size() ) continue;
|
|
weaps.Push(w);
|
|
bChanged = true;
|
|
}
|
|
if ( cursel >= weaps.Size() ) cursel = max(0,weaps.Size()-1);
|
|
if ( weaps.Size() <= 0 ) stage = 2; // force close if no weapons available
|
|
else if ( bChanged )
|
|
{
|
|
// re-sort and reposition
|
|
qsort_weapons(0,weaps.Size()-1);
|
|
let idx = weaps.Find(oldsel);
|
|
if ( idx < weaps.Size() ) cursel = idx;
|
|
curY = CalcHeight();
|
|
}
|
|
olalph = alph;
|
|
switch ( stage )
|
|
{
|
|
case 0:
|
|
// fade in
|
|
alph += 4./GameTicRate;
|
|
if ( alph >= 1. )
|
|
{
|
|
alph = 1.;
|
|
stage = 1;
|
|
return false;
|
|
}
|
|
break;
|
|
case 1:
|
|
// do nothing
|
|
break;
|
|
case 2:
|
|
// fade out
|
|
alph -= 6./GameTicRate;
|
|
if ( alph <= 0. )
|
|
{
|
|
PPShader.SetEnabled("BokehSel",false); // clear the shader
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
// smooth scroll
|
|
olsmoothY = smoothY;
|
|
smoothY = smoothY*.8+curY*.2;
|
|
double hs;
|
|
if ( SWWMStatusBar(StatusBar) ) hs = SWWMStatusBar(StatusBar).hs;
|
|
else hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
if ( abs(smoothY-curY) < (1./hs) ) smoothY = curY;
|
|
return false;
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
double fractic = System.GetTimeFrac();
|
|
double ssmoothY = SWWMUtility.Lerp(olsmoothY,smoothY,fractic);
|
|
double salph = SWWMUtility.Lerp(olalph,alph,fractic);
|
|
if ( swwm_shaders )
|
|
{
|
|
PPShader.SetEnabled("BokehSel",true);
|
|
PPShader.SetUniform1f("BokehSel","strength",salph);
|
|
}
|
|
Screen.Dim("Black",.4*salph,0,0,Screen.GetWidth(),Screen.GetHeight());
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
|
|
}
|
|
Vector2 hss = ss*.5;
|
|
double x = Screen.GetWidth()*.5;
|
|
double y = hss.y-ssmoothY;
|
|
for ( int i=0; i<weaps.Size(); i++ )
|
|
{
|
|
if ( !weaps[i] ) continue;
|
|
let w = weaps[i];
|
|
let sw = SWWMWeapon(weaps[i]);
|
|
double scl = sw?.125:1.;
|
|
y += 8.;
|
|
double fade = clamp(.8-abs(y-hss.y)/hss.y,0.,.8)/.8;
|
|
bool bHasAmmo = WeaponHasAmmo(w);
|
|
TextureID ico = w.Icon;
|
|
if ( ico.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(ico);
|
|
y += sz.y*scl*.5;
|
|
if ( sw && sw.SisterWeapon && (sw.Amount > 1) && ((mo.player.ReadyWeapon == sw) || ((mo.player.ReadyWeapon != sw.SisterWeapon) && !swwm_singlefirst)) )
|
|
{
|
|
// double draw
|
|
Screen.DrawTexture(ico,false,x-(4.*hs),(y-4.)*hs,DTA_ScaleX,scl*hs,DTA_ScaleY,scl*hs,DTA_Alpha,salph*fade,DTA_CenterOffset,true,DTA_Color,bHasAmmo?0xFFFFFFFF:0xFF800000,DTA_ColorOverlay,(i==cursel)?0x00000000:0x80000000);
|
|
Screen.DrawTexture(ico,false,x+(4.*hs),(y+4.)*hs,DTA_ScaleX,scl*hs,DTA_ScaleY,scl*hs,DTA_Alpha,salph*fade,DTA_CenterOffset,true,DTA_Color,bHasAmmo?0xFFFFFFFF:0xFF800000,DTA_ColorOverlay,(i==cursel)?0x00000000:0x80000000);
|
|
}
|
|
else Screen.DrawTexture(ico,false,x,y*hs,DTA_ScaleX,scl*hs,DTA_ScaleY,scl*hs,DTA_Alpha,salph*fade,DTA_CenterOffset,true,DTA_Color,bHasAmmo?0xFFFFFFFF:0xFF800000,DTA_ColorOverlay,(i==cursel)?0x00000000:0x80000000);
|
|
if ( i == cursel )
|
|
{
|
|
Screen.DrawChar(fnt,Font.CR_FIRE,x-((sz.x*scl*.5+16.+2.*sin((gametic+fractic)*8.))*hs),y*hs,0x25BA,DTA_ScaleX,hs,DTA_ScaleY,hs,DTA_Alpha,salph*fade,DTA_CenterOffset,true);
|
|
Screen.DrawChar(fnt,Font.CR_FIRE,x+((sz.x*scl*.5+16.+2.*sin((gametic+fractic)*8.))*hs),y*hs,0x25C4,DTA_ScaleX,hs,DTA_ScaleY,hs,DTA_Alpha,salph*fade,DTA_CenterOffset,true);
|
|
}
|
|
y += sz.y*scl*.5;
|
|
}
|
|
else
|
|
{
|
|
String label = "?WeaponName?";
|
|
if ( sw && sw.SisterWeapon && (sw.Amount > 1) && ((mo.player.ReadyWeapon == sw) || ((mo.player.ReadyWeapon != sw.SisterWeapon) && !swwm_singlefirst)) )
|
|
label = sw.SisterWeapon.GetTag();
|
|
else label = w.GetTag();
|
|
Vector2 sz = (fnt.StringWidth(label),fnt.GetHeight());
|
|
Screen.DrawText(fnt,bHasAmmo?Font.CR_WHITE:Font.CR_RED,x-sz.x*.5*hs,y*hs,label,DTA_ScaleX,hs,DTA_ScaleY,hs,DTA_Alpha,salph*fade,DTA_ColorOverlay,(i==cursel)?0x00000000:0x80000000);
|
|
y += sz.y*.5;
|
|
if ( i == cursel )
|
|
{
|
|
Screen.DrawChar(fnt,Font.CR_FIRE,x-((sz.x*.5+16.+2.*sin((gametic+fractic)*8.))*hs),y*hs,0x25BA,DTA_ScaleX,hs,DTA_ScaleY,hs,DTA_Alpha,salph*fade,DTA_CenterOffset,true);
|
|
Screen.DrawChar(fnt,Font.CR_FIRE,x+((sz.x*.5+16.+2.*sin((gametic+fractic)*8.))*hs),y*hs,0x25C4,DTA_ScaleX,hs,DTA_ScaleY,hs,DTA_Alpha,salph*fade,DTA_CenterOffset,true);
|
|
}
|
|
y += sz.y*.5;
|
|
}
|
|
y += 8.;
|
|
}
|
|
}
|
|
}
|