stinger_m/zscript/unrealhud.zsc
Marisa Kirisame bac9b6674d More stuff before public release.
Adjust the aspect of new 0.83 hud icons.
Impaler plays unique sound when ending altfire instead of select sound.
Adapt some things for the old sounds add-on.
Minor HUD adjustments (weapon slot related).
Left a couple notes of what I might do next.
2019-09-27 14:20:00 +02:00

899 lines
33 KiB
Text

// An almost 1:1 recreation of the Unreal 1 HUD
Class UnrealHUD : BaseStatusBar
{
double FracTic;
// for easy access to ammo slots
UnrealMainHandler hnd;
// 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, UBigFont, MedFont, WhiteFont, TinyFont, TinyWhiteFont, TinyRedFont;
HUDFont mMapFont;
// Common Textures
TextureID HalfHud, HudLine, HudAmmo, IconHeal, IconSkul, IconSel, IconBase, KeyIcons[7];
// messaging stuff
String PickupMsg;
int PickupMsgTic;
String ShortMsg[4];
int ShortMsgTic[4];
int ShortMsgCol[4];
String MidPrintStr;
int MidPrintTic;
bool MidPrintLarge;
// 0.83 HUD stuff
String OldAmmo[19];
Class<Inventory> OldAmmoType[19];
String OldArmor[6];
Class<Inventory> OldArmorType[6];
String OldKeys[7];
HUDFont mOldDigits, mOldDigitsSmall;
Font OldLargeFont, OldSmallFont;
// Translations
int RedIcon;
// Translator menu interaction
transient bool bTranslatorActive;
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.GetFont('ULargeFont');
LargeRedFont = Font.GetFont('ULargeRedFont');
UBigFont = Font.GetFont('UBigFont');
MedFont = Font.GetFont('UMedFont');
WhiteFont = Font.GetFont('UWhiteFont');
TinyFont = Font.GetFont('UTinyFont');
TinyWhiteFont = Font.GetFont('UTinyWhiteFont');
TinyRedFont = Font.GetFont('UTinyRedFont');
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.GetFont('U083Digits'),26,Mono_CellLeft);
mOldDigitsSmall = HUDFont.Create(Font.GetFont('U083DigitsSmall'),13,Mono_CellLeft);
mMapFont = HUDFont.Create(WhiteFont);
OldLargeFont = Font.GetFont('UOldLargeFont');
OldSmallFont = Font.GetFont('UOldSmallFont');
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";
OldAmmo[18] = "OLSMP083";
OldAmmoType[0] = "DefaultAmmo";
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";
OldAmmoType[18] = "OLSMPAmmo";
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 = CVar.GetCVar('hud_scale',players[consoleplayer]).GetInt();
if ( scalev.x < 0 ) scalev.x = scalev.y = max(1,min(Screen.GetWidth()/640.,Screen.GetHeight()/480.)); // the typical behavior is scaling to 640x400 but we're expecting 4:3 here
else if ( scalev.x == 0 )
{
scalev.x = CleanXFac_1;
scalev.y = CleanYFac_1;
}
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_Fullscreen )
{
BeginHUD();
DrawUnrealHUD();
}
else if ( state == HUD_StatusBar )
{
BeginStatusBar();
DrawUnrealBar();
}
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);
DrawIdentifyInfo(state);
DrawMessages(state);
}
private void DrawNumberOf( Inventory i, double x, double y )
{
if ( (i.Amount <= 1) && !((i is 'UnrealInventory') && UnrealInventory(i).bDRAWSPECIAL) ) return;
double TempX = CurX, TempY = CurY;
string itxt = String.Format("%d",((i is 'UnrealInventory')&&UnrealInventory(i).bDRAWSPECIAL)?i.special1: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, bool bIsArmor = false )
{
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).bActive || (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 == 0) || (HudMode == 3)) )
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<Ammo> aslots[10];
// clear the arrays before work
for ( int i=0; i<10; i++ ) aslots[i].Clear();
// we need the ammo slots array, if it isn't accessible then we're fucked
if ( !hnd ) hnd = UnrealMainHandler(EventHandler.Find("UnrealMainHandler"));
if ( hnd )
{
// populate the array
for ( int i=0; i<hnd.AmmoSlots.Size(); i++ )
{
let a = Ammo(CPlayer.mo.FindInventory(hnd.AmmoSlots[i].AmmoType));
if ( !a ) continue;
for ( int j=0; j<10; j++ )
{
if ( !hnd.AmmoSlots[i].UsedInSlot[j] ) continue;
aslots[j].Push(a);
}
}
}
// draw the slots
if ( (HudMode < 4) && !bNoWeapons )
{
for ( int i=0; i<10; i++ )
{
Font cfont = TinyFont;
if ( (pwslot != -1) && (pwslot == i) || (pwslot == -1) && (cwslot == i) )
cfont = TinyWhiteFont;
int realslot = i?i:10;
CurX = HalfHUDX-3+realslot*6;
CurY = HalfHUDY+4;
if ( CPlayer.HasWeaponsInSlot(i) )
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<aslots[i].Size(); j++ ) if ( aslots[i][j].Amount ) nammo++;
if ( nammo <= 0 ) continue;
int cbar = 0;
for ( int j=0; j<aslots[i].Size(); j++ )
{
let amo = aslots[i][j];
if ( amo.Amount <= 0 ) 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 ( !cw || (cw.Ammo1 != amo) ) 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++;
}
}
}
// flash translator icon
if ( translator ) bFlashTranslator = (translator.bNewMessage || translator.bNotNewMessage);
// draw the inventory bar
if ( (HUDMode == 5) || !SelectedItem ) return;
Count++;
if ( Count > 20 ) Count = 0;
if ( Prev && !Next && !bDrawOne ) x += 32; // this was missing from the original, causing a gap when there's only two items in the inventory
if ( Prev )
{
bRed = ((Prev is 'UnrealInventory') && UnrealInventory(Prev).bActive) || (Prev is 'Powerup') || ((Prev is 'UTranslator') && ((bTranslatorActive) || (bFlashTranslator && ((gametic%8)<4))));
DrawHudIcon(x,y,Prev,bRed);
if ( (Prev.MaxAmount > 1) || ((Prev is 'UnrealInventory') && UnrealInventory(Prev).bDRAWSPECIAL) ) DrawNumberOf(Prev,x,y);
}
bRed = ((SelectedItem is 'UnrealInventory') && UnrealInventory(SelectedItem).bActive) || (SelectedItem is 'Powerup') || ((SelectedItem is 'UTranslator') && ((bTranslatorActive) || (bFlashTranslator && ((gametic%8)<4))));
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) || ((SelectedItem is 'UnrealInventory') && UnrealInventory(SelectedItem).bDRAWSPECIAL) ) DrawNumberOf(SelectedItem,CurX,y);
if ( Next )
{
bRed = ((Next is 'UnrealInventory') && UnrealInventory(Next).bActive) || (Next is 'Powerup') || ((Next is 'UTranslator') && ((bTranslatorActive) || (bFlashTranslator && ((gametic%8)<4))));
DrawHudIcon(x+64,y,Next,bRed);
if ( (Next.MaxAmount > 1) || ((Next is 'UnrealInventory') && UnrealInventory(Next).bDRAWSPECIAL) ) 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;
int sec = -1, sec2 = -1;
bool red = false, red2 = false;
if ( CPlayer.ReadyWeapon is 'UnrealWeapon' )
[sec, sec2, red, red2] = UnrealWeapon(CPlayer.ReadyWeapon).GetClipAmount();
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);
double bx = CurX;
CurX = bx-MedFont.StringWidth(String.Format("%d",sec))-2;
CurY += cfont.GetHeight()-MedFont.GetHeight()-4;
if ( sec != -1 )
Screen.DrawText(MedFont,red?Font.CR_RED:Font.CR_UNTRANSLATED,CurX,CurY,String.Format("%d",sec),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurX = bx-MedFont.StringWidth(String.Format("%d",sec2))-2;
CurY -= MedFont.GetHeight()+2;
if ( sec2 != -1 )
Screen.DrawText(MedFont,red2?Font.CR_RED:Font.CR_UNTRANSLATED,CurX,CurY,String.Format("%d",sec2),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
}
CurX = x;
CurY = y;
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.));
if ( HudMode )
{
CurX = (x+30)-TinyFont.StringWidth(String.Format("%d",sec));
CurY = y+2;
if ( sec != -1 )
Screen.DrawText(red?TinyRedFont:TinyFont,Font.CR_UNTRANSLATED,CurX,CurY,String.Format("%d",sec),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
CurX = x+3;
if ( sec2 != -1 )
Screen.DrawText(red2?TinyRedFont:TinyFont,Font.CR_UNTRANSLATED,CurX,CurY,String.Format("%d",sec2),DTA_VirtualWidthF,ClipX,DTA_VirtualHeightF,ClipY,DTA_KeepRatio,true);
}
}
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( int state )
{
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());
let fnt = (state==HUD_Fullscreen)?WhiteFont:OldSmallFont;
CurX = (ClipX-fnt.StringWidth(tname))/2;
CurY = ClipY-54;
Screen.DrawText(fnt,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*fnt.GetHeight();
tname = String.Format("\c[%s]%s:\c[%s] %d",cl1,StringTable.Localize("$M_HEALTH"),cl2,lastseen.Health);
Screen.DrawText(fnt,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 )
{
// minimal hud
int ArmorAmount = 0;
for ( Inventory Inv=CPlayer.mo.Inv; Inv; Inv=Inv.Inv )
{
if ( !(Inv is 'UTArmor') ) continue;
ArmorAmount += Inv.Amount;
}
int AmmoAmount1 = 0, AmmoAmount2 = 0;
Ammo amo1, amo2;
[amo1, amo2] = GetCurrentAmmo();
if ( amo1 )
{
AmmoAmount1 = amo1.Amount;
if ( amo2 ) AmmoAmount2 = amo2.Amount;
}
String str;
if ( amo1 && amo2 && (amo2 != amo1) ) str = String.Format(StringTable.Localize("$S_MINHUD2"),CPlayer.Health,(deathmatch||teamplay)?CPlayer.fragcount:CPlayer.killcount,AmmoAmount2,AmmoAmount1);
else str = String.Format(StringTable.Localize("$S_MINHUD"),CPlayer.Health,(deathmatch||teamplay)?CPlayer.fragcount:CPlayer.killcount,AmmoAmount1);
Screen.DrawText(OldSmallFont,Font.CR_WHITE,(Screen.GetWidth()-OldSmallFont.StringWidth(str)*CleanXFac_1)/2,CleanYFac_1,str,DTA_CleanNoMove_1,true);
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(ClipX-96,ClipY-32);
}
else
{
// Display Keys
if ( HudMode < 3 ) DrawKeys(ClipX-16,ClipY-48);
else if ( HudMode == 3 ) DrawKeys(0,ClipY-48,true);
else if ( HudMode == 4 ) DrawKeys(ClipX-80,ClipY-16);
}
}
override void ReceivedWeapon( Weapon weapn )
{
Super.ReceivedWeapon(weapn);
if ( weapn.SlotNumber == -1 ) return;
// fuckin' hell
EventHandler.SendNetworkEvent("Bar083SlotFlash",weapn.SlotNumber);
}
private void DrawUnrealBar()
{
// 0.83 status bar, just for funsies
DrawImage("Bar083",(0,336),DI_ITEM_OFFSETS);
// extra widescreen filler
bool first = true;
double base = -128;
double rx, dummy;
do
{
[rx, dummy, dummy] = StatusBarToRealCoords(base,0,HorizontalResolution);
DrawImage(first?"BarL083":"BarM083",(base,336),DI_ITEM_OFFSETS);
first = false;
base -= 128;
} while ( rx >= -128 );
first = true;
base = 640;
do
{
[rx, dummy, dummy] = StatusBarToRealCoords(base,0,HorizontalResolution);
DrawImage(first?"BarR083":"BarM083",(base,336),DI_ITEM_OFFSETS);
first = false;
base += 128;
} while ( rx < Screen.GetWidth() );
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));
if ( CPlayer.PendingWeapon && (CPlayer.PendingWeapon != WP_NOCHANGE) )
used = (CPlayer.PendingWeapon.SlotNumber==i);
DrawImage(used?"Used083":"Slot083",(slotofs[i],342),DI_ITEM_OFFSETS);
}
let hnd = UnrealMainHandler(EventHandler.Find("UnrealMainHandler"));
if ( hnd )
{
for ( int i=0; i<10; i++ )
if ( hnd.slotflash[i] > gametic )
DrawImage("Flsh083",(slotofs[i],342),DI_ITEM_OFFSETS,(hnd.slotflash[i]-gametic+FracTic)/20.);
}
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<19; 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;
}
}
int sec = -1, sec2 = -1;
if ( CPlayer.ReadyWeapon && (CPlayer.ReadyWeapon is 'UnrealWeapon') )
[sec, sec2] = UnrealWeapon(CPlayer.ReadyWeapon).GetClipAmount();
if ( sec != -1 )
DrawString(mOldDigitsSmall,FormatNumber(sec,3),(633,378),DI_TEXT_ALIGN_RIGHT);
if ( sec2 != -1 )
DrawString(mOldDigitsSmall,FormatNumber(sec2,3),(556,378),DI_TEXT_ALIGN_LEFT);
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
DrawInventory(ClipX-(deathmatch?128:96),0,false,true);
}
override void Tick()
{
Super.Tick();
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;
}
override void FlushNotify()
{
for ( int i=0; i<4; i++ )
{
ShortMsg[i] = "";
ShortMsgTic[i] = int.min;
}
PickupMsg = "";
PickupMsgTic = int.min;
MidPrintStr = "";
MidPrintTic = int.min;
}
override bool ProcessNotify( EPrintLevel printlevel, String outline )
{
if ( printlevel == PRINT_LOW )
{
// set pickup message
PickupMsg = outline;
PickupMsgTic = gametic+50;
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+70;
return true;
}
return false;
}
override bool ProcessMidPrint( Font fnt, String msg, bool bold )
{
if ( !fnt || (fnt == SmallFont) || (fnt == OriginalSmallFont) || (fnt == NewSmallFont) )
{
MidPrintStr = msg;
MidPrintLarge = false;
MidPrintTic = gametic+70;
return true;
}
else if ( fnt == BigFont )
{
MidPrintStr = msg;
MidPrintLarge = true;
MidPrintTic = gametic+70;
return true;
}
return false;
}
override bool DrawChat( String txt )
{
int xpos = 4*CleanXFac_1;
int ypos = ((screenblocks<=10)||automapactive)?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 )
{
int xpos, ypos;
if ( (MidPrintStr.Length() > 0) && (MidPrintTic > gametic) )
{
let mfnt = MidPrintLarge?UBigFont:WhiteFont;
xpos = (Screen.GetWidth()-mfnt.StringWidth(MidPrintStr)*CleanXFac_1)/2;
ypos = 96*CleanYFac_1;
Screen.DrawText(mfnt,Font.FindFontColor('UTHudText'),xpos,ypos,MidPrintStr,DTA_CleanNoMove_1,true,DTA_Alpha,clamp((MidPrintTic-gametic+fractic)*0.05,0,1),DTA_LegacyRenderStyle,STYLE_Add);
}
if ( PickupMsgTic > gametic )
{
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,clamp((PickupMsgTic-gametic+fractic)*0.05,0,1),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 ( ShortMsgTic[i] < gametic ) 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;
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 < 5) && CPlayer.mo.InvSel )
rtop += (32*scalev.y)/scale.Y;
double cbottom = GetTopOfStatusBar()-textdist;
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;
}
}
}