// 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 OldAmmoType[19]; String OldArmor[6]; Class 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 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 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