376 lines
15 KiB
Text
376 lines
15 KiB
Text
// The SWWM GZ HUD is mostly built on top of what I had already done for SWWM Z, also a bit of Dark Souls
|
|
|
|
Class MsgLine
|
|
{
|
|
String str;
|
|
int tic, type, rep;
|
|
}
|
|
|
|
Class SWWMStatusBar : BaseStatusBar
|
|
{
|
|
TextureID StatusTex, WeaponTex, ScoreTex, InventoryTex, ChatTex[6],
|
|
HealthTex[4], FuelTex, DashTex;
|
|
HUDFont mTewiFont;
|
|
|
|
// "Full History" contains all messages since session start, nothing is flushed
|
|
// this can be accessed from a section of the knowledge base
|
|
Array<MsgLine> MainQueue, PickupQueue, FullHistory;
|
|
Actor targetactors[40], scoreactors[60], keyactors[10];
|
|
Vector3 exitpoints[10], uselines[10];
|
|
|
|
// client cvars
|
|
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol;
|
|
|
|
// shared stuff
|
|
Vector2 ss, hs;
|
|
int margin;
|
|
double FracTic;
|
|
int chatopen;
|
|
|
|
DynamicValueInterpolator HealthInter, ScoreInter, FuelInter, DashInter;
|
|
|
|
override void FlushNotify()
|
|
{
|
|
// flush non-chat messages
|
|
for ( int i=0; i<MainQueue.Size(); i++ )
|
|
{
|
|
if ( MainQueue[i].type >= PRINT_CHAT ) continue;
|
|
MainQueue.Delete(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
override bool ProcessNotify( EPrintLevel printlevel, String outline )
|
|
{
|
|
let m = new("MsgLine");
|
|
m.str = outline.Left(outline.Length()-1); // strip newline
|
|
m.type = printlevel;
|
|
m.tic = gametic;
|
|
m.rep = 1;
|
|
// append chat messages to full history
|
|
if ( (printlevel == PRINT_CHAT) || (printlevel == PRINT_TEAMCHAT) )
|
|
FullHistory.Push(m);
|
|
// ignore during intermission
|
|
if ( gamestate != GS_LEVEL ) return false;
|
|
if ( (printlevel < PRINT_LOW) || (printlevel > PRINT_TEAMCHAT) ) return true; // we couldn't care less about these
|
|
if ( printlevel == PRINT_LOW )
|
|
{
|
|
// check if repeated
|
|
for ( int i=0; i<PickupQueue.Size(); i++ )
|
|
{
|
|
if ( PickupQueue[i].str != m.str ) continue;
|
|
// delete old one and add its repeats
|
|
m.rep += PickupQueue[i].rep;
|
|
PickupQueue.Delete(i);
|
|
break;
|
|
}
|
|
PickupQueue.Push(m);
|
|
}
|
|
else
|
|
{
|
|
// check if repeated
|
|
for ( int i=0; i<MainQueue.Size(); i++ )
|
|
{
|
|
if ( MainQueue[i].str != m.str ) continue;
|
|
// delete old one and add its repeats
|
|
m.rep += MainQueue[i].rep;
|
|
MainQueue.Delete(i);
|
|
break;
|
|
}
|
|
MainQueue.Push(m);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( !chatduration ) chatduration = CVar.GetCVar('swwm_chatduration',players[consoleplayer]);
|
|
if ( !msgduration ) msgduration = CVar.GetCVar('swwm_msgduration',players[consoleplayer]);
|
|
if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]);
|
|
Super.Tick();
|
|
// prune old messages
|
|
for ( int i=0; i<PickupQueue.Size(); i++ )
|
|
{
|
|
if ( gametic < (PickupQueue[i].tic+pickduration.GetInt()) ) continue;
|
|
PickupQueue.Delete(i);
|
|
i--;
|
|
}
|
|
for ( int i=0; i<MainQueue.Size(); i++ )
|
|
{
|
|
if ( (MainQueue[i].type <= PRINT_HIGH) && (gametic < (MainQueue[i].tic+msgduration.GetInt())) ) continue;
|
|
else if ( (MainQueue[i].type > PRINT_HIGH) && (gametic < (MainQueue[i].tic+chatduration.GetInt())) ) continue;
|
|
MainQueue.Delete(i);
|
|
i--;
|
|
}
|
|
// update target actors
|
|
// update floating scores
|
|
// update interpolators
|
|
HealthInter.Update(CPlayer.health);
|
|
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
if ( hnd ) ScoreInter.Update(hnd.creditsbridge[CPlayer.mo.PlayerNumber()]);
|
|
else ScoreInter.Update(0);
|
|
let d = Demolitionist(CPlayer.mo);
|
|
if ( d )
|
|
{
|
|
FuelInter.Update(int(d.dashfuel));
|
|
DashInter.Update(int((40-d.dashcooldown)*3.));
|
|
}
|
|
else
|
|
{
|
|
FuelInter.Update(0);
|
|
DashInter.Update(0);
|
|
}
|
|
}
|
|
|
|
override void Init()
|
|
{
|
|
Super.Init();
|
|
SetSize(0,640,360);
|
|
StatusTex = TexMan.CheckForTexture("graphics/HUD/StatusBox.png",TexMan.Type_Any);
|
|
DashTex = TexMan.CheckForTexture("graphics/HUD/DashBar.png",TexMan.Type_Any);
|
|
FuelTex = TexMan.CheckForTexture("graphics/HUD/FuelBar.png",TexMan.Type_Any);
|
|
HealthTex[0] = TexMan.CheckForTexture("graphics/HUD/HealthBar0.png",TexMan.Type_Any);
|
|
HealthTex[1] = TexMan.CheckForTexture("graphics/HUD/HealthBar1.png",TexMan.Type_Any);
|
|
HealthTex[2] = TexMan.CheckForTexture("graphics/HUD/HealthBar2.png",TexMan.Type_Any);
|
|
HealthTex[3] = TexMan.CheckForTexture("graphics/HUD/HealthBar3.png",TexMan.Type_Any);
|
|
ScoreTex = TexMan.CheckForTexture("graphics/HUD/ScoreBox.png",TexMan.Type_Any);
|
|
WeaponTex = TexMan.CheckForTexture("graphics/HUD/WeaponBox.png",TexMan.Type_Any);
|
|
ChatTex[0] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop.png",TexMan.Type_Any);
|
|
ChatTex[1] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine.png",TexMan.Type_Any);
|
|
ChatTex[2] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom.png",TexMan.Type_Any);
|
|
ChatTex[3] = TexMan.CheckForTexture("graphics/HUD/ChatBoxTop_Smol.png",TexMan.Type_Any);
|
|
ChatTex[4] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine_Smol.png",TexMan.Type_Any);
|
|
ChatTex[5] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom_Smol.png",TexMan.Type_Any);
|
|
mTewiFont = HUDFont.Create("TewiShaded");
|
|
HealthInter = DynamicValueInterpolator.Create(100,.1,1,100);
|
|
ScoreInter = DynamicValueInterpolator.Create(0,.1,1,1000);
|
|
FuelInter = DynamicValueInterpolator.Create(120,.5,1,100);
|
|
DashInter = DynamicValueInterpolator.Create(120,.5,1,40);
|
|
}
|
|
|
|
private void DrawTarget()
|
|
{
|
|
// omnisight: usable highlights
|
|
// omnisight: key locations
|
|
// targetting array
|
|
// floating kill scores
|
|
}
|
|
|
|
private void DrawScore()
|
|
{
|
|
Screen.DrawTexture(ScoreTex,false,ss.x-(margin+73),margin,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,ss.x-(margin+58),margin+1,String.Format("%09d",clamp(ScoreInter.GetValue(),0,999999999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
|
|
private void DrawInventory()
|
|
{
|
|
// active items (armor / powerups)
|
|
// inventory box / bar
|
|
}
|
|
|
|
private void DrawWeapon()
|
|
{
|
|
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' ) SWWMWeapon(CPlayer.ReadyWeapon).DrawWeapon(FracTic,ss.x-margin,ss.y-(margin+28),hs,ss);
|
|
else
|
|
{
|
|
// TODO generic display
|
|
}
|
|
Screen.DrawTexture(WeaponTex,false,ss.x-(margin+61),ss.y-(margin+29),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
double xx = ss.x-(margin+58), yy = ss.y-(margin+29);
|
|
for ( int i=1; i<=10; i++ )
|
|
{
|
|
int ncolor = Font.CR_WHITE;
|
|
if ( !CPlayer.HasWeaponsInSlot(i%10) ) ncolor = Font.CR_DARKGRAY;
|
|
else if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) && (CPlayer.PendingWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
|
|
else if ( (!CPlayer.PendingWeapon || (CPlayer.PendingWeapon == WP_NOCHANGE)) && CPlayer.ReadyWeapon && (CPlayer.ReadyWeapon.SlotNumber == (i%10)) ) ncolor = Font.CR_FIRE;
|
|
else
|
|
{
|
|
bool hasammo = false;
|
|
for ( Inventory inv=CPlayer.mo.Inv; inv; inv=inv.Inv )
|
|
{
|
|
bool dummy;
|
|
int slot;
|
|
if ( inv is 'Weapon' ) [dummy, slot] = CPlayer.weapons.LocateWeapon(Weapon(inv).GetClass());
|
|
if ( (slot == (i%10)) && (!Weapon(inv).Ammo1 || (Weapon(inv).Ammo1.Amount > 0)) )
|
|
hasammo = true;
|
|
}
|
|
if ( !hasammo ) ncolor = Font.CR_RED;
|
|
}
|
|
Screen.DrawText(mTewiFont.mFont,ncolor,xx,yy,String.Format("%d",(i%10)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
xx += 12;
|
|
if ( i == 5 )
|
|
{
|
|
xx = ss.x-(margin+58);
|
|
yy += 14;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawStatus()
|
|
{
|
|
Screen.DrawTexture(StatusTex,false,margin,ss.y-(margin+27),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
let d = Demolitionist(CPlayer.mo);
|
|
int dw = DashInter.GetValue();
|
|
double alph = .6;
|
|
if ( !d || (d.dashfuel > 20) || ((gametic%10) < 5) ) alph = 1.;
|
|
Screen.DrawTexture(DashTex,false,margin+2,ss.y-(margin+21),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,dw,DTA_Alpha,alph);
|
|
int fw = FuelInter.GetValue();
|
|
Screen.DrawTexture(FuelTex,false,margin+2,ss.y-(margin+25),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,fw);
|
|
int ht = clamp(HealthInter.GetValue(),0,10000);
|
|
int hw = min(ht,100);
|
|
Screen.DrawTexture(HealthTex[0],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
|
|
if ( ht > 100 )
|
|
{
|
|
hw = min(ht-100,100);
|
|
Screen.DrawTexture(HealthTex[1],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
|
|
}
|
|
if ( ht > 200 )
|
|
{
|
|
hw = int(min(ht-100,400)*0.25);
|
|
Screen.DrawTexture(HealthTex[2],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
|
|
}
|
|
if ( ht > 500 )
|
|
{
|
|
hw = int(min(ht-500,500)*0.2);
|
|
Screen.DrawTexture(HealthTex[2],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
|
|
}
|
|
int hcolor = Font.CR_RED;
|
|
if ( ht > 500 ) hcolor = Font.CR_GOLD;
|
|
else if ( ht > 200 ) hcolor = Font.CR_PURPLE;
|
|
else if ( ht > 100 ) hcolor = Font.CR_CYAN;
|
|
Screen.DrawText(mTewiFont.mFont,hcolor,margin+108,ss.y-(margin+16),String.Format("%3d",clamp(ht,0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
|
|
private void DrawMessages()
|
|
{
|
|
if ( !chatduration ) chatduration = CVar.GetCVar('swwm_chatduration',players[consoleplayer]);
|
|
if ( !msgduration ) msgduration = CVar.GetCVar('swwm_msgduration',players[consoleplayer]);
|
|
if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]);
|
|
if ( !pickcol ) pickcol = CVar.GetCVar('msg0color',players[consoleplayer]);
|
|
if ( !obitcol ) obitcol = CVar.GetCVar('msg1color',players[consoleplayer]);
|
|
if ( !critcol ) critcol = CVar.GetCVar('msg2color',players[consoleplayer]);
|
|
if ( !chatcol ) chatcol = CVar.GetCVar('msg3color',players[consoleplayer]);
|
|
if ( !teamcol ) teamcol = CVar.GetCVar('msg4color',players[consoleplayer]);
|
|
// common message area
|
|
if ( MainQueue.Size() > 0 )
|
|
{
|
|
int mstart = max(0,MainQueue.Size()-(1+maxchat[chatopen>=gametic].GetInt()));
|
|
double xx = margin, yy = margin;
|
|
bool smol = (ss.x<640);
|
|
Screen.DrawTexture(ChatTex[smol?3:0],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
yy++;
|
|
for ( int i=mstart; i<MainQueue.Size(); i++ )
|
|
{
|
|
int col = critcol.GetInt();
|
|
if ( MainQueue[i].type == PRINT_MEDIUM ) col = obitcol.GetInt();
|
|
else if ( MainQueue[i].type == PRINT_CHAT ) col = chatcol.GetInt();
|
|
else if ( MainQueue[i].type == PRINT_TEAMCHAT ) col = teamcol.GetInt();
|
|
String cstr = MainQueue[i].str;
|
|
if ( MainQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",MainQueue[i].rep);
|
|
int curtime = MainQueue[i].tic-gametic;
|
|
if ( MainQueue[i].type < PRINT_CHAT ) curtime += msgduration.GetInt();
|
|
else curtime += chatduration.GetInt();
|
|
double alph = clamp(curtime/20.,0.,1.);
|
|
BrokenLines l = mTewiFont.mFont.BreakLines(cstr,smol?211:361);
|
|
for ( int j=0; j<l.Count(); j++ )
|
|
{
|
|
Screen.DrawTexture(ChatTex[smol?4:1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
Screen.DrawText(mTewiFont.mFont,col,xx+4,yy,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
yy += 13;
|
|
}
|
|
}
|
|
Screen.DrawTexture(ChatTex[smol?5:2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
}
|
|
// pickup messages
|
|
if ( PickupQueue.Size() > 0 )
|
|
{
|
|
// reverse order since they're drawn bottom to top
|
|
int mend = max(0,PickupQueue.Size()-(1+maxpick.GetInt()));
|
|
double yy = ss.y-(margin+50);
|
|
for ( int i=PickupQueue.Size()-1; i>=mend; i-- )
|
|
{
|
|
String cstr = PickupQueue[i].str;
|
|
if ( PickupQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",PickupQueue[i].rep);
|
|
int curtime = (PickupQueue[i].tic+pickduration.GetInt())-gametic;
|
|
double alph = clamp(curtime/20.,0.,1.);
|
|
BrokenLines l = mTewiFont.mFont.BreakLines(cstr,int(ss.x*.75));
|
|
int maxlen = 0;
|
|
for ( int j=0; j<l.Count(); j++ )
|
|
{
|
|
int len = mTewiFont.mFont.StringWidth(l.StringAt(j));
|
|
if ( len > maxlen ) maxlen = len;
|
|
}
|
|
int h = mTewiFont.mFont.GetHeight();
|
|
double xx = (ss.x-maxlen)/2.;
|
|
Screen.Dim("Black",.8*alph,int((xx-6)*hs.x),int((yy-h*(l.Count()-1))*hs.y),int((maxlen+12)*hs.x),int((h*l.Count()+4)*hs.y));
|
|
for ( int j=l.Count()-1; j>=0; j-- )
|
|
{
|
|
int len = mTewiFont.mFont.StringWidth(l.StringAt(j));
|
|
xx = (ss.x-len)/2.;
|
|
Screen.DrawText(mTewiFont.mFont,pickcol.GetInt(),xx,yy+2,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
|
yy -= h;
|
|
}
|
|
yy -= 6;
|
|
}
|
|
}
|
|
}
|
|
|
|
override bool DrawChat( String txt )
|
|
{
|
|
// ignore during intermission
|
|
if ( gamestate != GS_LEVEL ) return false;
|
|
chatopen = gametic+1; // have to add 1 because DrawChat is called after everything else
|
|
double xx = 2;
|
|
double yy = ss.y-14;
|
|
Screen.Dim("Black",.8,0,Screen.GetHeight()-int(15*hs.y),Screen.GetWidth(),int(15*hs.y));
|
|
String pname = players[consoleplayer].GetUserName();
|
|
// strip colors
|
|
for ( int i=0; i<pname.CodePointCount(); i++ )
|
|
{
|
|
int remlen = 0;
|
|
if ( pname.GetNextCodePoint(i) != 0x1C )
|
|
continue;
|
|
remlen++;
|
|
if ( pname.GetNextCodePoint(i+remlen) == 0x5B )
|
|
while ( pname.GetNextCodePoint(i+remlen) != 0x5D )
|
|
remlen++;
|
|
remlen++;
|
|
pname.Remove(i,remlen);
|
|
}
|
|
String fullstr = String.Format("\cq%s\cd@\cqdemolitionist%d\cn ~ \c-wall %s%s",pname,consoleplayer+1,txt,mTewiFont.mFont.GetCursor());
|
|
// cut out to fit
|
|
int w = mTewiFont.mFont.StringWidth(fullstr);
|
|
if ( w > ss.x-4 )
|
|
{
|
|
// draw trailing dots
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,xx,yy,"...",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
// shift back
|
|
xx -= w-(ss.x-4);
|
|
// draw trimmed
|
|
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ClipLeft,int(26*hs.x));
|
|
}
|
|
else Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,xx,yy,fullstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
|
return true;
|
|
}
|
|
|
|
override void Draw( int state, double TicFrac )
|
|
{
|
|
Super.Draw(state,TicFrac);
|
|
if ( (state != HUD_StatusBar) && (state != HUD_Fullscreen) ) return;
|
|
if ( !safezone ) safezone = CVar.GetCVar('swwm_hudmargin',players[consoleplayer]);
|
|
if ( !maxchat[0] ) maxchat[0] = CVar.GetCVar('swwm_maxshown',players[consoleplayer]);
|
|
if ( !maxchat[1] ) maxchat[1] = CVar.GetCVar('swwm_maxshownbig',players[consoleplayer]);
|
|
if ( !maxpick ) maxpick = CVar.GetCVar('swwm_maxpickup',players[consoleplayer]);
|
|
BeginHUD();
|
|
hs = GetHUDScale();
|
|
ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y);
|
|
margin = clamp(safezone.GetInt(),0,(ss.x<640)?10:40);
|
|
FracTic = TicFrac;
|
|
DrawTarget();
|
|
DrawScore();
|
|
DrawInventory();
|
|
DrawStatus();
|
|
DrawWeapon();
|
|
DrawMessages();
|
|
}
|
|
}
|