swwmgz_m/zscript/hud/swwm_hudextra.zsc

822 lines
25 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 = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
Vector2 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 = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
Vector2 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 = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
Vector2 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);
// append to the player's chat log (if it's valid)
if ( (seqnum < 1) || (seqnum > seqcnt) ) return;
// some messages may have newlines in them, split them
Array<String> storemsg;
txt.Split(storemsg,"\n");
foreach ( msg:storemsg )
{
EventHandler.SendNetworkEvent("swwmstoremessage."..chrname..": "..msg,level.totaltime,PRINT_CHAT,consoleplayer);
// stick it into the console as well
Console.PrintfEx(PRINT_CHAT|PRINT_NONOTIFY,chrname..": "..msg);
}
}
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.;
double 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);
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;
// fucking Windows
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);
// fucking Windows
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 = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
Vector2 ss = (Screen.GetWidth(),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);
}
}