stinger_m/zscript/unrealhud.zsc
Marisa Kirisame a3357251fe Fixups and adjustments to some item code.
Armors now properly sort themselves.
Powershield drains over time, for balance reasons.
Backpack no longer displays extra items text, I felt this was too verbose.
A little tease of something that's coming soon. The code is commented out until the feature is greenlit and merged.
2019-08-16 22:35:42 +02:00

793 lines
28 KiB
Text

// An almost 1:1 recreation of the Unreal 1 HUD
Class UnrealHUD : BaseStatusBar
{
double FracTic;
// Unreal HUD variables
Color RedColor, GreenColor, BlackColor;
int HudMode;
// Helpers
Vector2 scalev;
double CurX, CurY, ClipX, ClipY;
Color DrawColor;
ViewTracer vtracer;
Actor lastseen;
int lastseentic, Count;
// Fonts
Font LargeFont, LargeRedFont, MedFont, WhiteFont, TinyFont, TinyWhiteFont, TinyRedFont;
HUDFont mMapFont;
// Common Textures
TextureID HalfHud, HudLine, HudAmmo, IconHeal, IconSkul, IconSel, IconBase, KeyIcons[7];
// These can't be used yet
/*String PickupMsg;
int PickupMsgTic;
String ShortMsg[4];
int ShortMsgTic[4];
int ShortMsgCol[4];*/
// 0.83 HUD stuff
String OldAmmo[18];
Class<Inventory> OldAmmoType[18];
String OldArmor[6];
Class<Inventory> OldArmorType[6];
String OldKeys[7];
HUDFont mOldDigits;
// Translations
int RedIcon;
override void Init()
{
Super.Init();
SetSize(64,640,400);
// Initialize
Count = 0;
vtracer = new("ViewTracer");
RedColor = "FF 00 00";
GreenColor = "00 FF 00";
BlackColor = "00 00 00";
DrawColor = "FF FF FF";
LargeFont = Font.FindFont('ULargeFont');
LargeRedFont = Font.FindFont('ULargeRedFont');
MedFont = Font.FindFont('UMedFont');
WhiteFont = Font.FindFont('UWhiteFont');
TinyFont = Font.FindFont('UTinyFont');
TinyWhiteFont = Font.FindFont('UTinyWhiteFont');
TinyRedFont = Font.FindFont('UTinyRedFont');
mMapFont = HUDFont.Create(WhiteFont);
HalfHud = TexMan.CheckForTexture("HalfHud",TexMan.Type_Any);
HudLine = TexMan.CheckForTexture("HudLine",TexMan.Type_Any);
HudAmmo = TexMan.CheckForTexture("HudAmmo",TexMan.Type_Any);
IconHeal = TexMan.CheckForTexture("IconHeal",TexMan.Type_Any);
IconSkul = TexMan.CheckForTexture("IconSkul",TexMan.Type_Any);
IconSel = TexMan.CheckForTexture("IconSel",TexMan.Type_Any);
IconBase = TexMan.CheckForTexture("IconBase",TexMan.Type_Any);
RedIcon = Translation.GetID('RedIcon');
KeyIcons[0] = TexMan.CheckForTexture("I_KeyR",TexMan.Type_Any);
KeyIcons[1] = TexMan.CheckForTexture("I_KeyB",TexMan.Type_Any);
KeyIcons[2] = TexMan.CheckForTexture("I_KeyY",TexMan.Type_Any);
KeyIcons[3] = TexMan.CheckForTexture("I_SkullR",TexMan.Type_Any);
KeyIcons[4] = TexMan.CheckForTexture("I_SkullB",TexMan.Type_Any);
KeyIcons[5] = TexMan.CheckForTexture("I_SkullY",TexMan.Type_Any);
KeyIcons[6] = TexMan.CheckForTexture("I_KeyG",TexMan.Type_Any);
mOldDigits = HUDFont.Create(Font.FindFont('U083Digits'),26,Mono_CellLeft);
OldAmmo[0] = "Disp083";
OldAmmo[1] = "Clip083";
OldAmmo[2] = "Tary083";
OldAmmo[3] = "Asmd083";
OldAmmo[4] = "Rokt083";
OldAmmo[5] = "Flak083";
OldAmmo[6] = "Razor083";
OldAmmo[7] = "Bio083";
OldAmmo[8] = "Rifle083";
OldAmmo[9] = "Mini083";
OldAmmo[10] = "Shell083";
OldAmmo[11] = "Impal083";
OldAmmo[12] = "Flame083";
OldAmmo[13] = "Tele083";
OldAmmo[14] = "Stun083";
OldAmmo[15] = "Big083";
OldAmmo[16] = "Smini083";
OldAmmo[17] = "Peace083";
OldAmmoType[0] = "DispersionAmmo";
OldAmmoType[1] = "UMiniAmmo";
OldAmmoType[2] = "StingerAmmo";
OldAmmoType[3] = "AsmdAmmo";
OldAmmoType[4] = "URocketAmmo";
OldAmmoType[5] = "UFlakBox";
OldAmmoType[6] = "RazorAmmo";
OldAmmoType[7] = "UBioAmmo";
OldAmmoType[8] = "URifleAmmo";
OldAmmoType[9] = "UMinigun";
OldAmmoType[10] = "UShells";
OldAmmoType[11] = "ImpalerAmmo";
OldAmmoType[12] = "FlameAmmo";
OldAmmoType[13] = "UTranslocatorAmmo";
OldAmmoType[14] = "StunnerAmmo";
OldAmmoType[15] = "BigAmmo";
OldAmmoType[16] = "SMiniAmmo";
OldAmmoType[17] = "PeaceAmmo";
OldArmor[0] = "Armor083";
OldArmor[1] = "Kev083";
OldArmor[2] = "Asb083";
OldArmor[3] = "Tox083";
OldArmor[4] = "Belt083";
OldArmor[5] = "Pbelt083";
OldArmorType[0] = "UArmor";
OldArmorType[1] = "KevlarSuit";
OldArmorType[2] = "AsbestosSuit";
OldArmorType[3] = "ToxinSuit";
OldArmorType[4] = "ShieldBelt";
OldArmorType[5] = "PowerShield";
OldKeys[0] = "Redk083";
OldKeys[1] = "Bluek083";
OldKeys[2] = "Goldk083";
OldKeys[3] = "Rskul083";
OldKeys[4] = "Bskul083";
OldKeys[5] = "Gskul083";
OldKeys[6] = "Grenk083";
}
override void Draw( int state, double TicFrac )
{
Super.Draw(state,TicFrac);
FracTic = TicFrac;
HudMode = CVar.GetCVar('stinger_hudmode',players[consoleplayer]).GetInt();
scalev.x = scalev.y = Max(0,CVar.GetCVar('stinger_hudscale',players[consoleplayer]).GetInt());
if ( scalev.x == 0 ) scalev.x = scalev.y = max(1,min(Screen.GetWidth()/640.,Screen.GetHeight()/480.));
ClipX = Screen.GetWidth()/scalev.x;
ClipY = Screen.GetHeight()/scalev.y;
CurX = 0;
CurY = 0;
double lbottom = Screen.GetHeight()-32*scalev.y;
for ( Inventory i=CPlayer.mo.inv; i; i=i.inv )
if ( i is 'UnrealInventory' )
UnrealInventory(i).PreRender(lbottom);
if ( CPlayer.ReadyWeapon is 'UTWeapon' )
UTWeapon(CPlayer.ReadyWeapon).PreRender(lbottom);
if ( state == HUD_StatusBar )
{
BeginStatusBar();
DrawUnrealBar();
}
else if ( state == HUD_Fullscreen )
{
BeginHUD();
DrawUnrealHUD();
}
for ( Inventory i=CPlayer.mo.inv; i; i=i.inv )
if ( i is 'UnrealInventory' )
UnrealInventory(i).PostRender(lbottom);
if ( CPlayer.ReadyWeapon is 'UTWeapon' )
UTWeapon(CPlayer.ReadyWeapon).PostRender(lbottom);
DrawMessages(state);
}
private void DrawNumberOf( Inventory i, double x, double y )
{
if ( i.Amount <= 1 ) return;
double TempX = CurX, TempY = CurY;
string itxt = String.Format("%d",i.Amount);
CurX += 30;
CurY += 23;
CurX -= TinyRedFont.StringWidth(itxt);
Screen.DrawText(TinyRedFont,Font.CR_UNTRANSLATED,CurX,CurY,itxt,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurX = TempX;
CurY = TempY;
}
private void DrawIconValue( int n )
{
if ( !HudMode || (HudMode == 3) ) return;
double TempX = CurX, TempY = CurY;
string itxt = String.Format("%d",n);
CurX -= 2;
CurY -= 6;
CurX -= TinyFont.StringWidth(itxt);
Screen.DrawText(TinyFont,Font.CR_UNTRANSLATED,CurX,CurY,itxt,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurX = TempX;
CurY = TempY;
}
private void DrawHudIcon( double x, double y, Inventory i, bool bRed )
{
if ( i.Icon.IsNull() ) return;
double width = CurX;
CurX = x;
CurY = y;
// scale to fit
Vector2 scl = TexMan.GetScaledSize(i.Icon);
double mscl = 32./max(scl.x,scl.y);
double dw = (ClipX/mscl), dh = (ClipY/mscl);
double dx = CurX/mscl, dy = CurY/mscl;
if ( bRed )
{
Screen.DrawTexture(IconBase,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_TranslationIndex,RedIcon);
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_TranslationIndex,RedIcon,DTA_TopOffset,0,DTA_LeftOffset,0);
}
else
{
Screen.DrawTexture(IconBase,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_TopOffset,0,DTA_LeftOffset,0);
}
if ( (i is 'UnrealInventory') && (UnrealInventory(i).DefaultCharge > 0) && (UnrealInventory(i).Charge < UnrealInventory(i).DefaultCharge) )
Screen.DrawTexture(HudLine,false,CurX+2,CurY+29,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_WindowRightF,Min(28.*(UnrealInventory(i).Charge/double(UnrealInventory(i).DefaultCharge)),28.));
else if ( (i is 'UTArmor') && !HudMode )
Screen.DrawTexture(HudLine,false,CurX+2,CurY+29,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_WindowRightF,Min(28.*(i.Amount/double(i.MaxAmount)),28.));
}
private void DrawFragCount( double x, double y )
{
CurX = X;
CurY = Y;
Screen.DrawTexture(IconSkul,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurX += 30;
CurY += 23;
string score = String.Format("%d",(deathmatch||teamplay)?CPlayer.fragcount:CPlayer.killcount);
CurX -= TinyWhiteFont.StringWidth(score);
Screen.DrawText(TinyWhiteFont,Font.CR_UNTRANSLATED,CurX,CurY,score,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
}
private void DrawInventory( double x, double y, bool bDrawOne = false, bool bNoWeapons = false )
{
bool bGotNext, bGotPrev, bGotSelected, bRed, bFlashTranslator;
Inventory Inv, Prev, Next, SelectedItem;
UTranslator translator;
double HalfHUDX, HalfHUDY;
double AmmoBarSize;
if ( (HudMode < 4) && !bNoWeapons ) // then draw HalfHUD
{
HalfHUDX = ClipX-64;
HalfHUDY = ClipY-32;
Screen.DrawTexture(HalfHUD,false,HalfHUDX,HalfHUDY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
}
if ( !CPlayer.mo.Inv ) return; // can this even happen?
bFlashTranslator = false;
bGotSelected = false;
bGotNext = false;
bGotPrev = false;
Prev = null;
Next = null;
SelectedItem = CPlayer.mo.InvSel;
for ( Inv=CPlayer.mo.Inv; Inv; Inv=Inv.Inv )
{
if ( bDrawOne ) break;
// if drawing more than one inventory, find next and previous items
if ( Inv == SelectedItem ) bGotSelected = true;
else if ( Inv.bINVBAR )
{
if ( bGotSelected )
{
if ( !bGotNext )
{
Next = Inv;
bGotNext = true;
}
else if ( !bGotPrev ) Prev = Inv;
}
else
{
if ( !Next ) Next = Prev;
Prev = Inv;
bGotPrev = true;
}
}
if ( Inv is 'UTranslator' ) translator = UTranslator(Inv);
}
// drawing weapon slots differently than Unreal 1 because we have better methods here
let cw = CPlayer.ReadyWeapon;
int cwslot = -1;
if ( cw && (cw.SlotNumber != -1) ) cwslot = cw.SlotNumber;
let pw = CPlayer.PendingWeapon;
int pwslot = -1;
if ( pw && (pw != WP_NOCHANGE) && (pw.SlotNumber != -1) ) pwslot = pw.SlotNumber;
Array<Weapon> wslots[10];
// clear the arrays before work
for ( int i=0; i<10; i++ ) wslots[i].Clear();
// first run, populate the full array of weapons
for ( int i=0; i<10; i++ )
{
for ( Inv = CPlayer.mo.Inv; Inv; Inv=Inv.Inv )
{
if ( !(Inv is 'Weapon') ) continue;
let w = Weapon(Inv);
if ( w.SlotNumber != i ) continue;
int slot = w.SlotNumber;
wslots[slot].Push(w);
}
}
// second run, sort the slot arrays
for ( int i=0; i<10; i++ )
{
int j = 1;
while ( j < wslots[i].Size() )
{
int k = j;
while ( (k > 0) && (wslots[i][k-1].SelectionOrder >= wslots[i][k].SelectionOrder) )
{
Weapon tmp = wslots[i][k];
wslots[i][k] = wslots[i][k-1];
wslots[i][k-1] = tmp;
k--;
}
j++;
}
}
// draw the slots
if ( (HudMode < 4) && !bNoWeapons )
{
for ( int i=0; i<10; i++ )
{
if ( wslots[i].Size() <= 0 ) continue;
Font cfont = TinyFont;
if ( cwslot == i ) cfont = TinyWhiteFont;
int realslot = i?i:10;
CurX = HalfHUDX-3+realslot*6;
CurY = HalfHUDY+4;
Screen.DrawText(cfont,Font.CR_UNTRANSLATED,CurX,CurY,String.Format("%d",i),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
// Draw ammo bar(s)
int nammo = 0;
for ( int j=0; j<wslots[i].Size(); j++ ) if ( wslots[i][j].Ammo1 ) nammo++;
if ( nammo <= 0 ) continue;
int cbar = 0;
for ( int j=0; j<wslots[i].Size(); j++ )
{
let amo = wslots[i][j].Ammo1;
if ( !amo ) continue;
AmmoBarSize = 16*min(1.0,amo.Amount/double(amo.MaxAmount));
CurX = HalfHUDX-3+realslot*6+(4./nammo)*cbar;
CurY = HalfHUDY+29-AmmoBarSize;
if ( (AmmoBarSize < 8) && (amo.Amount < 10) && (amo.Amount > 0) && (nammo == 1) )
{
CurY -= 9;
Screen.DrawText(TinyRedFont,Font.CR_UNTRANSLATED,CurX,CurY,String.Format("%d",amo.Amount),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurY += 9;
}
DrawColor = Color(0,255,0);
if ( AmmoBarSize < 8 ) DrawColor = Color(255-int(AmmoBarSize)*30,int(AmmoBarSize)*30+40,0);
if ( wslots[i][j] != cw ) DrawColor = Color(DrawColor.r/2,DrawColor.g/2,DrawColor.b/2);
if ( amo.Amount > 0 )
{
Screen.DrawTexture(HudAmmo,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_FillColor,BlackColor,DTA_DestWidthF,4./nammo,DTA_DestHeightF,AmmoBarSize);
Screen.DrawTexture(HudAmmo,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_AlphaChannel,true,DTA_FillColor,DrawColor,DTA_DestWidthF,4./nammo,DTA_DestHeightF,AmmoBarSize);
}
cbar++;
}
}
}
// draw translator
if ( translator )
{
if ( translator.bCurrentlyActivated ) translator.DrawTranslator(scalev,ClipX,ClipY);
else bFlashTranslator = (translator.bNewMessage || translator.bNotNewMessage);
}
// draw the inventory bar
if ( (HUDMode == 5) || !SelectedItem ) return;
Count++;
if ( Count > 20 ) Count = 0;
if ( Prev )
{
bRed = ((Prev is 'UnrealInventory') && UnrealInventory(Prev).bActive) || (Prev is 'Powerup') || ((Prev is 'UTranslator') && bFlashTranslator);
DrawHudIcon(x,y,Prev,bRed);
if ( Prev.MaxAmount > 1 ) DrawNumberOf(Prev,x,y);
}
bRed = ((SelectedItem is 'UnrealInventory') && UnrealInventory(SelectedItem).bActive) || (SelectedItem is 'Powerup') || ((SelectedItem is 'UTranslator') && bFlashTranslator);
if ( !Next && !Prev && !bDrawOne ) DrawHudIcon(x+64,y,SelectedItem,bRed);
else DrawHudIcon(x+32,y,SelectedItem,bRed);
CurX = x+32;
if ( !Next && !Prev && !bDrawOne ) CurX = x+64;
CurY = y;
Screen.DrawTexture(IconSel,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_Alpha,0.5);
if ( SelectedItem.MaxAmount > 1 ) DrawNumberOf(SelectedItem,CurX,y);
if ( Next )
{
bRed = ((Next is 'UnrealInventory') && UnrealInventory(Next).bActive) || (Next is 'Powerup') || ((Next is 'UTranslator') && bFlashTranslator);
DrawHudIcon(x+64,y,Next,bRed);
if ( Next.MaxAmount > 1 ) DrawNumberOf(Next,x+64,y);
}
}
private bool DrawArmor( double x, double y, bool bDrawOne = false, bool bCheckOnly = false )
{
bool hasdrawn = false;
int ArmorAmount = 0, CurAbs = 0;
Inventory Inv, BestArmor;
double XL, YL;
CurX = x;
CurY = y;
for ( Inv=CPlayer.mo.Inv; Inv; Inv=Inv.Inv )
{
if ( !(Inv is 'UTArmor') ) continue;
ArmorAmount += Inv.Amount;
if ( (Inv.Amount <= 0) || Inv.Icon.IsNull() ) continue;
if ( !bDrawOne )
{
hasdrawn = true;
if ( !bCheckOnly ) DrawHudIcon(CurX,y,Inv,false);
CurX += 32;
CurY += HudMode?29:27;
if ( !bCheckOnly ) DrawIconValue(Inv.Amount);
CurY -= HudMode?29:27;
}
else if ( UTArmor(Inv).absorb > CurAbs )
{
CurAbs = UTArmor(Inv).absorb;
BestArmor = Inv;
}
}
if ( bDrawOne && BestArmor )
{
hasdrawn = true;
if ( !bCheckOnly ) DrawHudIcon(CurX,Y,BestArmor,false);
CurX += 32;
CurY += HudMode?29:27;
if ( !bCheckOnly ) DrawIconValue(BestArmor.Amount);
CurY -= HudMode?29:27;
}
if ( (ArmorAmount > 0) && !HudMode )
{
hasdrawn = true;
if ( !bCheckOnly ) Screen.DrawText(LargeFont,Font.CR_UNTRANSLATED,CurX+2,Y,String.Format("%d",ArmorAmount),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
}
return hasdrawn;
}
private void DrawAmmo( double x, double y )
{
CurX = x;
CurY = y;
if ( !CPlayer.ReadyWeapon || !CPlayer.ReadyWeapon.Ammo1 ) return;
Font cfont = LargeFont;
if ( CPlayer.ReadyWeapon.Ammo1.Amount <= min(9,CPlayer.ReadyWeapon.Ammo1.MaxAmount/3) ) cfont = LargeRedFont;
if ( !HudMode )
{
CurX -= cfont.StringWidth(String.Format("%d",CPlayer.ReadyWeapon.Ammo1.Amount))+2;
Screen.DrawText(cfont,Font.CR_UNTRANSLATED,CurX,CurY,String.Format("%d",CPlayer.ReadyWeapon.Ammo1.Amount),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
}
CurX = x;
Screen.DrawTexture(IconBase,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
TextureID icon = CPlayer.ReadyWeapon.Icon.IsNull()?CPlayer.ReadyWeapon.Ammo1.Icon:CPlayer.ReadyWeapon.Icon;
// scale to fit
Vector2 scl = TexMan.GetScaledSize(icon);
double mscl = 32./max(scl.x,scl.y);
double dw = (ClipX/mscl), dh = (ClipY/mscl);
double dx = CurX/mscl, dy = CurY/mscl;
Screen.DrawTexture(icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_TopOffset,0,DTA_LeftOffset,0);
CurX += 32;
CurY += 29;
DrawIconValue(CPlayer.ReadyWeapon.Ammo1.Amount);
CurX = X+2;
CurY = Y+29;
if ( (HudMode != 1) && (HudMode != 2) && (HudMode != 4) )
Screen.DrawTexture(HudLine,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_WindowRightF,Min(28.*(CPlayer.ReadyWeapon.Ammo1.Amount/double(CPlayer.ReadyWeapon.Ammo1.MaxAmount)),28.));
// TODO secondary ammo display
}
private void DrawHealth( double x, double y )
{
CurX = X;
CurY = Y;
Font cfont = LargeFont;
if ( CPlayer.mo.Health < 25 ) cfont = LargeRedFont;
Screen.DrawTexture(IconHeal,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurX += 32;
CurY += 29;
DrawIconValue(Max(0,CPlayer.mo.Health));
CurY -= 29;
if ( !HudMode ) Screen.DrawText(cfont,Font.CR_UNTRANSLATED,CurX+2,CurY,String.Format("%d",Max(0,CPlayer.mo.Health)),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurX = X+2;
CurY = Y+29;
if ( (HudMode != 1) && (HudMode != 2) && (HudMode != 4) )
Screen.DrawTexture(HudLine,false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_WindowRightF,Min(28.*(CPlayer.mo.Health/double(CPlayer.mo.SpawnHealth())),28.));
}
private void DrawIdentifyInfo()
{
double lalpha = 2.0-((gametic+fractic)-lastseentic)/Thinker.TICRATE;
if ( !lastseen || (lalpha <= 0) ) return;
String cl1 = "DarkGreen", cl2 = "Green";
if ( deathmatch && (lastseen.player.GetTeam() < teams.size()) )
{
cl2 = teams[lastseen.player.GetTeam()].mName;
cl1 = String.Format("Dark%s",cl2);
}
String tname = String.Format("\c[%s]%s:\c[%s] %s",cl1,StringTable.Localize("$M_NAME"),cl2,lastseen.player.GetUserName());
CurX = (ClipX-WhiteFont.StringWidth(tname))/2;
CurY = ClipY-54;
Screen.DrawText(WhiteFont,Font.CR_UNTRANSLATED,CurX,CurY,tname,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_Alpha,lalpha/2.);
if ( !deathmatch || (lastseen.IsTeammate(CPlayer.mo)) )
{
CurY += 1.2*WhiteFont.GetHeight();
tname = String.Format("\c[%s]%s:\c[%s] %d",cl1,StringTable.Localize("$M_HEALTH"),cl2,lastseen.Health);
Screen.DrawText(WhiteFont,Font.CR_UNTRANSLATED,CurX,CurY,tname,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true,DTA_Alpha,lalpha/2.);
}
}
private void DrawKeys( double x, double y, bool leftright = false )
{
if ( deathmatch ) return; // no need to draw in DM
if ( gameinfo.gametype&(GAME_Hexen|GAME_Strife) ) return; // no key display for these ATM (will do eventually)
CurX = x;
CurY = y;
int cnt = 0;
for ( int i=0; i<6; i++ )
{
if ( !CPlayer.mo.CheckKeys(i+1,false,true) ) continue;
Screen.DrawTexture(KeyIcons[((i==0)&&(gameinfo.gametype&GAME_Heretic))?6:i],false,CurX,CurY,DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
cnt++;
if ( !(cnt%3) )
{
CurX = x;
CurY -= 16;
}
else CurX += leftright?16:-16;
}
}
private void DrawUnrealHUD()
{
if ( HudMode == 5 )
{
DrawInventory(ClipX-96,0);
return;
}
if ( ClipX < 320 ) HudMode = 4;
// Draw Armor
if ( HudMode < 2 ) DrawArmor(0,0);
else if ( (HudMode == 3) || (HudMode == 2) ) DrawArmor(0,ClipY-32);
else if ( HudMode == 4 ) DrawArmor(ClipX-64,ClipY-64,true);
// Draw Ammo
if ( HudMode != 4 ) DrawAmmo(ClipX-96,ClipY-32);
else DrawAmmo(ClipX-32,ClipY-32);
// Draw Health
if ( HudMode < 2 ) DrawHealth(0,ClipY-32);
else if ( (HudMode == 3) || (HudMode == 2) ) DrawHealth(ClipX-128,ClipY-32);
else if ( HudMode == 4 ) DrawHealth(ClipX-64,ClipY-32);
// Display Inventory
if ( HudMode < 2 ) DrawInventory(ClipX-96,0);
else if ( HudMode == 3 ) DrawInventory(ClipX-96,ClipY-64);
else if ( HudMode == 4 ) DrawInventory(ClipX-64,ClipY-64,true);
else if ( HudMode == 2 ) DrawInventory(ClipX/2-64,ClipY-32);
if ( deathmatch )
{
// Display Frag count
if ( HudMode < 3 ) DrawFragCount(ClipX-32,ClipY-64);
else if ( HudMode == 3 ) DrawFragCount(0,ClipY-64);
else if ( HudMode == 4 ) DrawFragCount(0,ClipY-32);
}
else
{
// Display Keys
if ( HudMode < 3 ) DrawKeys(ClipX-(deathmatch?48:16),ClipY-48);
else if ( HudMode == 3 ) DrawKeys(deathmatch?32:0,ClipY-48,true);
else if ( HudMode == 4 ) DrawKeys(deathmatch?32:0,ClipY-16,true);
}
// Display Identification Info
DrawIdentifyInfo();
}
private void DrawUnrealBar()
{
// 0.83 status bar, just for funsies
DrawImage("Bar083",(0,336),DI_ITEM_OFFSETS);
static const float slotofs[] = {525, 84, 128, 173, 216, 259, 349, 392, 436, 481};
static const float keyofs[] = {187, 211, 235, 379, 403, 427};
for ( int i=0; i<10; i++ )
{
if ( !CPlayer.HasWeaponsInSlot(i) ) continue;
bool used = (CPlayer.ReadyWeapon&&(CPlayer.ReadyWeapon.SlotNumber==i));
DrawImage("Slot083",(slotofs[i],342),DI_ITEM_OFFSETS,used?1.:.8);
}
DrawString(mOldDigits,FormatNumber(CPlayer.health,3),(358,366),DI_TEXT_ALIGN_RIGHT);
int ArmorAmount = 0, CurAbs = -1;
Inventory BestArmor = null;
for ( Inventory Inv=CPlayer.mo.Inv; Inv; Inv=Inv.Inv )
{
if ( !(Inv is 'UTArmor') ) continue;
ArmorAmount += Inv.Amount;
if ( Inv.Amount <= 0 ) continue;
if ( UTArmor(Inv).absorb > CurAbs )
{
CurAbs = UTArmor(Inv).absorb;
BestArmor = Inv;
}
}
for ( int i=0; i<6; i++ )
{
if ( !(BestArmor is OldArmorType[i]) ) continue;
DrawImage(OldArmor[i],(4,340),DI_ITEM_OFFSETS);
break;
}
if ( ArmorAmount ) DrawString(mOldDigits,FormatNumber(ArmorAmount,3),(167,366),DI_TEXT_ALIGN_RIGHT);
Inventory Ammo1, Ammo2;
[Ammo1, Ammo2] = GetCurrentAmmo();
if ( Ammo1 )
{
if ( Ammo1.Amount ) DrawString(mOldDigits,FormatNumber(Ammo1.Amount,3),(549,366),DI_TEXT_ALIGN_RIGHT);
for ( int i=0; i<18; i++ )
{
// match by ammo
if ( (OldAmmoType[i] is 'Ammo') && !(Ammo1 is OldAmmoType[i]) ) continue;
// match by weapon
if ( (OldAmmoType[i] is 'Weapon') && !(CPlayer.ReadyWeapon is OldAmmoType[i]) ) continue;
DrawImage(OldAmmo[i],(560,336),DI_ITEM_OFFSETS);
break;
}
}
for ( int i=0; i<6; i++ )
{
if ( !CPlayer.mo.CheckKeys(i+1,false,true) ) continue;
DrawImage(OldKeys[((i==0)&&(gameinfo.gametype&GAME_Heretic))?6:i],(keyofs[i],366),DI_ITEM_OFFSETS);
}
if ( HudMode > 5 ) return;
// Draw frags in DM
if ( deathmatch ) DrawFragCount(ClipX-32,0);
// Need to draw the inventory bar (and translator)
DrawInventory(ClipX-(deathmatch?128:96),0,false,true);
// Display Identification Info
DrawIdentifyInfo();
}
override void Tick()
{
Super.Tick();
// prune expired short messages
/*for ( int i=0; i<3; i++ )
{
if ( (gametic-ShortMsgTic[i]) < 70 ) continue;
ShortMsg[i] = ShortMsg[i+1];
ShortMsgTic[i] = ShortMsgTic[i+1];
ShortMsgCol[i] = ShortMsgCol[i+1];
}*/
CPlayer.inventorytics = 0;
vtracer.ignore = CPlayer.mo;
vtracer.trace(CPlayer.mo.Vec2OffsetZ(0,0,CPlayer.viewz),CPlayer.mo.CurSector,(cos(CPlayer.mo.angle)*cos(CPlayer.mo.pitch),sin(CPlayer.mo.angle)*cos(CPlayer.mo.pitch),-sin(CPlayer.mo.pitch)),1000,0);
if ( vtracer.Results.HitType != TRACE_HitActor ) return;
lastseen = vtracer.Results.HitActor;
lastseentic = gametic;
}
// all of this requires features that are not available yet
/*override void NewGame()
{
PickupMsg = "";
}
override void FlushNotify()
{
for ( int i=0; i<4; i++ )
ShortMsg[i] = "";
}
override bool ProcessNotify( EPrintLevel printlevel, String outline )
{
if ( printlevel == PRINT_LOW )
{
// set pickup message
PickupMsg = outline;
PickupMsgTic = gametic;
return true;
}
else
{
// put message into queue
for ( int i=3; i>0; i-- )
{
ShortMsg[i] = ShortMsg[i-1];
ShortMsgTic[i] = ShortMsgTic[i-1];
ShortMsgCol[i] = ShortMsgCol[i-1];
}
if ( printlevel == PRINT_MEDIUM ) ShortMsgCol[0] = Font.CR_RED;
else if ( (printlevel == PRINT_CHAT) || (printlevel == PRINT_TEAMCHAT) ) ShortMsgCol[0] = Font.CR_GREEN;
else ShortMsgCol[0] = Font.CR_WHITE;
ShortMsg[0] = outline;
ShortMsgTic[0] = gametic;
return true;
}
return false;
}
override bool DrawChat( String txt )
{
int xpos = 4*CleanXFac_1;
int ypos = (screenblocks<=10)?GetTopOfStatusBar():(Screen.GetHeight()-((screenblocks>11)?0:int(32*scalev.y)));
ypos -= (WhiteFont.GetHeight()+4)*CleanYFac_1;
String fullstr = String.Format("(> Say %s%s",txt,WhiteFont.GetCursor());
// cut out until it fits
while ( (WhiteFont.StringWidth(fullstr) > CleanWidth_1) && fullstr.Length() > 7 )
fullstr.Remove(7,1);
Screen.DrawText(WhiteFont,Font.CR_GREEN,xpos,ypos,fullstr,DTA_CleanNoMove_1,true);
return true;
}*/
private void DrawMessages( int state )
{
// TODO add map intro text like in Unreal
/*double malpha = 2.0-((gametic+fractic)-PickupMsgTic)/Thinker.TICRATE;
int xpos, ypos;
if ( PickupMsg.Length() > 0 && (malpha > 0) )
{
xpos = (Screen.GetWidth()-WhiteFont.StringWidth(PickupMsg)*CleanXFac_1)/2;
if ( state == HUD_Statusbar ) ypos = GetTopOfStatusBar()-21*CleanYFac_1;
else ypos = Screen.GetHeight()-41*CleanYFac_1;
Screen.DrawText(WhiteFont,Font.CR_WHITE,xpos,ypos,PickupMsg,DTA_CleanNoMove_1,true,DTA_Alpha,min(1.,malpha),DTA_LegacyRenderStyle,STYLE_Add);
}
// draw messages
xpos = 4*CleanXFac_1;
ypos = 4*CleanYFac_1;
if ( (state == HUD_Fullscreen) && (HudMode < 2) && DrawArmor(0,0,false,true) ) ypos += int(32*scalev.y);
for ( int i=3; i>=0; i-- )
{
if ( (ShortMsg[i].Length() <= 0) || (gametic-ShortMsgTic[i] >= 70) ) continue;
let lines = WhiteFont.BreakLines(ShortMsg[i],CleanWidth_1/2);
for ( int j=0; j<lines.Count(); j++ )
{
Screen.DrawText(WhiteFont,ShortMsgCol[i],xpos,ypos,lines.StringAt(j),DTA_CleanNoMove_1,true);
ypos += (WhiteFont.GetHeight()+2)*CleanYFac_1;
}
}*/
}
override void DrawAutomapHUD( double ticFrac )
{
int crdefault = Font.CR_GREY;
int highlight = Font.CR_RED;
double cbottom = Screen.GetHeight()*0.99;
let scale = GetHUDScale();
double textdist = 8./scale.Y;
int height = WhiteFont.GetHeight();
String printtext;
int SCREENWIDTH = screen.GetWidth();
BeginHUD();
let y = textdist;
let width = WhiteFont.StringWidth("00:00:00");
double tmp, hres;
[tmp,tmp,hres] = StatusbarToRealCoords(0,0,HorizontalResolution);
double swidth = 0;
double ltop = 0, rtop = 0;
if ( (HudMode < 6) && CPlayer.mo.InvSel )
rtop += (32*scalev.y)/scale.Y;
int protrusion = GetProtrusion(swidth/hres);
[tmp,tmp,hres] = StatusbarToRealCoords(0,0,protrusion);
width += int((swidth-hres)/scale.X);
if ( am_showtime )
{
printtext = level.TimeFormatted();
DrawString(mMapFont,level.TimeFormatted(),(-textdist-width,y+rtop),0,crdefault);
y += height;
}
if ( am_showtotaltime ) DrawString(mMapFont,level.TimeFormatted(true),(-textdist-width,y+rtop),0,crdefault);
if ( !deathmatch )
{
y = textdist;
if ( am_showmonsters )
{
DrawString(mMapFont,String.Format("%s\34%c %d/%d",Stringtable.Localize("$AM_MONSTERS"),crdefault+65,level.killed_monsters,level.total_monsters),(textdist,y+ltop),0,highlight);
y += height;
}
if ( am_showsecrets )
{
DrawString(mMapFont,String.Format("%s\34%c %d/%d",Stringtable.Localize("$AM_SECRETS"),crdefault+65,level.found_secrets,level.total_secrets),(textdist,y+ltop),0,highlight);
y += height;
}
if ( am_showitems ) DrawString(mMapFont,String.Format("%s\34%c %d/%d",Stringtable.Localize("$AM_ITEMS"),crdefault+65,level.found_items,level.total_items),(textdist,y+ltop),0,highlight);
}
String mapname = level.FormatMapName(crdefault);
BrokenLines lines = WhiteFont.BreakLines(mapname,int(SCREENWIDTH/scale.X));
int numlines = lines.Count();
int finalwidth = int(WhiteFont.StringWidth(lines.StringAt(numlines-1))*scale.X);
[tmp,tmp,hres] = StatusbarToRealCoords(0,0,HorizontalResolution);
protrusion = GetProtrusion(finalwidth/hres);
[tmp,tmp,tmp,hres] = StatusbarToRealCoords(0,0,0,protrusion);
y = (cbottom-hres)/scale.Y-height*numlines;
for ( int i = 0; i < numlines; i++ )
{
DrawString(mMapFont,lines.StringAt(i),(0,y+ltop),DI_TEXT_ALIGN_CENTER|DI_SCREEN_HCENTER|DI_SCREEN_TOP,highlight);
y += height;
}
}
}