- Try to get rid of all implicit casts from string to name, color or class. - Use FindClass where needed. - Used a map in a case where a dictionary was unneeded. - Use new bounce flags where needed. - Replace Legacy of Rust weapons/ammo.
1611 lines
47 KiB
Text
1611 lines
47 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 ymargin;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
ymargin = SWWMStatusBar(StatusBar).ymargin0;
|
|
hs = SWWMStatusBar(StatusBar).hs0;
|
|
ss = SWWMStatusBar(StatusBar).ss0;
|
|
}
|
|
else
|
|
{
|
|
ymargin = clamp(swwm_hudmargin,0,10);
|
|
hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
ss = (Screen.GetWidth()/hs,Screen.GetHeight()/hs);
|
|
}
|
|
ymargin += 10;
|
|
if ( whichline == "" ) return; // don't draw empty strings
|
|
// split so it can fit
|
|
if ( !l ) l = mSmallFont.BreakLines(whichline,int(min(ss.x,ss.y/.5625)*.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(0xFF000000,alph*.8,int((Screen.GetWidth()-(maxlen+12)*hs)/2.),int(bottom-(ymargin+2+fh)*hs),int((maxlen+12)*hs),int((fh+4)*hs));
|
|
int yy = ymargin+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 && !viewactive) || (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);
|
|
}
|
|
}
|
|
|
|
// 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 ymargin;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
ymargin = SWWMStatusBar(StatusBar).ymargin;
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
ymargin = clamp(swwm_hudmargin,0,10);
|
|
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-(ymargin+36))+int(ymargin+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 swap prompt
|
|
Class SWWMWeaponSwapTip : HUDMessageBase
|
|
{
|
|
Inventory wa, wb;
|
|
SWWMWeapon swa, swb;
|
|
bool duala, dualb;
|
|
String wpna, wpnb, txt;
|
|
transient BrokenLines l;
|
|
double tics, holdtics, fadeintics, fadeouttics;
|
|
TextureID icoa, icob;
|
|
Font mSmallFont;
|
|
|
|
// just code deduplication here
|
|
private void UpdateMe( Inventory fromweapon, Inventory toweapon )
|
|
{
|
|
wa = fromweapon;
|
|
swa = SWWMWeapon(wa);
|
|
if ( !swa ) ThrowAbortException("swap from (%s) is not SWWMWeapon",wa?wa.GetClassName():'Null');
|
|
// are we swapping from a dual weapon?
|
|
if ( swa.SisterWeapon && (swa.Amount>1) )
|
|
{
|
|
wpna = swa.SisterWeapon.GetTag();
|
|
icoa = GetIcon(swa.SisterWeapon);
|
|
duala = true;
|
|
}
|
|
else
|
|
{
|
|
wpna = swa.GetTag();
|
|
icoa = GetIcon(swa);
|
|
duala = false;
|
|
}
|
|
wb = toweapon;
|
|
// are we swapping to a dual weapon?
|
|
if ( wb is 'SWWMDualWeaponGiver' )
|
|
{
|
|
swb = SWWMDualWeaponGiver(wb).giveme[0];
|
|
wpnb = wb.GetTag();
|
|
icob = GetIcon(swb);
|
|
dualb = true;
|
|
}
|
|
else if ( wb is 'SWWMWeapon' )
|
|
{
|
|
swb = SWWMWeapon(wb);
|
|
wpnb = swb.GetTag();
|
|
icob = GetIcon(swb);
|
|
dualb = false;
|
|
}
|
|
else ThrowAbortException("swap to (%s) is not SWWMWeapon or SWWMDualWeaponGiver",wb?wb.GetClassName():'Null');
|
|
txt = String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),wpna,wpnb);
|
|
if ( l ) l.Destroy();
|
|
}
|
|
|
|
private TextureID GetIcon( Weapon w )
|
|
{
|
|
let [ico, applyScale] = StatusBar.GetInventoryIcon(w,StatusBar.DI_SKIPALTICON|StatusBar.DI_SKIPREADY);
|
|
return ico;
|
|
}
|
|
|
|
SWWMWeaponSwapTip Init( Inventory fromweapon, Inventory toweapon )
|
|
{
|
|
UpdateMe(fromweapon,toweapon);
|
|
holdtics = 50;
|
|
fadeintics = 5;
|
|
fadeouttics = 15;
|
|
tics = 0;
|
|
mSmallFont = Font.GetFont('TewiFont');
|
|
return self;
|
|
}
|
|
|
|
// used by weapons when an existing tip is already there
|
|
void Poke( Inventory fromweapon, Inventory toweapon )
|
|
{
|
|
// update icons and text if different weapons
|
|
if ( (fromweapon != wa) || (toweapon != wb) )
|
|
UpdateMe(fromweapon,toweapon);
|
|
// invert the fade out into a fade-in
|
|
// otherwise just wind the tics back to right after fade-in
|
|
if ( tics > (fadeintics+holdtics) )
|
|
tics = fadeintics-(tics-(fadeintics+holdtics))/(fadeouttics/fadeintics);
|
|
else if ( tics > fadeintics )
|
|
tics = fadeintics;
|
|
}
|
|
|
|
// used by weapons when the swap has already happened
|
|
void Expire( Inventory fromweapon, Inventory toweapon )
|
|
{
|
|
// just forces a fade out
|
|
if ( (fromweapon == wa) && (toweapon == wb) )
|
|
tics = max(tics,fadeintics+holdtics);
|
|
}
|
|
|
|
override bool Tick()
|
|
{
|
|
tics++;
|
|
return (tics > holdtics+fadeintics+fadeouttics);
|
|
}
|
|
|
|
override void Draw( int bottom, int visibility )
|
|
{
|
|
if ( tics <= 0 ) return;
|
|
double ymargin;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
ymargin = SWWMStatusBar(StatusBar).ymargin0;
|
|
hs = SWWMStatusBar(StatusBar).hs0;
|
|
ss = SWWMStatusBar(StatusBar).ss0;
|
|
}
|
|
else
|
|
{
|
|
ymargin = clamp(swwm_hudmargin,0,10);
|
|
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);
|
|
if ( !l ) l = mSmallFont.BreakLines(txt,600);
|
|
int txtw = 0;
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
{
|
|
let lw = mSmallFont.StringWidth(l.StringAt(i));
|
|
if ( lw > txtw ) txtw = lw;
|
|
}
|
|
int icow = 16;
|
|
int icoh = mSmallFont.GetHeight()*2;
|
|
if ( icoa.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(icoa)*.125;
|
|
icow += int(sz.x)+(duala?12:4);
|
|
icoh = int(sz.y)+(duala?12:4);
|
|
}
|
|
else icow += mSmallFont.StringWidth(wpna);
|
|
if ( icob.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(icob)*.125;
|
|
icow += int(sz.x)+(dualb?12:4);
|
|
icoh = max(icoh,int(sz.y)+(dualb?12:4));
|
|
}
|
|
else
|
|
{
|
|
icow += mSmallFont.StringWidth(wpnb);
|
|
icoh = max(icoh,mSmallFont.GetHeight());
|
|
}
|
|
int w = max(txtw,icow);
|
|
int h = icoh+4+mSmallFont.GetHeight()*l.Count();
|
|
Vector2 pos = (int(ss.x/2),ss.y-(ymargin+80+h));
|
|
Screen.Dim(0xFF000000,.5*alpha,int((pos.x-(w+4)/2)*hs),int((pos.y-2)*hs),int((w+4)*hs),int((h+4)*hs));
|
|
// Left Icon
|
|
double x = pos.x-(icow/2);
|
|
if ( icoa.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(icoa)*.125;
|
|
if ( duala )
|
|
{
|
|
x += sz.x/2+6;
|
|
Screen.DrawTexture(icoa,false,(x-4)*hs,((pos.y+icoh/2)-4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true);
|
|
Screen.DrawTexture(icoa,false,(x+4)*hs,((pos.y+icoh/2)+4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true);
|
|
x += sz.x/2+6;
|
|
}
|
|
else
|
|
{
|
|
x += sz.x/2+2;
|
|
Screen.DrawTexture(icoa,false,x*hs,(pos.y+icoh/2)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true);
|
|
x += sz.x/2+2;
|
|
}
|
|
}
|
|
// Swap Arrow
|
|
String arr = "→";
|
|
Screen.DrawText(mSmallFont,Font.CR_GREEN,x+(16-mSmallFont.StringWidth(arr))/2,pos.y+(icoh/2-mSmallFont.GetHeight()),arr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
arr = "←";
|
|
Screen.DrawText(mSmallFont,Font.CR_GREEN,x+(16-mSmallFont.StringWidth(arr))/2,pos.y+(icoh/2),arr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
x += 16;
|
|
// Right Icon
|
|
if ( icob.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(icob)*.125;
|
|
if ( dualb )
|
|
{
|
|
x += sz.x/2+6;
|
|
Screen.DrawTexture(icob,false,(x-4)*hs,((pos.y+icoh/2)-4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true);
|
|
Screen.DrawTexture(icob,false,(x+4)*hs,((pos.y+icoh/2)+4)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true);
|
|
}
|
|
else
|
|
{
|
|
x += sz.x/2+2;
|
|
Screen.DrawTexture(icob,false,x*hs,(pos.y+icoh/2)*hs,DTA_ScaleX,.125*hs,DTA_ScaleY,.125*hs,DTA_Alpha,alpha,DTA_CenterOffset,true);
|
|
}
|
|
}
|
|
// Swap Message
|
|
for ( int i=0; i<l.Count(); i++ )
|
|
Screen.DrawText(mSmallFont,Font.CR_WHITE,pos.x-mSmallFont.StringWidth(l.StringAt(i))/2,pos.y+icoh+4+i*mSmallFont.GetHeight(),l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha);
|
|
}
|
|
}
|
|
|
|
// 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 ymargin;
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
ymargin = SWWMStatusBar(StatusBar).ymargin0;
|
|
hs = SWWMStatusBar(StatusBar).hs0;
|
|
ss = SWWMStatusBar(StatusBar).ss0;
|
|
}
|
|
else
|
|
{
|
|
ymargin = clamp(swwm_hudmargin,0,10);
|
|
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-(ymargin+80+h));
|
|
Screen.Dim(0xFF000000,.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;
|
|
int ymargin;
|
|
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) )
|
|
{
|
|
ymargin = SWWMStatusBar(StatusBar).ymargin;
|
|
hs = SWWMStatusBar(StatusBar).hs;
|
|
ss = SWWMStatusBar(StatusBar).ss;
|
|
}
|
|
else
|
|
{
|
|
ymargin = clamp(swwm_hudmargin,0,10);
|
|
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,ymargin+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 abstract
|
|
{
|
|
override void Activate( Actor activator )
|
|
{
|
|
// this is a huge gross hack that only exists because you can't get arg0str out of actors
|
|
// (primarily, because you can convert names to ints, but not viceversa)
|
|
String dlg = GetClassName();
|
|
dlg.StripLeft('SWWMDialogueTrigger');
|
|
if ( !bAMBUSH || (activator && (activator.player == players[consoleplayer])) )
|
|
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue."..dlg);
|
|
Destroy();
|
|
}
|
|
override void Tick() {}
|
|
}
|
|
|
|
Class SWWMDialogueTriggerGOTCHAEND : SWWMDialogueTrigger {}
|
|
Class SWWMDialogueTriggerSpcEV2BCD : SWWMNonInteractiveActor
|
|
{
|
|
Actor thecaco;
|
|
int spcstate;
|
|
|
|
// this one is very special, yup
|
|
override void PostBeginPlay()
|
|
{
|
|
// the one singular astral cacodemon in this map
|
|
// needed for everything
|
|
let cacoclass = (Class<Actor>)(FindClass('AstralCacodemon','Actor'));
|
|
if ( cacoclass ) thecaco = Actor(ThinkerIterator.Create(cacoclass).Next());
|
|
if ( !thecaco )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( !thecaco || (thecaco.Health <= 0) )
|
|
{
|
|
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2D");
|
|
Destroy();
|
|
return;
|
|
}
|
|
double dist;
|
|
switch ( spcstate )
|
|
{
|
|
case 0:
|
|
// check that the player is close to the astral cacodemon
|
|
dist = (thecaco.pos.xy-players[consoleplayer].mo.pos.xy).length();
|
|
if ( dist < 1024 )
|
|
{
|
|
spcstate++;
|
|
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2B");
|
|
}
|
|
break;
|
|
case 1:
|
|
// wait until the astral caco leaves its spawn position
|
|
dist = (thecaco.pos.xy-thecaco.spawnpoint.xy).length();
|
|
if ( dist > 64 ) spcstate++;
|
|
break;
|
|
case 2:
|
|
// check that the player is close to where the astral cacodemon originally was
|
|
dist = (thecaco.spawnpoint.xy-players[consoleplayer].mo.pos.xy).length();
|
|
if ( dist < 1024 )
|
|
{
|
|
spcstate++;
|
|
EventHandler.SendInterfaceEvent(consoleplayer,"swwmsetdialogue.EV2C");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Class SWWMDialogueTriggerEV2J : SWWMDialogueTrigger {}
|
|
|
|
// 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;
|
|
bool hasnewline;
|
|
int tics, holdtics, fadeintics, fadeouttics;
|
|
int ultics;
|
|
|
|
transient bool bDontDeleteMe; // safeguard for savegames
|
|
|
|
bool bTxtIsSplit;
|
|
Array<String> txt_split;
|
|
Array<int> txtwidth_split;
|
|
int txtmaxwidth_split;
|
|
|
|
// 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;
|
|
}
|
|
void MyStringBreak( String str, int maxw )
|
|
{
|
|
bTxtIsSplit = true;
|
|
txt_split.Clear();
|
|
txtwidth_split.Clear();
|
|
txtmaxwidth_split = 0;
|
|
int cur = 0;
|
|
int w = 0;
|
|
int len = str.CodePointCount();
|
|
bool wasspace = false;
|
|
bool leftspace = false;
|
|
int lastspace = 0, pastspace = 0;
|
|
for ( int i=0, pos=0; i<len; i++ )
|
|
{
|
|
int oldpos = pos;
|
|
int ch;
|
|
[ch, pos] = str.GetNextCodePoint(pos);
|
|
if ( (ch == 0x09) || (ch == 0x0A) || (ch == 0x0D) || (ch == 0x20) )
|
|
{
|
|
if ( leftspace )
|
|
{
|
|
if ( ch == 0x0A )
|
|
{
|
|
txt_split.Push("");
|
|
txtwidth_split.Push(0);
|
|
}
|
|
continue;
|
|
}
|
|
if ( !wasspace )
|
|
{
|
|
lastspace = oldpos;
|
|
wasspace = true;
|
|
}
|
|
pastspace = pos;
|
|
}
|
|
else
|
|
{
|
|
wasspace = false;
|
|
leftspace = false;
|
|
}
|
|
int cw = (ch>255)?0:glyphs[ch].advance;
|
|
bool endof = ((i+1)>=len);
|
|
if ( (ch != 0x0A) && !endof && ((w <= 0) || (w+cw <= maxw)) )
|
|
{
|
|
w += cw;
|
|
continue;
|
|
}
|
|
String sstr = str.Mid(cur,endof?int.max:(lastspace-cur));
|
|
int lw = MyStringWidth(sstr);
|
|
txt_split.Push(sstr);
|
|
txtwidth_split.Push(lw);
|
|
if ( lw > txtmaxwidth_split ) txtmaxwidth_split = lw;
|
|
w = 0;
|
|
wasspace = false;
|
|
cur = pastspace;
|
|
lastspace = 0;
|
|
pastspace = 0;
|
|
leftspace = true;
|
|
}
|
|
}
|
|
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);
|
|
// may contain color escapes, which we don't support here
|
|
SWWMUtility.StripColor(txt);
|
|
SWWMUtility.StripColor(txtsub);
|
|
// level name may contain trailing whitespace due to DEHACKED nonsense, so strip it
|
|
txt.StripRight();
|
|
if ( txtsub == "" ) // if we already have an author name, don't do this stuff
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
hasnewline = (txt.IndexOf("\n") != -1);
|
|
bTxtIsSplit = false;
|
|
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 void ScreenSizeChanged()
|
|
{
|
|
// force line re-break
|
|
bTxtIsSplit = false;
|
|
}
|
|
|
|
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
|
|
if ( (tics == holdtics+fadeintics) && (txt == "Go Fuck Yourself") ) // Sunlust MAP29
|
|
Eventhandler.SendNetworkEvent("swwmlustysuns",consoleplayer);
|
|
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);
|
|
double xx = int(ss.x/2.);
|
|
double yy = int(ss.y/2.)-64.;
|
|
double wfact = clamp(ftics/double(ultics),0.,1.);
|
|
int wsub = MySubStringWidth(txtsub);
|
|
int w = MyStringWidth(txt);
|
|
int capw = int(min(ss.x,ss.y/.5625)-250); // limit to 16:9, avoids super-long text in ultrawide
|
|
if ( (w < capw) && !hasnewline )
|
|
{
|
|
DrawUnderline(xx,yy+1,ss,(w+32)*wfact,alpha);
|
|
MyDrawText(txt,xx-w/2,yy,ss,alpha);
|
|
MySubDrawText(txtsub,xx-wsub/2,yy+fheight_sub+12,ss,alpha);
|
|
return;
|
|
}
|
|
if ( !bTxtIsSplit ) MyStringBreak(txt,capw);
|
|
yy += (fheight/2)*(txt_split.Size()-1);
|
|
DrawUnderline(xx,yy+1,ss,(txtmaxwidth_split+32)*wfact,alpha);
|
|
yy -= fheight*txt_split.Size();
|
|
for ( int i=0; i<txt_split.Size(); i++ )
|
|
{
|
|
yy += fheight;
|
|
MyDrawText(txt_split[i],xx-txtwidth_split[i]/2,yy,ss,alpha);
|
|
}
|
|
MySubDrawText(txtsub,xx-wsub/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, idxa] = mo.player.weapons.LocateWeapon(a.GetClass());
|
|
if ( slota == 0 ) slota = 10;
|
|
let [dummyb, slotb, idxb] = mo.player.weapons.LocateWeapon(b.GetClass());
|
|
if ( slotb == 0 ) slotb = 10;
|
|
if ( slota == slotb )
|
|
return idxa > idxb;
|
|
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 TextureID GetIcon( Weapon w )
|
|
{
|
|
let [ico, applyScale] = StatusBar.GetInventoryIcon(w,StatusBar.DI_SKIPALTICON|StatusBar.DI_SKIPREADY);
|
|
return ico;
|
|
}
|
|
|
|
private double GetHeight( Weapon w )
|
|
{
|
|
double h = 16.; // padding
|
|
TextureID ico = GetIcon(w);
|
|
if ( ico.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(ico);
|
|
if ( w is 'SWWMWeapon' ) // SWWM weapon icons are larger
|
|
sz *= .125;
|
|
h += sz.y;
|
|
}
|
|
else h += fnt.GetHeight();
|
|
return h;
|
|
}
|
|
|
|
private double CalcHeight( bool bGetTotal = false )
|
|
{
|
|
double th = 0.;
|
|
double cur = -1.;
|
|
for ( int i=0; i<weaps.Size(); i++ )
|
|
{
|
|
if ( !weaps[i] ) continue;
|
|
double h = GetHeight(weaps[i]);
|
|
if ( i == cursel ) cur = th+(h*.5);
|
|
th += h;
|
|
}
|
|
if ( bGetTotal ) return th;
|
|
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] )
|
|
{
|
|
TextureID ico = GetIcon(weaps[cursel]);
|
|
if ( ico.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(ico);
|
|
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 )
|
|
{
|
|
double fh = CalcHeight(true);
|
|
smoothY += fh;
|
|
olsmoothY += fh;
|
|
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() )
|
|
{
|
|
double fh = CalcHeight(true);
|
|
smoothY -= fh;
|
|
olsmoothY -= fh;
|
|
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()
|
|
{
|
|
// automatically close if disabled or player changes weapons through other means
|
|
if ( (!swwm_useweaponbar || (mo.player.PendingWeapon != WP_NOCHANGE)) && (stage != 2) )
|
|
{
|
|
stage = 2;
|
|
S_StartSound("menu/clear",CHAN_AUTO,CHANF_UI|CHANF_OVERLAP);
|
|
}
|
|
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. ) return true;
|
|
break;
|
|
}
|
|
// smooth scroll
|
|
olsmoothY = smoothY;
|
|
smoothY = smoothY*.8+curY*.2;
|
|
double hs;
|
|
if ( SWWMStatusBar(StatusBar) ) hs = SWWMStatusBar(StatusBar).hs0;
|
|
else hs = max(min(floor(Screen.GetWidth()/640.),floor(Screen.GetHeight()/360.)),1.);
|
|
if ( abs(smoothY-curY) < (1./hs) ) smoothY = curY;
|
|
return false;
|
|
}
|
|
|
|
// simplify some code here
|
|
private bool DrawWeapon( Weapon w, int i, double x, double &y, double hs, Vector2 hss, double salph, double fractic, bool bOverflow = false, bool bUpward = false )
|
|
{
|
|
let sw = SWWMWeapon(w);
|
|
double scl = sw?.125:1.;
|
|
y += bUpward?-8.:8.;
|
|
bool bHasAmmo = WeaponHasAmmo(w);
|
|
TextureID ico = GetIcon(w);
|
|
double fade = 0.;
|
|
if ( ico.IsValid() )
|
|
{
|
|
Vector2 sz = TexMan.GetScaledSize(ico);
|
|
y += sz.y*scl*(bUpward?-.5:.5);
|
|
fade = clamp(.8-abs(y-hss.y)/hss.y,0.,.8)/.8;
|
|
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)&&!bOverflow)?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)&&!bOverflow)?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)&&!bOverflow)?0x00000000:0x80000000);
|
|
if ( (i == cursel) && !bOverflow )
|
|
{
|
|
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*(bUpward?-.5:.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());
|
|
fade = clamp(.8-abs((bUpward?(y-sz.y*.5):y+sz.y*.5)-hss.y)/hss.y,0.,.8)/.8;
|
|
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)&&!bOverflow)?0x00000000:0x80000000);
|
|
y += sz.y*(bUpward?-.5:.5);
|
|
if ( (i == cursel) && !bOverflow )
|
|
{
|
|
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*(bUpward?-.5:.5);
|
|
}
|
|
y += bUpward?-8.:8.;
|
|
return (fade <= 0.);
|
|
}
|
|
|
|
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);
|
|
Screen.Dim(0xFF000000,.4*salph,0,0,Screen.GetWidth(),Screen.GetHeight());
|
|
double hs;
|
|
Vector2 ss;
|
|
if ( SWWMStatusBar(StatusBar) )
|
|
{
|
|
hs = SWWMStatusBar(StatusBar).hs0;
|
|
ss = SWWMStatusBar(StatusBar).ss0;
|
|
}
|
|
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;
|
|
int i;
|
|
for ( i=0; i<weaps.Size(); i++ )
|
|
{
|
|
if ( !weaps[i] ) continue;
|
|
DrawWeapon(weaps[i],i,x,y,hs,hss,salph,fractic);
|
|
}
|
|
// continue drawing downwards until alpha is zero
|
|
i = 0;
|
|
while ( !DrawWeapon(weaps[i],i,x,y,hs,hss,salph,fractic,true) )
|
|
{
|
|
if ( ++i >= weaps.Size() ) i = 0;
|
|
}
|
|
// reposition and draw upwards until alpha is zero
|
|
y = hss.y-ssmoothY;
|
|
i = weaps.Size()-1;
|
|
while ( !DrawWeapon(weaps[i%weaps.Size()],i%weaps.Size(),x,y,hs,hss,salph,fractic,true,true) )
|
|
{
|
|
if ( --i < 0 ) i = weaps.Size()-1;
|
|
}
|
|
|
|
}
|
|
}
|