diff --git a/BrewedPC/KFClassicHUD.u b/BrewedPC/KFClassicHUD.u new file mode 100644 index 0000000..54e76a8 Binary files /dev/null and b/BrewedPC/KFClassicHUD.u differ diff --git a/BrewedPC/KFClassicMode_Assets.upk b/BrewedPC/KFClassicMode_Assets.upk new file mode 100644 index 0000000..de640c9 Binary files /dev/null and b/BrewedPC/KFClassicMode_Assets.upk differ diff --git a/Src/KFClassicHUD/Classes/ClassicHUD.uc b/Src/KFClassicHUD/Classes/ClassicHUD.uc new file mode 100644 index 0000000..6fe5596 --- /dev/null +++ b/Src/KFClassicHUD/Classes/ClassicHUD.uc @@ -0,0 +1,102 @@ +class ClassicHUD extends KFMutator; + +var KFPawn LastHitZed; +var int LastHitHP; +var KFPlayerController LastDamageDealer; +var vector LastDamagePosition; +var class LastDamageDMGType; + +struct RepInfoS +{ + var DamageReplicationInfo DRI; + var KFPlayerController KFPC; +}; +var array DamageReplicationInfos; + +function PostBeginPlay() +{ + Super.PostBeginPlay(); + WorldInfo.Game.HUDType = class'ClassicKFHUD'; +} + +function NetDamage(int OriginalDamage, out int Damage, Pawn Injured, Controller InstigatedBy, vector HitLocation, out vector Momentum, class DamageType, Actor DamageCauser) +{ + Super.NetDamage(OriginalDamage, Damage, Injured, InstigatedBy, HitLocation, Momentum, DamageType, DamageCauser); + + if( LastDamageDealer!=None ) + { + ClearTimer('CheckDamageDone'); + CheckDamageDone(); + } + + if( Damage>0 && InstigatedBy != None ) + { + if( KFPawn_Monster(Injured) != None && KFPlayerController(InstigatedBy) != None ) + { + LastDamageDealer = KFPlayerController(InstigatedBy); + + LastHitZed = KFPawn(Injured); + LastHitHP = LastHitZed.Health; + LastDamagePosition = HitLocation; + LastDamageDMGType = class(DamageType); + SetTimer(0.1,false,'CheckDamageDone'); + } + } +} + +final function CheckDamageDone() +{ + local int Damage, i; + + if( LastDamageDealer!=None && LastHitZed!=None && LastHitHP!=LastHitZed.Health ) + { + Damage = LastHitHP-Max(LastHitZed.Health,0); + if( Damage>0 ) + { + i = DamageReplicationInfos.Find('KFPC', LastDamageDealer); + if( i != INDEX_NONE ) + DamageReplicationInfos[i].DRI.ClientNumberMsg(Damage,LastDamagePosition,LastDamageDMGType); + } + } + LastDamageDealer = None; +} + +function NotifyLogin(Controller C) +{ + if( KFPlayerController(C) != None ) + CreateReplicationInfo(KFPlayerController(C)); + + Super.NotifyLogin(C); +} + +function NotifyLogout(Controller C) +{ + if( KFPlayerController(C) != None ) + DestroyReplicationInfo(KFPlayerController(C)); + + Super.NotifyLogout(C); +} + +function CreateReplicationInfo(KFPlayerController C) +{ + local RepInfoS Info; + + Info.DRI = Spawn(class'DamageReplicationInfo', C); + Info.KFPC = C; + + Info.DRI.KFPC = C; + + DamageReplicationInfos.AddItem(Info); +} + +function DestroyReplicationInfo(KFPlayerController C) +{ + local int i; + + i = DamageReplicationInfos.Find('KFPC', C); + if( i != INDEX_NONE ) + { + DamageReplicationInfos[i].DRI.Destroy(); + DamageReplicationInfos.RemoveItem(DamageReplicationInfos[i]); + } +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/ClassicKFHUD.uc b/Src/KFClassicHUD/Classes/ClassicKFHUD.uc new file mode 100644 index 0000000..38b90d0 --- /dev/null +++ b/Src/KFClassicHUD/Classes/ClassicKFHUD.uc @@ -0,0 +1,3562 @@ +class ClassicKFHUD extends KFGFxHudWrapper; + +const MAX_WEAPON_GROUPS = 4; +const HUDBorderSize = 3; + +const PHASE_DONE = -1; +const PHASE_SHOWING = 0; +const PHASE_DELAYING = 1; +const PHASE_HIDING = 2; + +enum EDamageTypes +{ + DMG_Fire, + DMG_Toxic, + DMG_Bleeding, + DMG_EMP, + DMG_Freeze, + DMG_Flashbang, + DMG_Generic, + DMG_High, + DMG_Medium, + DMG_Unspecified +}; + +enum PopupPosition +{ + PP_BOTTOM_CENTER, + PP_BOTTOM_LEFT, + PP_BOTTOM_RIGHT, + PP_TOP_CENTER, + PP_TOP_LEFT, + PP_TOP_RIGHT +}; + +enum EJustificationType +{ + HUDA_None, + HUDA_Right, + HUDA_Left, + HUDA_Top, + HUDA_Bottom +}; + +enum EPriorityAlignment +{ + PR_TOP, + PR_BOTTOM +}; + +enum EPriorityAnimStyle +{ + ANIM_SLIDE, + ANIM_DROP +}; + +struct WeaponInfoS +{ + var Weapon Weapon; + var string WeaponName; +}; +var transient WeaponInfoS CachedWeaponInfo; + +struct FKillMessageType +{ + var bool bDamage,bLocal,bPlayerDeath,bSuicide; + var int Counter; + var Class Type; + var string Name, KillerName; + var PlayerReplicationInfo OwnerPRI; + var float MsgTime,XPosition,CurrentXPosition; + var color MsgColor; +}; +var transient array KillMessages; + +var Color HudMainColor, HudOutlineColor, FontColor; +var Color DefaultHudMainColor, DefaultHudOutlineColor, DefaultFontColor; +var transient float LevelProgressBar, VisualProgressBar; +var transient bool bInterpolating, bDisplayingProgress; + +var Texture HealthIcon, ArmorIcon, WeightIcon, GrenadesIcon, DoshIcon, ClipsIcon, BulletsIcon, BurstBulletIcon, AutoTargetIcon, ManualTargetIcon, ProgressBarTex, DoorWelderBG; +var Texture WaveCircle, BioCircle; +var Texture ArrowIcon, FlameIcon, FlameTankIcon, FlashlightIcon, FlashlightOffIcon, RocketIcon, BoltIcon, M79Icon, PipebombIcon, SingleBulletIcon, SyringIcon, SawbladeIcon, DoorWelderIcon; +var Texture TraderBox, TraderArrow, TraderArrowLight; +var Texture VoiceChatIcon; +var Texture2D PerkStarIcon, DoshEarnedIcon; + +var KFDroppedPickup WeaponPickup; +var float MaxWeaponPickupDist; +var float WeaponPickupScanRadius; +var float ZedScanRadius; +var Texture2D WeaponAmmoIcon, WeaponWeightIcon; +var float WeaponIconSize; +var Color WeaponIconColor,WeaponOverweightIconColor; + +var int MaxNonCriticalMessages; +var float NonCriticalMessageDisplayTime,NonCriticalMessageFadeInTime,NonCriticalMessageFadeOutTime; + +var int HealthBarFullVisDist, HealthBarCutoffDist; + +struct PopupDamageInfo +{ + var int Damage; + var float HitTime; + var Vector HitLocation; + var byte Type; + var color FontColor; + var vector RandVect; +}; +const DAMAGEPOPUP_COUNT = 32; +var PopupDamageInfo DamagePopups[DAMAGEPOPUP_COUNT]; +var int NextDamagePopupIndex; +var float DamagePopupFadeOutTime; + +struct FCritialMessage +{ + var string Text, Delimiter; + var float StartTime; + var bool bHighlight,bUseAnimation; + var int TextAnimAlpha; +}; +var transient array NonCriticalMessages; + +struct FPriorityMessage +{ + var string PrimaryText, SecondaryText; + var float StartTime, SecondaryStartTime, LifeTime, FadeInTime, FadeOutTime; + var EPriorityAlignment SecondaryAlign; + var EPriorityAnimStyle PrimaryAnim, SecondaryAnim; + var Texture2D Icon,SecondaryIcon; + var Color IconColor,SecondaryIconColor; + var bool bSecondaryUsesFullLength; + + structdefaultproperties + { + FadeInTime=0.15f + FadeOutTime=0.15f + LifeTime=5.f + IconColor=(R=255,G=255,B=255,A=255) + SecondaryIconColor=(R=255,G=255,B=255,A=255) + } +}; +var transient FPriorityMessage PriorityMessage; +var int CurrentPriorityMessageA,CurrentSecondaryMessageA; + +var transient vector PLCameraLoc,PLCameraDir; +var transient rotator PLCameraRot; + +var int PlayerScore, OldPlayerScore, ScoreDelta; +var float TimeX, TimeXEnd; +var int PerkIconSize; +var int MaxPerkStars, MaxStarsPerRow; + +var bool bDisplayQuickSyringe; +var float QuickSyringeStartTime, QuickSyringeDisplayTime, QuickSyringeFadeInTime, QuickSyringeFadeOutTime; + +struct HUDBoxRenderInfo +{ + var int JustificationPadding; + var Color TextColor, OutlineColor, BoxColor; + var Texture IconTex; + var float Alpha; + var float IconScale; + var array StringArray; + var bool bUseOutline, bUseRounded, bRoundedOutline, bHighlighted; + var EJustificationType Justification; + + structdefaultproperties + { + TextColor=(R=255,B=255,G=255,A=255) + Alpha=-1.f + IconScale=1.f + } +}; + +var Texture2D MedicLockOnIcon; +var float MedicLockOnIconSize, LockOnStartTime, LockOnEndTime; +var Color MedicLockOnColor, MedicPendingLockOnColor; +var KFPawn OldTarget; + +var rotator MedicWeaponRot; +var float MedicWeaponHeight; +var Color MedicWeaponBGColor; +var Color MedicWeaponNotChargedColor, MedicWeaponChargedColor; + +struct InventoryCategory +{ + var array Items; + var int ItemCount; +}; +var int MinWeaponIndex[MAX_WEAPON_GROUPS], MaxWeaponIndex[MAX_WEAPON_GROUPS]; +var int MaxWeaponsPerCatagory; + +var float ScaledBorderSize; + +var const Color BlueColor; +var ObjectReferencer RepObject; +var transient KF2GUIController GUIController; +var transient GUIStyleBase GUIStyle; + +var int FontBlurX,FontBlurX2,FontBlurY,FontBlurY2; + +struct XPEarnedS +{ + var float StartTime,XPos,YPos,RandX,RandY; + var bool bInit; + var int XP; + var Texture2D Icon; + var Color IconColor; +}; +const XPEARNED_COUNT = 32; +var XPEarnedS XPPopups[XPEARNED_COUNT]; +var int NextXPPopupIndex; +var float XPFadeOutTime; + +struct DoshEarnedS +{ + var float StartTime,XPos,YPos,RandX,RandY; + var bool bInit; + var int Dosh; +}; +const DOSHEARNED_COUNT = 32; +var DoshEarnedS DoshPopups[XPEARNED_COUNT]; +var int NextDoshPopupIndex; +var float DoshFadeOutTime; + +var array PawnList; + +var bool bDisplayInventory; +var float InventoryFadeTime, InventoryFadeStartTime, InventoryFadeInTime, InventoryFadeOutTime, InventoryX, InventoryY, InventoryBoxWidth, InventoryBoxHeight, BorderSize; +var Texture InventoryBackgroundTexture, SelectedInventoryBackgroundTexture; +var int SelectedInventoryCategory, SelectedInventoryIndex; +var KFWeapon SelectedInventory; + +struct PopupMessage +{ + var string Body; + var Texture2D Image; + var PopupPosition MsgPosition; +}; +var privatewrite int NotificationPhase; +var privatewrite array MessageQueue; +var privatewrite string NewLineSeparator; +var float NotificationPhaseStartTime, NotificationIconSpacing, NotificationShowTime, NotificationHideTime, NotificationHideDelay, NotificationBorderSize; +var Texture NotificationBackground; + +var array HUDWidgets; + +var class ScoreboardClass; +var KFScoreBoard Scoreboard; + +struct FHealthBarInfo +{ + var float LastHealthUpdate,HealthUpdateEndTime; + var int OldBarHealth,OldHealth; + var bool bDrawingHistory; +}; +var array HealthBarDamageHistory; +var int DamageHistoryNum; + +var KFPawn_Scripted ScriptedPawn; +var KFInterface_MonsterBoss BossPawn; +var float BossShieldPct; +var bool bDisplayImportantHealthBar; +var Color BossBattlePhaseColor; +var Texture2D BossInfoIcon; +var array BattlePhaseColors; + +struct FNewItemEntry +{ + var Texture2D Icon; + var string Item,IconURL; + var float MsgTime; +}; +var transient array NewItems; +var transient array WasNewlyAdded; +var transient OnlineSubsystem OnlineSub; +var transient bool bLoadedInitItems; +var array DamageMsgColors; + +simulated function PostBeginPlay() +{ + Super.PostBeginPlay(); + + SetupHUDTextures(); + + HudMainColor = DefaultHudMainColor; + HudOutlineColor = DefaultHudOutlineColor; + FontColor = DefaultFontColor; + + SetTimer(0.1, true, 'SetupFontBlur'); + SetTimer(0.1f, true, 'CheckForWeaponPickup'); + SetTimer(0.1f, true, 'BuildCacheItems'); + + PlayerOwner.PlayerInput.OnReceivedNativeInputKey = NotifyInputKey; + PlayerOwner.PlayerInput.OnReceivedNativeInputAxis = NotifyInputAxis; + PlayerOwner.PlayerInput.OnReceivedNativeInputChar = NotifyInputChar; + + OnlineSub = class'GameEngine'.static.GetOnlineSubsystem(); + if( OnlineSub!=None ) + { + OnlineSub.AddOnInventoryReadCompleteDelegate(SearchInventoryForNewItem); + SetTimer(60,false,'SearchInventoryForNewItem'); + } + + SetTimer(300 + FRand()*120.f, false, 'CheckForItems'); +} + +function BuildCacheItems() +{ + local KFPawn_Human KFPH; + + foreach WorldInfo.AllPawns( class'KFPawn_Human', KFPH ) + { + if( PawnList.Find(KFPH) == INDEX_NONE ) + PawnList.AddItem(KFPH); + } +} + +simulated function CheckForWeaponPickup() +{ + WeaponPickup = GetWeaponPickup(); +} + +simulated function KFDroppedPickup GetWeaponPickup() +{ + local KFDroppedPickup KFDP, BestKFDP; + local int KFDPCount, ZedCount; + local vector EndTrace, HitLocation, HitNormal; + local Actor HitActor; + local float DistSq, BestDistSq; + local KFPawn_Monster KFPM; + + if (KFPlayerOwner == None || !KFPlayerOwner.WorldInfo.GRI.bMatchHasBegun) + return None; + + EndTrace = PLCameraLoc + PLCameraDir * MaxWeaponPickupDist; + HitActor = KFPlayerOwner.Trace(HitLocation, HitNormal, EndTrace, PLCameraLoc); + + if (HitActor == None) + return None; + + foreach KFPlayerOwner.CollidingActors(class'KFPawn_Monster', KFPM, ZedScanRadius, HitLocation) + { + if (KFPM.IsAliveAndWell()) + return None; + + ZedCount++; + if (ZedCount > 20) + return None; + } + + BestDistSq = WeaponPickupScanRadius * WeaponPickupScanRadius; + + foreach KFPlayerOwner.CollidingActors(class'KFDroppedPickup', KFDP, WeaponPickupScanRadius, HitLocation) + { + if (KFDP.Velocity.Z == 0 && ClassIsChildOf(KFDP.InventoryClass, class'KFWeapon')) + { + DistSq = VSizeSq(KFDP.Location - HitLocation); + if (DistSq < BestDistSq) + { + BestKFDP = KFDP; + BestDistSq = DistSq; + } + } + + KFDPCount++; + if (KFDPCount > 2) + break; + } + + return BestKFDP; +} + +simulated function SetupFontBlur() +{ + FontBlurX = RandRange(-8, 8); + FontBlurX2 = RandRange(-8, 8); + FontBlurY = RandRange(-8, 8); + FontBlurY2 = RandRange(-8, 8); +} + +function SetupHUDTextures(optional bool bUseColorIcons) +{ + ProgressBarTex = Texture2D(RepObject.ReferencedObjects[85]); + + HealthIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[146]) : Texture2D(RepObject.ReferencedObjects[27]); + ArmorIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[149]) : Texture2D(RepObject.ReferencedObjects[31]); + WeightIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[152]) : Texture2D(RepObject.ReferencedObjects[34]); + GrenadesIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[142]) : Texture2D(RepObject.ReferencedObjects[23]); + DoshIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[148]) : Texture2D(RepObject.ReferencedObjects[30]); + BulletsIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[136]) : Texture2D(RepObject.ReferencedObjects[17]); + ClipsIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[131]) : Texture2D(RepObject.ReferencedObjects[11]); + BurstBulletIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[137]) : Texture2D(RepObject.ReferencedObjects[18]); + AutoTargetIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[133]) : Texture2D(RepObject.ReferencedObjects[13]); + + ArrowIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[132]) : Texture2D(RepObject.ReferencedObjects[12]); + FlameIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[139]) : Texture2D(RepObject.ReferencedObjects[19]); + FlameTankIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[138]) : Texture2D(RepObject.ReferencedObjects[20]); + FlashlightIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[141]) : Texture2D(RepObject.ReferencedObjects[21]); + FlashlightOffIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[140]) : Texture2D(RepObject.ReferencedObjects[22]); + RocketIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[143]) : Texture2D(RepObject.ReferencedObjects[24]); + BoltIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[144]) : Texture2D(RepObject.ReferencedObjects[25]); + M79Icon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[145]) : Texture2D(RepObject.ReferencedObjects[26]); + PipebombIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[147]) : Texture2D(RepObject.ReferencedObjects[29]); + SingleBulletIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[150]) : Texture2D(RepObject.ReferencedObjects[32]); + SyringIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[151]) : Texture2D(RepObject.ReferencedObjects[33]); + SawbladeIcon = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[153]) : Texture2D(RepObject.ReferencedObjects[78]); + ManualTargetIcon = bUseColorIcons ? Texture2D'KFClassicMode_Assets.HUD_Color.Hud_ManualTarget_White' : Texture2D'KFClassicMode_Assets.HUD.Hud_ManualTarget'; + + TraderBox = Texture2D(RepObject.ReferencedObjects[16]); + + InventoryBackgroundTexture = Texture2D(RepObject.ReferencedObjects[113]); + SelectedInventoryBackgroundTexture = Texture2D(RepObject.ReferencedObjects[114]); + + WaveCircle = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[134]) : Texture2D(RepObject.ReferencedObjects[15]); + BioCircle = bUseColorIcons ? Texture2D(RepObject.ReferencedObjects[135]) : Texture2D(RepObject.ReferencedObjects[14]); +} + +function PostRender() +{ + if( KFGRI == None ) + KFGRI = KFGameReplicationInfo(WorldInfo.GRI); + + if( GUIController!=None && PlayerOwner.PlayerInput==None ) + GUIController.NotifyLevelChange(); + + if( GUIController==None || GUIController.bIsInvalid ) + { + GUIController = Class'KFClassicHUD.KF2GUIController'.Static.GetGUIController(PlayerOwner); + if( GUIController!=None ) + { + GUIStyle = GUIController.CurrentStyle; + GUIStyle.HUDOwner = self; + LaunchHUDMenus(); + } + } + GUIStyle.Canvas = Canvas; + GUIStyle.PickDefaultFontSize(Canvas.ClipY); + GUIController.HandleDrawMenu(); + + ScaledBorderSize = FMax(GUIStyle.ScreenScale(HUDBorderSize), 1.f); + + Super.PostRender(); + + PlayerOwner.GetPlayerViewPoint(PLCameraLoc,PLCameraRot); + PLCameraDir = vector(PLCameraRot); + + DamageHistoryNum = 0; +} + +function LaunchHUDMenus() +{ + Scoreboard = KFScoreBoard(GUIController.InitializeHUDWidget(ScoreboardClass)); + Scoreboard.SetVisibility(false); +} + +function bool NotifyInputKey(int ControllerId, Name Key, EInputEvent Event, float AmountDepressed, bool bGamepad) +{ + local int i; + + for( i=(HUDWidgets.Length-1); i>=0; --i ) + { + if( HUDWidgets[i].bVisible && HUDWidgets[i].NotifyInputKey(ControllerId, Key, Event, AmountDepressed, bGamepad) ) + return true; + } + + return false; +} + +function bool NotifyInputAxis(int ControllerId, name Key, float Delta, float DeltaTime, optional bool bGamepad) +{ + local int i; + + for( i=(HUDWidgets.Length-1); i>=0; --i ) + { + if( HUDWidgets[i].bVisible && HUDWidgets[i].NotifyInputAxis(ControllerId, Key, Delta, DeltaTime, bGamepad) ) + return true; + } + + return false; +} + +function bool NotifyInputChar(int ControllerId, string Unicode) +{ + local int i; + + for( i=(HUDWidgets.Length-1); i>=0; --i ) + { + if( HUDWidgets[i].bVisible && HUDWidgets[i].NotifyInputChar(ControllerId, Unicode) ) + return true; + } + + return false; +} + +delegate int SortRenderDistance(KFPawn_Human PawnA, KFPawn_Human PawnB) +{ + return VSizeSq(PawnA.Location - PlayerOwner.Location) < VSizeSq(PawnB.Location - PlayerOwner.Location) ? -1 : 0; +} + +function DrawHUD() +{ + local KFPawn_Human KFPH; + local vector PlayerPartyInfoLocation; + local array VisibleHumanPlayers; + local array HiddenHumanPlayers; + local float ThisDot; + local vector TargetLocation; + local Actor LocActor; + local int i; + + if( KFPlayerOwner != none && KFPlayerOwner.Pawn != None && KFPlayerOwner.Pawn.Weapon != None ) + { + KFPlayerOwner.Pawn.Weapon.DrawHUD( self, Canvas ); + } + + Super(HUD).DrawHUD(); + + Canvas.EnableStencilTest(true); + + if( WeaponPickup != None ) + { + DrawWeaponPickupInfo(); + } + + DrawDamage(); + + if( KFPlayerOwner != None && KFPlayerOwner.Pawn != None ) + { + if( KFWeap_MedicBase(KFPlayerOwner.Pawn.Weapon) != None ) + { + DrawMedicWeaponLockOn(KFWeap_MedicBase(KFPlayerOwner.Pawn.Weapon)); + } + + if( !KFPlayerOwner.bCinematicMode ) + DrawMedicWeaponRecharge(); + } + + Canvas.EnableStencilTest(false); + + DrawTraderIndicator(); + + if( KFGRI == None ) + { + KFGRI = KFGameReplicationInfo( WorldInfo.GRI ); + } + + if( KFPlayerOwner == None ) + { + return; + } + + if( !KFPlayerOwner.bCinematicMode ) + { + LocActor = KFPlayerOwner.ViewTarget != none ? KFPlayerOwner.ViewTarget : KFPlayerOwner; + + if( KFPlayerOwner != none && (bDrawCrosshair || bForceDrawCrosshair || KFPlayerOwner.GetTeamNum() == 255) ) + { + DrawCrosshair(); + } + + if( PlayerOwner.GetTeamNum() == 0 ) + { + Canvas.EnableStencilTest(true); + + // Probably slow but needed to properly sort the rendering so farther elements don't overlap closer ones. + PawnList.Sort(SortRenderDistance); + foreach PawnList( KFPH ) + { + if( KFPH != None && KFPH.IsAliveAndWell() && KFPH != KFPlayerOwner.Pawn && KFPH.Mesh.SkeletalMesh != none && KFPH.Mesh.bAnimTreeInitialised ) + { + PlayerPartyInfoLocation = KFPH.Mesh.GetPosition() + ( KFPH.CylinderComponent.CollisionHeight * vect(0,0,1) ); + if(`TimeSince(KFPH.Mesh.LastRenderTime) < 0.2f && Normal(PlayerPartyInfoLocation - PLCameraLoc) dot PLCameraDir > 0.f ) + { + if( DrawFriendlyHumanPlayerInfo(KFPH) ) + { + VisibleHumanPlayers.AddItem( KFPH.PlayerReplicationInfo ); + } + else + { + HiddenHumanPlayers.Insert( 0, 1 ); + HiddenHumanPlayers[0].HumanPawn = KFPH; + HiddenHumanPlayers[0].HumanPRI = KFPH.PlayerReplicationInfo; + } + } + else + { + HiddenHumanPlayers.Insert( 0, 1 ); + HiddenHumanPlayers[0].HumanPawn = KFPH; + HiddenHumanPlayers[0].HumanPRI = KFPH.PlayerReplicationInfo; + } + } + } + + if( !KFGRI.bHidePawnIcons ) + { + CheckAndDrawHiddenPlayerIcons( VisibleHumanPlayers, HiddenHumanPlayers ); + CheckAndDrawRemainingZedIcons(); + + if(KFGRI.CurrentObjective != none && KFGRI.ObjectiveInterface != none) + { + KFGRI.ObjectiveInterface.DrawHUD(self, Canvas); + + TargetLocation = KFGRI.ObjectiveInterface.GetIconLocation(); + ThisDot = Normal((TargetLocation + (class'KFPawn_Human'.default.CylinderComponent.CollisionHeight * vect(0, 0, 1))) - PLCameraLoc) dot PLCameraDir; + + if (ThisDot > 0 && + KFGRI.ObjectiveInterface.ShouldShowObjectiveHUD() && + (!KFGRI.ObjectiveInterFace.HasObjectiveDrawDistance() || VSizeSq(TargetLocation - LocActor.Location) < MaxDrawDistanceObjective)) + { + DrawObjectiveHUD(); + } + } + } + + Canvas.EnableStencilTest(false); + } + } + + if( KillMessages.Length > 0 ) + { + RenderKillMsg(); + } + + if( NonCriticalMessages.Length > 0 ) + { + for( i=0; i 0 ) + { + DrawItemsList(); + } +} + +simulated function SearchInventoryForNewItem() +{ + local int i,j; + + if( WasNewlyAdded.Length!=OnlineSub.CurrentInventory.Length ) + WasNewlyAdded.Length = OnlineSub.CurrentInventory.Length; + for( i=0; i=10.f ) + { + NewItems.Remove(i--,1); + continue; + } + if( T>9.f ) + { + T = 255.f * (10.f-T); + TextColor = MakeColor(255,255,255,T); + + BT = HudMainColor.A * (10.f-BT); + BackgroundColor = MakeColor(HudMainColor.R, HudMainColor.G, HudMainColor.B, BT); + + OT = HudOutlineColor.A * (10.f-OT); + OutlineColor = MakeColor(HudOutlineColor.R, HudOutlineColor.G, HudOutlineColor.B, OT); + } + else + { + TextColor = MakeColor(255,255,255,255); + BackgroundColor = HudMainColor; + OutlineColor = HudOutlineColor; + } + + Canvas.TextSize(NewItems[i].Item,XS,YS,FontScale,FontScale); + GUIStyle.DrawOutlinedBox(XPos-(XS+(ScaledBorderSize*2)), YPos-(ScaledBorderSize*0.5), XS+(ScaledBorderSize*4), YSize+(ScaledBorderSize*2), 1, BackgroundColor, OutlineColor); + + XS = XPos-XS; + + Canvas.DrawColor = TextColor; + Canvas.SetPos(XS, YPos); + Canvas.DrawText("New Item:",, FontScale, FontScale); + Canvas.SetPos(XS, YPos+(YSize*0.5)); + Canvas.DrawText(NewItems[i].Item,, FontScale, FontScale); + + YPos-=YSize; + } +} + +simulated function CheckForItems() +{ + if( KFGRI!=none ) + KFGRI.ProcessChanceDrop(); + SetTimer(260+FRand()*220.f,false,'CheckForItems'); +} + +function AddPopupMessage(const out PopupMessage NewMessage) +{ + MessageQueue.AddItem(NewMessage); + + if( MessageQueue.Length == 1 ) + { + NotificationPhaseStartTime = WorldInfo.TimeSeconds; + NotificationPhase = PHASE_SHOWING; + } +} + +function DrawPopupInfo() +{ + local float IconSize, TempX, TempY, DrawHeight, TimeElapsed, TempWidth, TempHeight, FontScalar, NotificationHeight, NotificationWidth; + + Canvas.Font = GUIStyle.PickFont(FontScalar); + NotificationHeight = GUIStyle.DefaultHeight * 1.5f; + + Canvas.TextSize(MessageQueue[0].Body, TempWidth, TempHeight, FontScalar, FontScalar); + NotificationWidth = TempWidth + (NotificationHeight*2) + (ScaledBorderSize*4); + + TimeElapsed = `TimeSince(NotificationPhaseStartTime); + switch( NotificationPhase ) + { + case PHASE_SHOWING: + if (TimeElapsed < NotificationShowTime) + { + DrawHeight = (TimeElapsed / NotificationShowTime) * NotificationHeight; + } + else + { + NotificationPhase = PHASE_DELAYING; + NotificationPhaseStartTime = `TimeSince(TimeElapsed - NotificationShowTime); + DrawHeight = NotificationHeight; + } + break; + case PHASE_DELAYING: + if (TimeElapsed < NotificationHideDelay ) + { + DrawHeight = NotificationHeight; + } + else + { + NotificationPhase = PHASE_HIDING; // Hiding Phase + TimeElapsed -= NotificationHideDelay; + NotificationPhaseStartTime = `TimeSince(TimeElapsed); + DrawHeight = (1.0 - (TimeElapsed / NotificationHideTime)) * NotificationHeight; + } + break; + case PHASE_HIDING: + if (TimeElapsed < NotificationHideTime) + { + DrawHeight = (1.0 - (TimeElapsed / NotificationHideTime)) * NotificationHeight; + } + else + { + // We're done + MessageQueue.Remove(0, 1); + if( MessageQueue.Length != 0 ) + { + NotificationPhaseStartTime = WorldInfo.TimeSeconds; + NotificationPhase = PHASE_SHOWING; + } + else + { + NotificationPhase = PHASE_DONE; + } + return; + } + break; + } + + switch( MessageQueue[0].MsgPosition ) + { + case PP_TOP_LEFT: + case PP_BOTTOM_LEFT: + TempX = 0; + break; + case PP_TOP_CENTER: + case PP_BOTTOM_CENTER: + TempX = (Canvas.ClipX / 2.0) - (NotificationWidth / 2.0); + break; + case PP_TOP_RIGHT: + case PP_BOTTOM_RIGHT: + TempX = Canvas.ClipX - NotificationWidth; + break; + default: + `Warn("Unrecognized position:" @ MessageQueue[0].MsgPosition); + break; + } + + switch( MessageQueue[0].MsgPosition ) + { + case PP_BOTTOM_CENTER: + case PP_BOTTOM_LEFT: + case PP_BOTTOM_RIGHT: + TempY = Canvas.ClipY - DrawHeight - (ScaledBorderSize*2); + break; + case PP_TOP_CENTER: + case PP_TOP_LEFT: + case PP_TOP_RIGHT: + TempY = DrawHeight - NotificationHeight + (ScaledBorderSize*2); + break; + default: + `Warn("Unrecognized position:" @ MessageQueue[0].MsgPosition); + break; + } + + // Draw the Background + GUIStyle.DrawRoundedBox(ScaledBorderSize*2, TempX, TempY, NotificationWidth, NotificationHeight, HudMainColor); + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*2, TempX, TempY, NotificationHeight, NotificationHeight, HudOutlineColor, true, false, true, false); + + IconSize = NotificationHeight - (NotificationBorderSize * 2.0); + + Canvas.SetDrawColor(255, 255, 255, 255); + Canvas.SetPos(TempX + ((NotificationHeight-IconSize)/2), TempY + ((NotificationHeight-IconSize)/2)); + Canvas.DrawTile(MessageQueue[0].Image, IconSize, IconSize, 1, 0, 256, 256); + + Canvas.SetPos(TempX + (NotificationHeight/2) + ((NotificationWidth-TempWidth)/2), TempY + ((NotificationHeight-TempHeight)/2)); + Canvas.DrawText(MessageQueue[0].Body,, FontScalar, FontScalar); +} + +exec function SetShowScores(bool bNewValue) +{ + if( Scoreboard!=None ) + Scoreboard.SetVisibility(bNewValue); +} + +function string GetGameInfoText() +{ + if( KFGRI != None ) + { + if( KFGRI.bTraderIsOpen ) + { + return GUIStyle.GetTimeString(KFGRI.GetTraderTimeRemaining()); + } + else if( KFGRI.bWaveIsActive ) + { + if( KFGRI.IsBossWave() ) + { + return class'KFGFxHUD_WaveInfo'.default.BossWaveString; + } + else if( KFGRI.IsEndlessWave() ) + { + return Chr(0x221E); + } + else if( KFGRI.bMatchIsOver ) + { + return "---"; + } + + return string(KFGRI.AIRemaining); + } + } + + return ""; +} + +function string GetGameInfoSubText() +{ + local int WaveMax; + local string S; + + if( KFGRI != None && KFGRI.bWaveIsActive && !KFGRI.IsBossWave() ) + { + WaveMax = KFGRI.WaveMax-1; + + if( KFGameReplicationInfo_Endless(KFGRI) != None ) + S = string(KFGRI.WaveNum); + else S = string(KFGRI.WaveNum) $ "/" $ string(WaveMax); + + return class'KFGFxHUD_WaveInfo'.default.WaveString @ S; + } + + return ""; +} + +function DrawHUDBox + ( + out float X, + out float Y, + float Width, + float Height, + coerce string Text, + float TextScale=1.f, + optional HUDBoxRenderInfo HBRI + ) +{ + local float XL, YL, IconXL, IconYL, IconW, TextX, TextY; + local bool bUseAlpha; + local int i; + local FontRenderInfo FRI; + local Color BoxColor, OutlineColor, TextColor, BlankColor; + + FRI.bClipText = true; + FRI.bEnableShadow = true; + + bUseAlpha = HBRI.Alpha != -1.f; + BoxColor = HBRI.BoxColor == BlankColor ? HudMainColor : HBRI.BoxColor; + OutlineColor = HBRI.OutlineColor == BlankColor ? HudOutlineColor : HBRI.OutlineColor; + TextColor = HBRI.TextColor == BlankColor ? FontColor : HBRI.TextColor; + + if( bUseAlpha ) + { + BoxColor.A = byte(Min(HBRI.Alpha, HudMainColor.A)); + OutlineColor.A = byte(Min(HBRI.Alpha, HudOutlineColor.A)); + TextColor.A = byte(HBRI.Alpha); + } + + if( HBRI.bUseRounded ) + { + if( HBRI.bHighlighted ) + { + if( HBRI.bRoundedOutline ) + GUIStyle.DrawOutlinedBox(X+(ScaledBorderSize*2), Y, Width-(ScaledBorderSize*4), Height, ScaledBorderSize, BoxColor, OutlineColor); + else + { + Canvas.DrawColor = BoxColor; + Canvas.SetPos(X+(ScaledBorderSize*2), Y); + GUIStyle.DrawWhiteBox(Width-(ScaledBorderSize*4), Height); + } + + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*2, X, Y, ScaledBorderSize*2, Height, OutlineColor, true, false, true, false); + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*2, X+Width-(ScaledBorderSize*2), Y, ScaledBorderSize*2, Height, OutlineColor, false, true, false, true); + } + else + { + if( HBRI.bRoundedOutline ) + GUIStyle.DrawRoundedBoxOutlined(ScaledBorderSize, X, Y, Width, Height, BoxColor, OutlineColor); + else GUIStyle.DrawRoundedBox(ScaledBorderSize*2, X, Y, Width, Height, BoxColor); + } + } + else GUIStyle.DrawOutlinedBox(X, Y, Width, Height, ScaledBorderSize, BoxColor, OutlineColor); + + if( HBRI.IconTex != None ) + { + if( HBRI.IconScale == 1.f ) + HBRI.IconScale = Height; + + IconW = HBRI.IconScale - (HBRI.bUseRounded ? 0.f : ScaledBorderSize); + + IconXL = X + (IconW/2); + IconYL = Y + (Height / 2) - (IconW / 2); + + if( HudOutlineColor != DefaultHudOutlineColor ) + { + Canvas.DrawColor = HudOutlineColor; + if( !bUseAlpha ) + Canvas.DrawColor.A = 255; + } + else Canvas.SetDrawColor(255, 255, 255, bUseAlpha ? byte(HBRI.Alpha) : 255); + + Canvas.SetPos(IconXL, IconYL); + Canvas.DrawRect(IconW, IconW, HBRI.IconTex); + } + + Canvas.DrawColor = TextColor; + + if( HBRI.StringArray.Length < 1 ) + { + Canvas.TextSize(Text, XL, YL, TextScale, TextScale); + + if( HBRI.IconTex != None ) + TextX = IconXL + IconW + (ScaledBorderSize*4); + else TextX = X + (Width / 2) - (XL / 2); + + TextY = Y + (Height / 2) - (YL / 2); + if( !HBRI.bUseRounded ) + { + TextY -= (ScaledBorderSize/2); + + // Always one pixel off, could not find the source + if( Canvas.SizeX != 1920 ) + TextY -= GUIStyle.ScreenScale(1.f); + } + + if( HBRI.bUseOutline ) + GUIStyle.DrawTextShadow(Text, TextX, TextY, 1, TextScale); + else + { + Canvas.SetPos(TextX, TextY); + Canvas.DrawText(Text,, TextScale, TextScale, FRI); + } + } + else + { + TextY = Y + ((Height*0.05)/2); + + for( i=0; i 0 ) + { + Canvas.DrawColor = PlayerBarShadowColor; + Canvas.SetPos(PerkXL+1, PerkYL+1); + Canvas.DrawTile(MyKFPRI.CurrentPerkClass.default.PrestigeIcons[PrestigeLevel - 1], scale_w, scale_w, 0, 3, 256, 256); + + Canvas.DrawColor = WhiteColor; + Canvas.SetPos(PerkXL, PerkYL); + Canvas.DrawTile(MyKFPRI.CurrentPerkClass.default.PrestigeIcons[PrestigeLevel - 1], scale_w, scale_w, 0, 3, 256, 256); + } + + if (PrestigeLevel > 0) + { + Canvas.DrawColor = WhiteColor; + Canvas.SetPos(PerkXL + ((scale_w/2) - ((scale_w*PrestigeIconScale)/2)), PerkYL + ((scale_w/2) - ((scale_w*PrestigeIconScale)/2)) - 4); + Canvas.DrawRect(scale_w*PrestigeIconScale, scale_w*PrestigeIconScale, PerkIcon); + } + else + { + Canvas.DrawColor = PlayerBarShadowColor; + Canvas.SetPos(PerkXL+1, PerkYL+1); + Canvas.DrawRect(scale_w, scale_w, PerkIcon); + + Canvas.DrawColor = WhiteColor; + Canvas.SetPos(PerkXL, PerkYL); + Canvas.DrawRect(scale_w, scale_w, PerkIcon); + } + + //Perk Stars + if( PerkLevel > 0 ) + { + StarCount = 0; + PerkIconSize = GUIStyle.ScreenScale(default.PerkIconSize); + StarXL = PerkXL + scale_w; + + for ( i = 0; i < PerkLevel; i++ ) + { + StarYL = (PerkYL + (scale_w - PerkIconSize)) - (StarCount * PerkIconSize); + + Canvas.DrawColor = PlayerBarShadowColor; + Canvas.SetPos(StarXL+1, StarYL+1); + Canvas.DrawRect(PerkIconSize, PerkIconSize, PerkStarIcon); + + Canvas.DrawColor = WhiteColor; + Canvas.SetPos(StarXL, StarYL); + Canvas.DrawRect(PerkIconSize, PerkIconSize, PerkStarIcon); + + if( ++StarCount == MaxStarsPerRow ) + { + StarCount = 0; + StarXL += PerkIconSize; + } + } + } + + // Progress Bar + PerkProgressSize = GUIStyle.ScreenScale(76); + PerkProgressX = Canvas.ClipX * 0.007; + PerkProgressY = PerkYL - (scale_w / 2); + Canvas.DrawColor = WhiteColor; + + bDisplayingProgress = true; + LevelProgressBar = KFPlayerOwner.GetPerkLevelProgressPercentage(KFPlayerOwner.CurrentPerk.Class) / 100.f; + DrawProgressBar(PerkProgressX,PerkProgressY-PerkProgressSize*0.12f,PerkProgressSize*2.f,PerkProgressSize*0.125f,VisualProgressBar); + DrawXPEarned(PerkProgressX + (PerkProgressSize/2), PerkProgressY-(PerkProgressSize*0.125f)-(ScaledBorderSize*2)); + } + } + + // Trader Distance/Objective Container + if( KFGRI != None ) + { + if( KFGRI.OpenedTrader != None || KFGRI.NextTrader != None ) + { + T = KFGRI.OpenedTrader != None ? KFGRI.OpenedTrader : KFGRI.NextTrader; + if( T != None ) + { + FontScalar = OriginalFontScalar + GUIStyle.ScreenScale(0.3); + + TraderDistanceText = "Trader"$": "$int(VSize(T.Location - KFPH.Location) / 100.f)$"m"; + Canvas.TextSize(TraderDistanceText, XL, YL, FontScalar, FontScalar); + + Canvas.DrawColor = FontColor; + GUIStyle.DrawTextShadow(TraderDistanceText, Canvas.ClipX*0.015, YL, 1, FontScalar); + } + } + + //Map Objectives + MapObjective = KFInterface_MapObjective(KFGRI.CurrentObjective); + if( MapObjective == None ) + MapObjective = KFInterface_MapObjective(KFGRI.PreviousObjective); + + if( MapObjective != None && (MapObjective.IsActive() || ((MapObjective.IsComplete() || MapObjective.HasFailedObjective()) && KFGRI.bWaveIsActive)) ) + { + FontScalar = OriginalFontScalar + GUIStyle.ScreenScale(0.155); + + ObjectivePadding = GUIStyle.ScreenScale(8); + ObjectiveH = GUIStyle.ScreenScale(142); + ObjectiveSize = ObjectiveH * 2.25; + + ObjX = Canvas.ClipX*0.015; + ObjY = T != None ? (YL * 2) + ObjectivePadding : ObjectiveH; + + ObjectiveTitle = Localize("Objectives", "ObjectiveTitle", "KFGame"); + Canvas.TextSize(ObjectiveTitle, XL, ObjYL, FontScalar, FontScalar); + + GUIStyle.DrawRoundedBoxOutlined(ScaledBorderSize, ObjX, ObjY, ObjectiveSize, ObjectiveH, HudMainColor, HudOutlineColor); + + // Objective Title + XPos = ObjX + ObjectivePadding; + YPos = ObjY + ((ObjectivePadding-ScaledBorderSize) / 2); + + if( MapObjective.GetIcon() != None ) + { + Canvas.DrawColor = FontColor; + Canvas.SetPos(XPos + ScaledBorderSize, YPos + (ScaledBorderSize*2.5) + 0.5); + Canvas.DrawTile(MapObjective.GetIcon(), ObjYL - (ScaledBorderSize*4), ObjYL - (ScaledBorderSize*4), 0, 0, 256, 256); + + XPos += (ObjYL - (ScaledBorderSize*2)) + ObjectivePadding; + } + + Canvas.DrawColor = FontColor; + Canvas.SetPos(XPos, YPos); + Canvas.DrawText(ObjectiveTitle,, FontScalar, FontScalar, FRI); + + // Objective Progress + if( MapObjective.IsComplete() ) + { + ObjectiveProgress = Localize("Objectives", "SuccessString", "KFGame"); + Canvas.SetDrawColor(0, 255, 0, 255); + } + else if( MapObjective.HasFailedObjective() ) + { + ObjectiveProgress = Localize("Objectives", "FailedString", "KFGame"); + Canvas.SetDrawColor(255, 0, 0, 255); + } + else + { + ObjectiveProgress = MapObjective.GetProgressText(); + Canvas.DrawColor = FontColor; + } + Canvas.TextSize(ObjectiveProgress, XL, YL, FontScalar, FontScalar); + + XPos = ObjX + (ObjectiveSize - XL - ObjectivePadding); + + Canvas.SetPos(XPos, YPos); + Canvas.DrawText(ObjectiveProgress,, FontScalar, FontScalar, FRI); + + // Objective Reward + Canvas.SetDrawColor(0, 255, 0, 255); + FontScalar = OriginalFontScalar + GUIStyle.ScreenScale(0.1); + + ObjectiveReward = "£" $ (MapObjective.HasFailedObjective() ? 0 : MapObjective.GetDoshReward()); + Canvas.TextSize(ObjectiveReward, XL, YL, FontScalar, FontScalar); + + XPos = ObjX + (ObjectiveSize - XL - ObjectivePadding); + YPos = ObjY + ((ObjectiveH-ObjYL)/2) + (YL/2); + + Canvas.SetPos(XPos, YPos); + Canvas.DrawText(ObjectiveReward,, FontScalar, FontScalar, FRI); + + // Objective Description + ObjectiveDesc = MapObjective.GetLocalizedShortDescription(); + if( MapObjective.IsComplete() || MapObjective.HasFailedObjective() ) + Canvas.DrawColor = FontColor * 0.5f; + else Canvas.DrawColor = FontColor; + + YPos = ObjY + ((ObjectiveH-ObjYL)/1.5f) - (YL/1.5f) - (ScaledBorderSize*2); + XPos = ObjX + ObjectivePadding; + + Canvas.SetPos(XPos, YPos); + Canvas.DrawText(ObjectiveDesc,, FontScalar, FontScalar, FRI); + + // Status Message for the Objective + MapObjective.GetLocalizedStatus(ObjectiveStatusMessage, bStatusWarning, bStatusNotification); + if( ObjectiveStatusMessage != "" ) + { + if( bool(bStatusWarning) ) + Canvas.SetDrawColor(255, Clamp(Sin(WorldInfo.TimeSeconds * 12) * 200 + 200, 0, 200), 0, 255); + else Canvas.DrawColor = FontColor; + + Canvas.TextSize(ObjectiveStatusMessage, XL, YL, FontScalar, FontScalar); + + XPos = ObjX + ObjectivePadding; + YPos += YL; + + Canvas.SetPos(XPos, YPos); + Canvas.DrawText(ObjectiveStatusMessage,, FontScalar, FontScalar, FRI); + } + } + } + + CurrentWeapon = KFWeapon(KFPH.Weapon); + if( CurrentWeapon != None ) + { + FontScalar = OriginalFontScalar + GUIStyle.ScreenScale(0.1); + + // Weapon Name + if( CachedWeaponInfo.Weapon != CurrentWeapon ) + { + if( KFGRI != None ) + { + TraderItems = KFGRI.TraderItems; + if( TraderItems != None ) + { + Index = TraderItems.SaleItems.Find('ClassName', CurrentWeapon.Class.Name); + if( Index != INDEX_NONE ) + { + WeaponName = TraderItems.SaleItems[Index].WeaponDef.static.GetItemName(); + } + } + } + + if( WeaponName == "" ) + WeaponName = CurrentWeapon.ItemName; + + CachedWeaponInfo.Weapon = CurrentWeapon; + CachedWeaponInfo.WeaponName = WeaponName; + } + else + { + WeaponName = CachedWeaponInfo.WeaponName; + } + + Canvas.TextSize(WeaponName, XL, YL, FontScalar, FontScalar); + Canvas.DrawColor = FontColor; + GUIStyle.DrawTextShadow(WeaponName, (SizeX * 0.95f) - XL, SizeY * 0.892f, 1, FontScalar); + + Canvas.Font = GUIStyle.PickFont(OriginalFontScalar,true); + + BoxXL = SizeX * 0.915; + FontScalar = OriginalFontScalar + GUIStyle.ScreenScale(0.3); + + HBRI.Justification = HUDA_Left; + + if( Inv != None ) + { + // Grenades + HBRI.IconTex = GrenadesIcon; + DrawHUDBox(BoxXL, BoxYL, BoxSW, BoxSH, string(Inv.GrenadeCount), FontScalar, HBRI); + } + + // ToDo - Find better way to check for weapons like the Welder and Med Syringe + if( CurrentWeapon.UsesAmmo() || CurrentWeapon.IsA('KFWeap_Welder') || CurrentWeapon.IsA('KFWeap_Healer_Syringe') ) + { + bSingleFire = CurrentWeapon.MagazineCapacity[0] <= 1; + bHasSecondaryAmmo = CurrentWeapon.UsesSecondaryAmmo(); + + AmmoCount = CurrentWeapon.AmmoCount[0]; + MagCount = bSingleFire ? CurrentWeapon.GetSpareAmmoForHUD() : FCeil(float(CurrentWeapon.GetSpareAmmoForHUD()) / float(CurrentWeapon.MagazineCapacity[0])); + + if( CurrentWeapon.IsA('KFWeap_Welder') || CurrentWeapon.IsA('KFWeap_Healer_Syringe') ) + { + bSingleFire = true; + MagCount = AmmoCount; + } + + // Clips + HBRI.IconTex = GetClipIcon(CurrentWeapon, bSingleFire); + DrawHUDBox(BoxXL, BoxYL, BoxSW, BoxSH, string(MagCount), FontScalar, HBRI); + + // Bullets + if( !bSingleFire ) + { + HBRI.IconTex = GetBulletIcon(CurrentWeapon); + DrawHUDBox(BoxXL, BoxYL, BoxSW, BoxSH, string(AmmoCount), FontScalar, HBRI); + } + + // Secondary Ammo + if( bHasSecondaryAmmo ) + { + if( CurrentWeapon.AmmoCount[class'KFWeapon'.const.ALTFIRE_FIREMODE] <= 0 ) + { + SecondaryXL = BoxXL; + SecondaryYL = BoxYL - BoxSH; + + HBRI.IconTex = None; + HBRI.TextColor = MakeColor(255, Clamp(Sin(WorldInfo.TimeSeconds * 12) * 200 + 200, 0, 200), 0, 255); + + DrawHUDBox(SecondaryXL, SecondaryYL, BoxSW, BoxSH, "RELOAD", FontScalar * 0.75, HBRI); + + HBRI.TextColor = FontColor; + } + + HBRI.IconTex = GetSecondaryAmmoIcon(CurrentWeapon); + DrawHUDBox(BoxXL, BoxYL, BoxSW, BoxSH, CurrentWeapon.GetSecondaryAmmoForHUD(), FontScalar, HBRI); + } + } + + // Flashlight + FlashlightCharge = KFPH.BatteryCharge; + if( FlashlightCharge != KFPH.default.BatteryCharge || KFPH.bFlashlightOn ) + { + HBRI.IconTex = KFPH.bFlashlightOn ? FlashlightIcon : FlashlightOffIcon; + DrawHUDBox(BoxXL, BoxYL, BoxSW, BoxSH, string(int(KFPH.BatteryCharge)), FontScalar, HBRI); + } + } + + // Speed + DrawSpeedMeter(); + + // Inventory + if ( bDisplayInventory ) + { + DrawInventory(); + } +} + +function RefreshInventory() +{ + if ( `TimeSince(InventoryFadeStartTime) > InventoryFadeInTime ) + { + if ( `TimeSince(InventoryFadeStartTime) > InventoryFadeTime - InventoryFadeOutTime ) + InventoryFadeStartTime = `TimeSince(InventoryFadeInTime + ((InventoryFadeTime - `TimeSince(InventoryFadeStartTime)) * InventoryFadeInTime)); + else InventoryFadeStartTime = `TimeSince(InventoryFadeInTime); + } +} + +function DrawInventory() +{ + local InventoryCategory Categorized[MAX_WEAPON_GROUPS]; + local int i, j; + local byte FadeAlpha, OrgFadeAlpha, ItemIndex; + local float TempSize, TempX, TempY, TempWidth, TempHeight, TempBorder, OriginalFontScalar, FontScalar, AmmoFontScalar, CatagoryFontScalar, UpgradeX, UpgradeY, UpgradeW, UpgradeH, EmptyW, EmptyH, EmptyX, EmptyY; + local float XL, YL, XS, YS; + local string WeaponName, S; + local bool bHasAmmo; + local KFWeapon KFW; + local Color MainColor, OutlineColor; + local HUDBoxRenderInfo HBRI; + + if( PlayerOwner.Pawn == None || PlayerOwner.Pawn.InvManager == None ) + { + return; + } + + TempSize = `TimeSince(InventoryFadeStartTime); + if ( TempSize > InventoryFadeTime ) + { + bDisplayInventory = false; + return; + } + + if ( TempSize < InventoryFadeInTime ) + { + FadeAlpha = int((TempSize / InventoryFadeInTime) * 255.0); + } + else if ( TempSize > InventoryFadeTime - InventoryFadeOutTime ) + { + FadeAlpha = int((1.0 - ((TempSize - (InventoryFadeTime - InventoryFadeOutTime)) / InventoryFadeOutTime)) * 255.0); + } + else + { + FadeAlpha = 255; + } + + foreach PlayerOwner.Pawn.InvManager.InventoryActors( class'KFWeapon', KFW ) + { + if ( KFW.InventoryGroup < MAX_WEAPON_GROUPS ) + { + Categorized[KFW.InventoryGroup].Items[Categorized[KFW.InventoryGroup].ItemCount++] = KFW; + } + } + + Canvas.Font = GUIStyle.PickFont(OriginalFontScalar); + FontScalar = OriginalFontScalar; + AmmoFontScalar = OriginalFontScalar; + CatagoryFontScalar = OriginalFontScalar; + + TempWidth = InventoryBoxWidth * Canvas.ClipX; + TempHeight = InventoryBoxHeight * Canvas.ClipX; + TempBorder = BorderSize * Canvas.ClipX; + + TempX = (Canvas.ClipX/2) - (((TempWidth + TempBorder) * MAX_WEAPON_GROUPS)/2); + + OrgFadeAlpha = FadeAlpha; + + for ( i = 0; i < MAX_WEAPON_GROUPS; i++ ) + { + if( SelectedInventoryCategory == i && MaxWeaponIndex[i] != 0 ) + { + if( SelectedInventoryIndex == 0 && MinWeaponIndex[i] != 0 ) + { + MinWeaponIndex[i] = 0; + } + + if( SelectedInventoryIndex > MaxWeaponIndex[i] ) + MinWeaponIndex[i] = SelectedInventoryIndex - MaxWeaponsPerCatagory; + else if( SelectedInventoryIndex < MinWeaponIndex[i] ) + MinWeaponIndex[i]--; + } + else if( MinWeaponIndex[i] != 0 ) + { + MinWeaponIndex[i] = 0; + } + + TempY = InventoryY * Canvas.ClipY; + + HBRI.Justification = HUDA_Top; + HBRI.JustificationPadding = 24; + HBRI.TextColor = FontColor; + HBRI.Alpha = OrgFadeAlpha; + HBRI.bUseOutline = false; + + DrawHUDBox(TempX, TempY, TempWidth, TempHeight * 0.25, GetWeaponCatagoryName(i), CatagoryFontScalar, HBRI); + + if ( Categorized[i].ItemCount != 0 ) + { + for ( j = 0; j < Categorized[i].ItemCount; j++ ) + { + if( j < MinWeaponIndex[i] ) + continue; + + KFW = Categorized[i].Items[j]; + bHasAmmo = KFW.HasAnyAmmo(); + if( !bHasAmmo ) + FadeAlpha *= 0.5; + else if( FadeAlpha != OrgFadeAlpha ) + FadeAlpha = OrgFadeAlpha; + + OutlineColor = KFW.CurrentWeaponUpgradeIndex > 0 ? MakeColor(255, 255, 0) : HudOutlineColor; + OutlineColor.A = Min(OrgFadeAlpha, default.DefaultHudOutlineColor.A); + + if ( i == SelectedInventoryCategory && j == SelectedInventoryIndex ) + { + MainColor = HudOutlineColor * 0.5; + MainColor.A = Min(FadeAlpha, DefaultHudOutlineColor.A); + + if( KFW.CurrentWeaponUpgradeIndex > 0 ) + GUIStyle.DrawRoundedBoxOutlined(ScaledBorderSize, TempX, TempY, TempWidth, TempHeight, MainColor, OutlineColor); + else GUIStyle.DrawRoundedBox(ScaledBorderSize*2, TempX, TempY, TempWidth, TempHeight, MainColor); + + if( KFGRI != None && KFGRI.TraderItems.GetItemIndicesFromArche(ItemIndex, KFW.Class.Name) ) + WeaponName = KFGRI.TraderItems.SaleItems[ItemIndex].WeaponDef.static.GetItemName(); + else WeaponName = KFW.ItemName; + + Canvas.DrawColor = WhiteColor; + Canvas.DrawColor.A = FadeAlpha; + Canvas.TextSize(WeaponName, XS, YS, FontScalar, FontScalar); + + while( XS > TempWidth ) + { + FontScalar -= 0.1; + Canvas.TextSize(WeaponName, XS, YS, FontScalar, FontScalar); + } + + Canvas.SetPos(TempX + ((TempWidth/2) - (XS/2)), TempY + (YS/4)); + Canvas.DrawText(WeaponName,, FontScalar, FontScalar); + } + else + { + MainColor = HudMainColor; + MainColor.A = Min(FadeAlpha, default.DefaultHudMainColor.A); + + GUIStyle.DrawRoundedBox(ScaledBorderSize*2, TempX, TempY, TempWidth, TempHeight, MainColor); + } + + if( KFW.CurrentWeaponUpgradeIndex > 0 ) + { + S = "*"$KFW.CurrentWeaponUpgradeIndex; + Canvas.TextSize(S, XS, YS, OriginalFontScalar, OriginalFontScalar); + + UpgradeW = XS + (ScaledBorderSize*4); + UpgradeH = YS + (ScaledBorderSize*4); + UpgradeX = TempX + ScaledBorderSize; + UpgradeY = TempY + (TempHeight/2) - (UpgradeH/2); + + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*2, UpgradeX, UpgradeY, UpgradeW, UpgradeH, OutlineColor, false, true, false, true); + + Canvas.DrawColor = WhiteColor; + Canvas.DrawColor.A = FadeAlpha; + + GUIStyle.DrawTextShadow(S, UpgradeX + ((UpgradeW/2) - (XS/2)), UpgradeY + (UpgradeH/2) - (YS/2), 2, OriginalFontScalar); + } + + Canvas.DrawColor = WhiteColor; + Canvas.DrawColor.A = FadeAlpha; + + XL = TempWidth * 0.75; + YL = TempHeight * 0.5; + + Canvas.SetPos(TempX + ((TempWidth/2) - (XL/2)), TempY + ((TempHeight/2) - (YL/2))); + Canvas.DrawRect(XL, YL, KFW.WeaponSelectTexture); + + if( KFW.static.UsesAmmo() ) + { + S = KFW.AmmoCount[class'KFWeapon'.const.DEFAULT_FIREMODE]$"/"$KFW.SpareAmmoCount[class'KFWeapon'.const.DEFAULT_FIREMODE]; + Canvas.TextSize(S, XS, YS, AmmoFontScalar, AmmoFontScalar); + Canvas.SetPos(TempX + (TempWidth - XS) - (ScaledBorderSize*2), TempY + (TempHeight - YS) - (ScaledBorderSize*2)); + Canvas.DrawText(S,, AmmoFontScalar, AmmoFontScalar); + } + + if( KFW.UsesSecondaryAmmo() && KFW.bCanRefillSecondaryAmmo ) + { + if( KFW.SpareAmmoCount[class'KFWeapon'.const.ALTFIRE_FIREMODE] <= 0 ) + S = "[" @ string(KFW.AmmoCount[class'KFWeapon'.const.ALTFIRE_FIREMODE]) @ "]"; + else S = "[" @ KFW.AmmoCount[class'KFWeapon'.const.ALTFIRE_FIREMODE]$"/"$KFW.SpareAmmoCount[class'KFWeapon'.const.ALTFIRE_FIREMODE] @ "]"; + + Canvas.TextSize(S, XS, YS, AmmoFontScalar, AmmoFontScalar); + Canvas.SetPos(TempX + (ScaledBorderSize*2), TempY + (TempHeight - YS) - (ScaledBorderSize*2)); + Canvas.DrawText(S,, AmmoFontScalar, AmmoFontScalar); + } + + if( !bHasAmmo ) + { + S = "EMPTY"; + Canvas.TextSize(S, XS, YS, OriginalFontScalar, OriginalFontScalar); + + EmptyW = XS * 1.25f; + EmptyH = YS * 1.25f; + EmptyX = TempX + ((TempWidth/2) - (EmptyW/2)); + EmptyY = TempY + ((TempHeight/2) - (EmptyH/2)); + + MainColor = DefaultHudMainColor; + MainColor.A = Min(FadeAlpha, default.DefaultHudMainColor.A); + + GUIStyle.DrawRoundedBox(ScaledBorderSize*2, EmptyX, EmptyY, EmptyW, EmptyH, MainColor); + + Canvas.DrawColor = WhiteColor; + Canvas.DrawColor.A = FadeAlpha; + Canvas.SetPos(EmptyX + (EmptyW/2) - (XS/2), EmptyY + (EmptyH/2) - (YS/2)); + Canvas.DrawText(S,, OriginalFontScalar, OriginalFontScalar); + } + + if( (TempY + TempHeight) > (Canvas.ClipY * 0.75) ) + { + if( MaxWeaponsPerCatagory == 0 ) + { + MaxWeaponsPerCatagory = j; + } + + MaxWeaponIndex[i] = j; + break; + } + + TempY += TempHeight; + } + } + + TempX += TempWidth + TempBorder; + } +} + +function string GetWeaponCatagoryName(int Index) +{ + switch(Index) + { + case 0: + return class'KFGFxHUD_WeaponSelectWidget'.default.PrimaryString; + case 1: + return class'KFGFxHUD_WeaponSelectWidget'.default.SecondaryString; + case 2: + return class'KFGFxHUD_WeaponSelectWidget'.default.MeleeString; + case 3: + return class'KFGFxHUD_WeaponSelectWidget'.default.EquiptmentString; + default: + return "ERROR!!"; + } +} + +function DrawPriorityMessage() +{ + local float XS, YS, TextX, TextY, IconX, IconY, BoxW, OrgBoxW, BoxH, OrgBoxH, BoxX, BoxY, OrignalFontScalar, FontScalar, Box2W, OrgBox2W, Box2H, OrgBox2H, Box2X, Box2Y, Box3W, Box3X, SecondaryXS, SecondaryYS, SecondaryScaler; + local float TempSize, BoxAlpha, SecondaryBoxAlpha; + local bool bHasIcon, bHasSecondaryIcon, bHasSecondary, bAlignTop, bAlignBottom, bAnimFinished; + + TempSize = `TimeSince(PriorityMessage.StartTime); + + Canvas.Font = GUIStyle.PickFont(OrignalFontScalar); + + bHasIcon = PriorityMessage.Icon != None; + bHasSecondaryIcon = PriorityMessage.SecondaryIcon != None; + bHasSecondary = PriorityMessage.SecondaryText != ""; + + FontScalar = OrignalFontScalar + GUIStyle.ScreenScale(0.85f); + Canvas.TextSize(PriorityMessage.PrimaryText, XS, YS, FontScalar, FontScalar); + + if( bHasSecondary ) + { + SecondaryScaler = OrignalFontScalar + GUIStyle.ScreenScale(0.3f); + Canvas.TextSize(PriorityMessage.SecondaryText, SecondaryXS, SecondaryYS, SecondaryScaler, SecondaryScaler); + BoxW = FMax(XS,SecondaryXS + (SecondaryXS/2))+(YS*2)*2; + } + else BoxW = XS+(YS*2)*2; + BoxH = YS; + + OrgBoxW = BoxW; + OrgBoxH = BoxH; + + if( PriorityMessage.FadeInTime - TempSize > 0 ) + { + BoxAlpha = (PriorityMessage.FadeInTime - TempSize) / PriorityMessage.FadeInTime; + BoxAlpha = 1.f - BoxAlpha; + } + else if( (PriorityMessage.LifeTime - TempSize) < PriorityMessage.FadeOutTime ) + { + BoxAlpha = (PriorityMessage.LifeTime - TempSize) / PriorityMessage.FadeOutTime; + } + else + { + BoxAlpha = 1.f; + } + + if( PriorityMessage.PrimaryAnim == ANIM_SLIDE ) + BoxW = Lerp(BoxH, BoxW, BoxAlpha); + else BoxH = Lerp(0, BoxH, BoxAlpha); + + if( TempSize > PriorityMessage.LifeTime ) + { + PriorityMessage = default.PriorityMessage; + CurrentPriorityMessageA = 0; + CurrentSecondaryMessageA = 0; + return; + } + + BoxX = CenterX - (BoxW/2); + BoxY = (CenterY*0.5) - (BoxH/2); + + TextX = BoxX + (BoxW/2) - (XS/2); + TextY = BoxY + (BoxH/2) - (YS/2); + + if( bHasIcon ) + GUIStyle.DrawOutlinedBox(BoxX+BoxH, BoxY, BoxW-(BoxH*2), BoxH, ScaledBorderSize, HudMainColor, HudOutlineColor); + else GUIStyle.DrawRoundedBoxOutlined(ScaledBorderSize, BoxX, BoxY, BoxW, BoxH, HudMainColor, HudOutlineColor); + + bAnimFinished = (PriorityMessage.PrimaryAnim == ANIM_SLIDE ? BoxW >= OrgBoxW : BoxH >= OrgBoxH) && (TempSize+PriorityMessage.FadeInTime+0.5f) > 1.f; + if( bAnimFinished ) + { + if( CurrentPriorityMessageA != 255 ) + { + CurrentPriorityMessageA += RandRange(3,10); + if( CurrentPriorityMessageA > 255 ) + CurrentPriorityMessageA = 255; + } + + Canvas.DrawColor = FontColor; + Canvas.DrawColor.A = CurrentPriorityMessageA; + GUIStyle.DrawTextBlurry(PriorityMessage.PrimaryText, TextX, TextY, FontScalar); + } + + if( bHasIcon ) + { + IconX = BoxX; + + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*2, IconX, BoxY, BoxH, BoxH, HudOutlineColor, true, false, true, false); + + Canvas.DrawColor = PriorityMessage.IconColor; + Canvas.SetPos(IconX, TextY); + Canvas.DrawRect(BoxH, BoxH, PriorityMessage.Icon); + + IconX = BoxX+(BoxW-BoxH); + + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*2, IconX, BoxY, BoxH, BoxH, HudOutlineColor, false, true, false, true); + + Canvas.DrawColor = PriorityMessage.IconColor; + Canvas.SetPos(IconX, TextY); + Canvas.DrawRect(BoxH, BoxH, PriorityMessage.Icon); + } + + if( bHasSecondary && bAnimFinished && CurrentPriorityMessageA >= 255 ) + { + Box2H = SecondaryYS; + + if( PriorityMessage.SecondaryStartTime <= 0.f ) + PriorityMessage.SecondaryStartTime = WorldInfo.TimeSeconds; + + if( PriorityMessage.bSecondaryUsesFullLength ) + Box2W = BoxW - (BoxH * 2) + (ScaledBorderSize*2); + else + { + Box2W = FMin(SecondaryXS + (SecondaryXS/2), BoxW - (BoxH * 2)); + if( bHasSecondaryIcon ) + Box2W += Box2H*2; + } + + OrgBox2W = Box2W; + OrgBox2H = Box2H; + + SecondaryBoxAlpha = GUIStyle.TimeFraction(PriorityMessage.SecondaryStartTime, PriorityMessage.SecondaryStartTime+PriorityMessage.FadeInTime, WorldInfo.TimeSeconds); + if( PriorityMessage.SecondaryAnim == ANIM_SLIDE ) + Box2W = Lerp(0, Box2W, SecondaryBoxAlpha); + else Box2H = Lerp(0, Box2H, SecondaryBoxAlpha); + + Box2X = BoxX + (BoxW/2) - (Box2W/2); + + bAlignTop = PriorityMessage.SecondaryAlign == PR_TOP; + bAlignBottom = PriorityMessage.SecondaryAlign == PR_BOTTOM; + + if( bAlignTop ) + Box2Y = BoxY - Box2H; + else Box2Y = BoxY + BoxH; + + Box3X = Box2X+ScaledBorderSize; + Box3W = Box2W-(ScaledBorderSize*2); + + Canvas.DrawColor = HudMainColor; + Canvas.SetPos(Box3X, Box2Y); + GUIStyle.DrawWhiteBox(Box3W, Box2H); + + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*4, Box2X, Box2Y, ScaledBorderSize*2, Box2H, HudOutlineColor, bAlignTop, false, bAlignBottom, false); + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*4, Box2X+(Box2W-(ScaledBorderSize*2)), Box2Y, ScaledBorderSize*2, Box2H, HudOutlineColor, false, bAlignTop, false, bAlignBottom); + + TextX = Box3X + ((Box3W-SecondaryXS)/2); + TextY = Box2Y + ((Box2H-SecondaryYS)/2); + + if( PriorityMessage.SecondaryAnim == ANIM_SLIDE ? Box2W >= OrgBox2W : Box2H >= OrgBox2H ) + { + if( CurrentSecondaryMessageA != 255 ) + { + CurrentSecondaryMessageA += RandRange(3,10); + if( CurrentSecondaryMessageA > 255 ) + CurrentSecondaryMessageA = 255; + } + + Canvas.DrawColor = FontColor; + Canvas.DrawColor.A = CurrentSecondaryMessageA; + Canvas.SetPos(TextX, TextY); + Canvas.DrawText(PriorityMessage.SecondaryText,,SecondaryScaler,SecondaryScaler); + } + + if( bHasSecondaryIcon ) + { + IconX = Box3X+(ScaledBorderSize*4); + IconY = TextY+(ScaledBorderSize*2); + + Canvas.DrawColor = PriorityMessage.SecondaryIconColor; + Canvas.SetPos(IconX, IconY); + Canvas.DrawRect(Box2H-(ScaledBorderSize*4), Box2H-(ScaledBorderSize*4), PriorityMessage.SecondaryIcon); + + IconX = Box3X+Box3W-Box2H; + + Canvas.DrawColor = PriorityMessage.SecondaryIconColor; + Canvas.SetPos(IconX, IconY); + Canvas.DrawRect(Box2H-(ScaledBorderSize*4), Box2H-(ScaledBorderSize*4), PriorityMessage.SecondaryIcon); + } + } +} + +function ShowPriorityMessage(FPriorityMessage Msg) +{ + if( Msg.LifeTime <= 0.f ) + Msg.LifeTime = 15.f; + + Msg.LifeTime += 0.5f; + Msg.StartTime = WorldInfo.TimeSeconds; + PriorityMessage = Msg; +} + +function DrawNonCritialMessage( int Index, FCritialMessage Message, float X, float Y ) +{ + local float XS, YS, XL, YL, TX, BoxXS, BoxYS, FontScalar, TempSize, TY, OrgXL, BoxAlpha, AnimFadeIn, AnimFadeOut, DisplayTime; + local int i, FadeAlpha; + local array SArray; + local HUDBoxRenderInfo HBRI; + local bool bAnimFinished, bTextAnimFinished; + local string S; + local Color TextColor; + + Canvas.Font = GUIStyle.PickFont(FontScalar); + FontScalar += GUIStyle.ScreenScale(0.1); + TextColor = FontColor; + DisplayTime = Message.bUseAnimation ? 1.775f : NonCriticalMessageDisplayTime; + + TempSize = `TimeSince(Message.StartTime); + if ( TempSize > DisplayTime ) + { + NonCriticalMessages.RemoveItem(Message); + return; + } + + if( Message.Delimiter != "" ) + { + SArray = SplitString(Message.Text, Message.Delimiter); + if( SArray.Length > 0 ) + { + for( i=0; i 0 ) + { + BoxAlpha = (AnimFadeIn - TempSize) / AnimFadeIn; + BoxAlpha = 1.f - BoxAlpha; + } + else if( (DisplayTime - TempSize) < AnimFadeOut ) + { + BoxAlpha = (DisplayTime - TempSize) / AnimFadeOut; + } + else + { + BoxAlpha = 1.f; + } + + BoxAlpha = FClamp(BoxAlpha, 0.f, 1.f); + XL = Lerp(ScaledBorderSize*2, XL, BoxAlpha); + + bAnimFinished = XL >= OrgXL && (TempSize+AnimFadeIn+0.5f) > 1.f; + if( bAnimFinished ) + { + HBRI.StringArray = SArray; + S = Message.Text; + + bTextAnimFinished = NonCriticalMessages[Index].TextAnimAlpha >= 255; + if( !bTextAnimFinished ) + { + NonCriticalMessages[Index].TextAnimAlpha += RandRange(3,10); + if( NonCriticalMessages[Index].TextAnimAlpha > 255 ) + NonCriticalMessages[Index].TextAnimAlpha = 255; + } + + TextColor.A = NonCriticalMessages[Index].TextAnimAlpha; + } + } + else + { + if ( TempSize < NonCriticalMessageFadeInTime ) + { + FadeAlpha = int((TempSize / NonCriticalMessageFadeInTime) * 255.0); + } + else if ( TempSize > DisplayTime - NonCriticalMessageFadeOutTime ) + { + FadeAlpha = int((1.0 - ((TempSize - (DisplayTime - NonCriticalMessageFadeOutTime)) / NonCriticalMessageFadeOutTime)) * 255.0); + } + else + { + FadeAlpha = 255; + } + + HBRI.StringArray = SArray; + S = Message.Text; + } + + BoxXS = X - (XL / 2); + BoxYS = Y - ((YL + (ScaledBorderSize * 2)) * Index); + + if( (BoxYS + YL) > Canvas.ClipY ) + BoxYS = Canvas.ClipY - YL - (ScaledBorderSize * 2); + + HBRI.TextColor = TextColor; + HBRI.Alpha = FadeAlpha; + HBRI.bUseOutline = false; + HBRI.bUseRounded = true; + HBRI.bHighlighted = Message.bHighlight; + + DrawHUDBox(BoxXS, BoxYS, XL, YL, S, FontScalar, HBRI); +} + +function ShowNonCriticalMessage( string Message, optional string Delimiter, optional bool bHighlight, optional bool bUseAnimation ) +{ + local FCritialMessage Messages; + local int Index; + local float DisplayTime; + + if( KFPlayerOwner.IsBossCameraMode() ) + return; + + Index = NonCriticalMessages.Find('Text', Message); + if( Index != INDEX_NONE ) + { + DisplayTime = bUseAnimation ? 1.775f : NonCriticalMessageDisplayTime; + if ( `TimeSince(NonCriticalMessages[Index].StartTime) > NonCriticalMessageFadeInTime ) + { + if ( `TimeSince(NonCriticalMessages[Index].StartTime) > DisplayTime - NonCriticalMessageFadeOutTime ) + NonCriticalMessages[Index].StartTime = `TimeSince(NonCriticalMessageFadeInTime + ((DisplayTime - `TimeSince(NonCriticalMessages[Index].StartTime)) * NonCriticalMessageFadeInTime)); + else NonCriticalMessages[Index].StartTime = `TimeSince(NonCriticalMessageFadeInTime); + } + + return; + } + + if( NonCriticalMessages.Length >= MaxNonCriticalMessages ) + return; + + Messages.Text = Message; + Messages.Delimiter = Delimiter; + Messages.StartTime = WorldInfo.TimeSeconds; + Messages.bHighlight = bHighlight; + Messages.bUseAnimation = bUseAnimation; + + NonCriticalMessages.AddItem(Messages); +} + +function Texture GetClipIcon(KFWeapon Wep, bool bSingleFire) +{ + if( bSingleFire ) + return GetBulletIcon(Wep); + else if( Wep.FireModeIconPaths[Wep.const.DEFAULT_FIREMODE] != None && Wep.FireModeIconPaths[Wep.const.DEFAULT_FIREMODE].Name == 'UI_FireModeSelect_Flamethrower' ) + return FlameTankIcon; + + return ClipsIcon; +} + +function Texture GetBulletIcon(KFWeapon Wep) +{ + if( Wep.bUseAltFireMode ) + return GetSecondaryAmmoIcon(Wep); + else if( Wep.IsA('KFWeap_Bow_Crossbow') ) + return ArrowIcon; + else + { + if( KFWeap_ThrownBase(Wep) != None && Wep.FireModeIconPaths[class'KFWeap_ThrownBase'.const.THROW_FIREMODE] != None ) + { + Switch(Wep.FireModeIconPaths[class'KFWeap_ThrownBase'.const.THROW_FIREMODE].Name) + { + case 'UI_FireModeSelect_Grenade': + return PipebombIcon; + } + } + else if( Wep.FireModeIconPaths[Wep.const.DEFAULT_FIREMODE] != None ) + { + Switch(Wep.FireModeIconPaths[Wep.const.DEFAULT_FIREMODE].Name) + { + case 'UI_FireModeSelect_Flamethrower': + return FlameIcon; + case 'UI_FireModeSelect_Sawblade': + return SawbladeIcon; + case 'UI_FireModeSelect_BulletSingle': + if( Wep.MagazineCapacity[Wep.const.DEFAULT_FIREMODE] > 1 ) + return BulletsIcon; + return SingleBulletIcon; + case 'UI_FireModeSelect_Grenade': + return M79Icon; + case 'UI_FireModeSelect_MedicDart': + return SyringIcon; + case 'UI_FireModeSelect_Rocket': + return RocketIcon; + case 'UI_FireModeSelect_Electricity': + return BoltIcon; + case 'UI_FireModeSelect_BulletBurst': + return BurstBulletIcon; + } + } + } + + return BulletsIcon; +} + +function Texture GetSecondaryAmmoIcon(KFWeapon Wep) +{ + if( Wep.UsesSecondaryAmmo() && Wep.SecondaryAmmoTexture != None ) + { + Switch(Wep.SecondaryAmmoTexture.Name) + { + case 'GasTank': + return FlameTankIcon; + case 'MedicDarts': + return SyringIcon; + case 'UI_FireModeSelect_Grenade': + return M79Icon; + } + } + else if( Wep.FireModeIconPaths[Wep.const.ALTFIRE_FIREMODE] != None ) + { + Switch(Wep.FireModeIconPaths[Wep.const.ALTFIRE_FIREMODE].Name) + { + case 'UI_FireModeSelect_AutoTarget': + return AutoTargetIcon; + case 'UI_FireModeSelect_ManualTarget': + return ManualTargetIcon; + case 'UI_FireModeSelect_BulletBurst': + return BurstBulletIcon; + case 'UI_FireModeSelect_BulletSingle': + if( Wep.MagazineCapacity[Wep.ALTFIRE_FIREMODE] > 1 ) + return BulletsIcon; + else return SingleBulletIcon; + case 'UI_FireModeSelect_Electricity': + return BoltIcon; + case 'UI_FireModeSelect_MedicDart': + return SyringIcon; + } + } + + return SingleBulletIcon; +} + +function RenderKillMsg() +{ + local float Sc,PDSc,CurrentSc,XL,YL,TextXL,TextYL,PDYL,T,Y; + local string S; + local int i; + local KFInterface_MapObjective MapObjective; + + Canvas.Font = GUIStyle.PickFont(Sc); + Canvas.TextSize("A",XL,YL,Sc,Sc); + + PDSc = Sc*1.375f; + Canvas.TextSize("A",XL,PDYL,PDSc,PDSc); + + MapObjective = KFInterface_MapObjective(KFGRI.CurrentObjective); + if( MapObjective == None ) + MapObjective = KFInterface_MapObjective(KFGRI.PreviousObjective); + + if( MapObjective != None && (MapObjective.IsActive() || ((MapObjective.IsComplete() || MapObjective.HasFailedObjective()) && KFGRI.bWaveIsActive)) ) + Y = Canvas.ClipY*0.235; + else Y = Canvas.ClipY*0.15; + + for( i=0; i1 ? " kills" : " kill"); + else if( KillMessages[i].bPlayerDeath ) + S = (KillMessages[i].bSuicide ? "" : KillMessages[i].Name)$" UI_PerkIcons_TEX.UI_PerkIcon_ZED "$(KillMessages[i].OwnerPRI!=None ? KillMessages[i].OwnerPRI.GetHumanReadableName() : KillMessages[i].KillerName); + else S = (KillMessages[i].OwnerPRI!=None ? KillMessages[i].OwnerPRI.GetHumanReadableName() : KillMessages[i].KillerName)$" +"$KillMessages[i].Counter@KillMessages[i].Name$(KillMessages[i].Counter>1 ? " kills" : " kill"); + + CurrentSc = KillMessages[i].bPlayerDeath ? PDSc : Sc; + + if( T>6.f ) + { + KillMessages[i].CurrentXPosition -= RenderDelta*400.f; + + Canvas.TextSize(GUIStyle.StripTextureFromString(S),TextXL,TextYL,CurrentSc,CurrentSc); + if( (KillMessages[i].CurrentXPosition+TextXL) <= 0.f ) + { + KillMessages.Remove(i--,1); + continue; + } + } + else + { + KillMessages[i].CurrentXPosition += RenderDelta*200.f; + KillMessages[i].CurrentXPosition = FMin(KillMessages[i].CurrentXPosition, KillMessages[i].XPosition); + } + + Canvas.DrawColor = KillMessages[i].MsgColor; + GUIStyle.DrawTexturedString(S, KillMessages[i].CurrentXPosition, Y, CurrentSc,, true); + Y+=KillMessages[i].bPlayerDeath ? PDYL : YL; + } +} + +function color GetMsgColor( bool bDamage, int Count ) +{ + local float T; + + if( bDamage ) + { + if( Count>1500 ) + return MakeColor(148,0,0,255); + else if( Count>1000 ) + { + T = (Count-1000) / 500.f; + return MakeColor(148,0,0,255)*T + MakeColor(255,0,0,255)*(1.f-T); + } + else if( Count>500 ) + { + T = (Count-500) / 500.f; + return MakeColor(255,0,0,255)*T + MakeColor(255,255,0,255)*(1.f-T); + } + T = Count / 500.f; + return MakeColor(255,255,0,255)*T + MakeColor(0,255,0,255)*(1.f-T); + } + if( Count>20 ) + return MakeColor(255,0,0,255); + else if( Count>10 ) + { + T = (Count-10) / 10.f; + return MakeColor(148,0,0,255)*T + MakeColor(255,0,0,255)*(1.f-T); + } + else if( Count>5 ) + { + T = (Count-5) / 5.f; + return MakeColor(255,0,0,255)*T + MakeColor(255,255,0,255)*(1.f-T); + } + T = Count / 5.f; + return MakeColor(255,255,0,255)*T + MakeColor(0,255,0,255)*(1.f-T); +} + +static function string StripMsgColors( string S ) +{ + local int i; + + while( true ) + { + i = InStr(S,Chr(6)); + if( i==-1 ) + break; + S = Left(S,i)$Mid(S,i+2); + } + return S; +} + +static function string GetNameArticle( string S ) +{ + switch( Caps(Left(S,1)) ) // Check if a vowel, then an. + { + case "A": + case "E": + case "I": + case "O": + case "U": + return "an"; + } + return "a"; +} + +static function string GetNameOf( class Other ) +{ + local string S; + local class KFM; + + KFM = class(Other); + if( KFM!=None ) + return KFM.static.GetLocalizedName(); + + if( Other.Default.MenuName!="" ) + return Other.Default.MenuName; + + S = string(Other.Name); + if( Left(S,10)~="KFPawn_Zed" ) + S = Mid(S,10); + else if( Left(S,7)~="KFPawn_" ) + S = Mid(S,7); + S = Repl(S,"_"," "); + + return S; +} + +function ShowKillMessage(PlayerReplicationInfo PRI1, PlayerReplicationInfo PRI2, optional bool bDeathMessage=false, optional string KilledName, optional string KillerName) +{ + local FKillMessageType Msg; + local int i; + + if( bDeathMessage ) + { + Msg.bPlayerDeath = true; + Msg.KillerName = KillerName; + Msg.MsgTime = WorldInfo.TimeSeconds; + Msg.Name = KilledName; + Msg.bSuicide = KillerName == KilledName; + Msg.MsgColor = MakeColor(0, 162, 232, 255); + Msg.XPosition = SizeX*0.015; + + KillMessages.AddItem(Msg); + return; + } + + for( i=0; i Type ) +{ + local vector RandVect; + local EDamageOverTimeGroup DotType; + + RandVect.X = RandRange(-64, 64); + RandVect.Y = RandRange(-64, 64); + RandVect.Z = RandRange(-64, 64); + + DamagePopups[NextDamagePopupIndex].Damage = Amount; + DamagePopups[NextDamagePopupIndex].HitTime = WorldInfo.TimeSeconds; + DamagePopups[NextDamagePopupIndex].HitLocation = Pos; + DamagePopups[NextDamagePopupIndex].RandVect = RandVect; + + if( Type == None ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Unspecified]; + else + { + DotType = Type.default.DoT_Type; + if( DotType == DOT_Fire ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Fire]; + else if( DotType == DOT_Toxic ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Toxic]; + else if( DotType == DOT_Bleeding ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Bleeding]; + else if( Type.default.EMPPower > 0.f ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_EMP]; + else if( Type.default.FreezePower > 0.f ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Freeze]; + else if( class(Type) != None ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Flashbang]; + else if ( Amount < 100 ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Generic]; + else if ( Amount >= 175 ) + DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_High]; + else DamagePopups[NextDamagePopupIndex].FontColor = DamageMsgColors[DMG_Medium]; + } + + if( ++NextDamagePopupIndex >= DAMAGEPOPUP_COUNT) + NextDamagePopupIndex=0; +} + +function DrawDamage() +{ + local int i, Vel; + local float TimeSinceHit, TextWidth, TextHeight, Sc, TextX, TextY; + local vector HBScreenPos; + local string S; + + Canvas.Font = GUIStyle.PickFont(Sc); + + for( i=0; i < DAMAGEPOPUP_COUNT ; i++ ) + { + TimeSinceHit = `TimeSince(DamagePopups[i].HitTime); + if( TimeSinceHit > DamagePopupFadeOutTime || ( Normal(DamagePopups[i].HitLocation - PLCameraLoc) dot Normal(PLCameraDir) < 0.1 ) ) //don't draw if player faced back to the hit location + continue; + + S = string(DamagePopups[i].Damage); + + Canvas.TextSize(S,TextWidth,TextHeight,Sc,Sc); + Vel = RenderDelta*900.f; + + if ( i % 2 == 0 ) + DamagePopups[i].RandVect.X *= -1.f; + + DamagePopups[i].HitLocation += DamagePopups[i].RandVect*RenderDelta; + if( (TimeSinceHit/DamagePopupFadeOutTime) < 0.035f ) + DamagePopups[i].RandVect.Z += Vel*2; + else DamagePopups[i].RandVect.Z -= Vel; + + HBScreenPos = Canvas.Project(DamagePopups[i].HitLocation); + + TextX = HBScreenPos.X-(TextWidth*0.5f); + TextY = HBScreenPos.Y-(TextHeight*0.5f); + if( TextX < 0 || TextX > Canvas.ClipX || TextY < 0 || TextY > Canvas.ClipY ) + continue; + + Canvas.DrawColor = DamagePopups[i].FontColor; + Canvas.DrawColor.A = 255 * Cos(0.5f * Pi * TimeSinceHit/DamagePopupFadeOutTime); + + GUIStyle.DrawTextShadow(S, TextX, TextY, 1, Sc); + } +} + +function string GetSpeedStr() +{ + local int Speed; + local string S; + local vector Velocity2D; + + if ( KFPawn(PlayerOwner.Pawn) == None ) + return S; + + Velocity2D = PlayerOwner.Pawn.Velocity; + Velocity2D.Z = 0; + Speed = VSize(Velocity2D); + S = string(Speed) $ "/" $ int(PlayerOwner.Pawn.GroundSpeed); + + if ( Speed >= int(KFPawn(PlayerOwner.Pawn).SprintSpeed) ) + Canvas.SetDrawColor(0, 100, 255); + else if ( Speed >= int(PlayerOwner.Pawn.GroundSpeed) ) + Canvas.SetDrawColor(0, 206, 0); + else Canvas.SetDrawColor(255, 64, 64); + + return S; +} + +function DrawSpeedMeter() +{ + local float FontScalar, XL, YL; + local string S; + + S = GetSpeedStr() $ " ups"; + + Canvas.Font = GUIStyle.PickFont(FontScalar); + Canvas.TextSize(S,XL,YL,FontScalar,FontScalar); + + GUIStyle.DrawTextShadow(S, Canvas.ClipX - XL + (ScaledBorderSize*2), Canvas.ClipY * 0.80, 1, FontScalar); +} + +function DrawImportantHealthBar(float X, float Y, float W, float H, string S, float HealthFrac, Color MainColor, Color BarColor, Texture2D Icon, optional float BorderScale, optional bool bDisabled, optional bool bTrackDamageHistory, optional int Health, optional int HealthMax, optional bool bEaseInOut) +{ + local float FontScalar,MainBoxH,XPos,YPos,IconBoxX,IconBoxY,IconXL,IconYL,XL,YL,HistoryX; + local Color BoxColor,FadeColor; + + if( BorderScale == 0.f ) + BorderScale = ScaledBorderSize*2; + + if( bDisabled ) + MainColor.A = 95; + + MainBoxH = H * 2; + IconBoxX = X; + IconBoxY = Y; + + BoxColor = MakeColor(30, 30, 30, 255); + GUIStyle.DrawRoundedBoxEx(BorderScale, IconBoxX, IconBoxY, MainBoxH, MainBoxH, BoxColor, true, false, true, false); + + X += MainBoxH; + W -= MainBoxH; + + GUIStyle.DrawRoundedBoxEx(BorderScale, X, Y, W, H, MainColor, false, true, false, true); + + // ToDo - Make this code less ugly and more optimal. Moving the boss healthbar to a widget may help + if( bTrackDamageHistory ) + { + if( HealthBarDamageHistory.Length == 0 ) + HealthBarDamageHistory.Length = DamageHistoryNum+1; + + GUIStyle.DrawRoundedBoxEx(BorderScale, X, Y, W * HealthFrac, H, BarColor, false, !HealthBarDamageHistory[DamageHistoryNum].bDrawingHistory, false, !HealthBarDamageHistory[DamageHistoryNum].bDrawingHistory); + + if( DamageHistoryNum >= HealthBarDamageHistory.Length ) + HealthBarDamageHistory.Length = DamageHistoryNum+1; + + if( HealthBarDamageHistory[DamageHistoryNum].OldBarHealth != Health ) + { + if( HealthBarDamageHistory[DamageHistoryNum].OldBarHealth > Health ) + { + HealthBarDamageHistory[DamageHistoryNum].bDrawingHistory = true; + + if( HealthBarDamageHistory[DamageHistoryNum].OldHealth != Health ) + { + HealthBarDamageHistory[DamageHistoryNum].OldHealth = Health; + HealthBarDamageHistory[DamageHistoryNum].LastHealthUpdate = WorldInfo.RealTimeSeconds + 0.1f; + HealthBarDamageHistory[DamageHistoryNum].HealthUpdateEndTime = WorldInfo.RealTimeSeconds + 1.225f; + } + + HistoryX = X + (W * HealthFrac); + HealthFrac = FMin(float(HealthBarDamageHistory[DamageHistoryNum].OldBarHealth-Health) / float(HealthMax),1.f-HealthFrac); + + FadeColor = WhiteColor; + FadeColor.A = BarColor.A; + if( HealthBarDamageHistory[DamageHistoryNum].LastHealthUpdate < WorldInfo.RealTimeSeconds ) + { + FadeColor.A = Clamp(Sin(WorldInfo.RealTimeSeconds * 12) * 200 + 255, 0, BarColor.A); + + if( HealthBarDamageHistory[DamageHistoryNum].HealthUpdateEndTime < WorldInfo.RealTimeSeconds ) + { + HealthBarDamageHistory[DamageHistoryNum].OldBarHealth = Health; + HealthBarDamageHistory[DamageHistoryNum].bDrawingHistory = false; + HealthBarDamageHistory[DamageHistoryNum].LastHealthUpdate = 0.f; + HealthBarDamageHistory[DamageHistoryNum].HealthUpdateEndTime = 0.f; + } + } + + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize*2, HistoryX, Y, W * HealthFrac, H, FadeColor, false, true, false, true); + } + else + { + HealthBarDamageHistory[DamageHistoryNum].OldBarHealth = Health; + } + } + + DamageHistoryNum++; + } + else GUIStyle.DrawRoundedBoxEx(BorderScale, X, Y, W * HealthFrac, H, BarColor, false, true, false, true); + + if( BossShieldPct > 0.f ) + GUIStyle.DrawRoundedBoxEx(ScaledBorderSize, X, Y, W * BossShieldPct, H * 0.25, MakeColor(0, 162, 232, 255), false, true, false, false); + + Canvas.DrawColor = BoxColor; + Canvas.SetPos(IconBoxX+MainBoxH,IconBoxY); + GUIStyle.DrawCornerTex(BorderScale*2,3); + + IconXL = MainBoxH-BorderScale; + IconYL = IconXL; + + XPos = IconBoxX + (MainBoxH/2) - (IconXL/2); + YPos = IconBoxY + (MainBoxH/2) - (IconYL/2); + + Canvas.SetDrawColor(255, 255, 255, bDisabled ? 95 : 255); + Canvas.SetPos(XPos, YPos); + Canvas.DrawRect(IconXL, IconYL, Icon); + + if( S != "" ) + { + Canvas.Font = GUIStyle.PickFont(FontScalar); + Canvas.TextSize(S, XL, YL, FontScalar, FontScalar); + + XPos = X + BorderScale; + YPos = (Y+H) + (H/2) - (YL/2); + + Canvas.DrawColor = class'HUD'.default.WhiteColor; + GUIStyle.DrawTextShadow(S, XPos, YPos, 1, FontScalar); + } +} + +function DrawBossHealthBars() +{ + local int i; + local float BarH, BarW, MainBarX, MainBarY, MainBoxW, ArmorW, ArmorH; + local float ArmorPct; + local ArmorZoneInfo ArmorZone; + local KFPawn_Monster Pawn; + + if( bDisplayInventory || Scoreboard.bVisible || !bDisplayImportantHealthBar ) + return; + + Pawn = BossRef.GetMonsterPawn(); + + BarH = GUIStyle.DefaultHeight; + BarW = Canvas.ClipX * 0.45; + + MainBoxW = BarW * 0.125; + + MainBarX = (Canvas.ClipX/2) - (BarW/2) + (MainBoxW/2); + MainBarY = BarH; + + DrawImportantHealthBar(MainBarX, MainBarY, BarW, BarH, Pawn.static.GetLocalizedName(), FClamp(BossRef.GetHealthPercent(), 0.f, 1.f), HudMainColor, BossBattlePhaseColor, BossInfoIcon,,,true,Pawn.Health,Pawn.HealthMax,true); + + if( Pawn.ArmorInfo != None ) + { + ArmorW = BarW * 0.2; + ArmorH = BarH * 0.45; + + MainBarX = MainBarX + (BarW - ArmorW - ScaledBorderSize); + MainBarY += (BarH/2) + ArmorH + (ScaledBorderSize*2); + + for(i=0; i Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY) + return; + + IconSize = WorldInfo.static.GetResolutionBasedHUDScale() * MedicLockOnIconSize; + RealIconSize = FInterpEaseInOut(IconSize*2, IconSize, GUIStyle.TimeFraction(LockOnStartTime, LockOnEndTime, WorldInfo.RealTimeSeconds), 2.5); + + Canvas.DrawColor = IconColor; + Canvas.SetPos(ScreenPos.X - (RealIconSize / 2.0), ScreenPos.Y - (RealIconSize / 2.0)); + Canvas.DrawRect(RealIconSize, RealIconSize, MedicLockOnIcon); +} + +function DrawTraderIndicator() +{ + local KFTraderTrigger T; + + if( KFGRI == None || (KFGRI.OpenedTrader == None && KFGRI.NextTrader == None) ) + return; + + T = KFGRI.OpenedTrader != None ? KFGRI.OpenedTrader : KFGRI.NextTrader; + if( T != None ) + DrawDirectionalIndicator(T.Location, TraderArrow, Canvas.ClipY/33.f,, HudOutlineColor, class'KFGFxHUD_TraderCompass'.default.TraderString, true); +} + +final function Vector DrawDirectionalIndicator(Vector Loc, Texture Mat, float IconSize, optional float FontMult=1.f, optional Color DrawColor=WhiteColor, optional string Text, optional bool bDrawBackground) +{ + local rotator R; + local vector V,X; + local float XS,YS,FontScalar,BoxW,BoxH,BoxX,BoxY; + local Canvas.FontRenderInfo FI; + local bool bWasStencilEnabled; + + FI.bClipText = true; + Canvas.Font = GUIStyle.PickFont(FontScalar); + FontScalar *= FontMult; + + X = PLCameraDir; + + // First see if on screen. + V = Loc - PLCameraLoc; + if( (V Dot X)>0.997 ) // Front of camera. + { + V = Canvas.Project(Loc+vect(0,0,1.055)); + if( V.X>0 && V.Y>0 && V.X0 ) // Must flip pitch + R.Yaw = 32768-R.Yaw; + R.Yaw+=16384; + + // Check screen edge location. + V = FindEdgeIntersection(V.Y,-V.Z,IconSize); + + // Draw material. + Canvas.DrawColor = PlayerBarShadowColor; + Canvas.DrawColor.A = DrawColor.A; + Canvas.SetPos(V.X+1,V.Y+1); + Canvas.DrawRotatedTile(Mat,R,IconSize,IconSize,0,0,Mat.GetSurfaceWidth(),Mat.GetSurfaceHeight()); + + Canvas.DrawColor = DrawColor; + Canvas.SetPos(V.X,V.Y); + Canvas.DrawRotatedTile(Mat,R,IconSize,IconSize,0,0,Mat.GetSurfaceWidth(),Mat.GetSurfaceHeight()); + + if( bWasStencilEnabled ) + Canvas.EnableStencilTest(true); + + return V; +} + +final function vector FindEdgeIntersection( float XDir, float YDir, float ClampSize ) +{ + local vector V; + local float TimeXS,TimeYS,SX,SY; + + // First check for paralell lines. + if( Abs(XDir)<0.001f ) + { + V.X = Canvas.ClipX*0.5f; + if( YDir>0.f ) + V.Y = Canvas.ClipY-ClampSize; + else V.Y = ClampSize; + } + else if( Abs(YDir)<0.001f ) + { + V.Y = Canvas.ClipY*0.5f; + if( XDir>0.f ) + V.X = Canvas.ClipX-ClampSize; + else V.X = ClampSize; + } + else + { + SX = Canvas.ClipX*0.5f; + SY = Canvas.ClipY*0.5f; + + // Look for best intersection axis. + TimeXS = Abs((SX-ClampSize) / XDir); + TimeYS = Abs((SY-ClampSize) / YDir); + + if( TimeXS0.f ) + { + Canvas.DrawColor.A = 150; + Canvas.SetPos(X,Y); + Canvas.DrawTileStretched(ProgressBarTex,XS*Value,YS,0,0,ProgressBarTex.GetSurfaceWidth(),ProgressBarTex.GetSurfaceHeight()); + } +} + +function DrawXPEarned(float X, float Y) +{ + local int i; + local float EndTime, TextWidth, TextHeight, Sc, FadeAlpha; + local string S; + + Canvas.Font = GUIStyle.PickFont(Sc); + + for( i=0; i XPFadeOutTime ) + continue; + + S = "+"$string(XPPopups[i].XP)@"XP"; + Canvas.TextSize(S,TextWidth,TextHeight,Sc,Sc); + + if( XPPopups[i].bInit ) + { + XPPopups[i].XPos = X; + XPPopups[i].YPos = Y-(TextHeight*0.5f); + XPPopups[i].bInit = false; + } + + if( XPPopups[i].XPos > 0.f && XPPopups[i].XPos < Canvas.ClipX ) + XPPopups[i].XPos += Asin(0.75f * Pi * EndTime/XPFadeOutTime) * (i % 2 == 0 ? -XPPopups[i].RandX : XPPopups[i].RandX); + else XPPopups[i].XPos = FClamp(XPPopups[i].XPos, 0, Canvas.ClipX); + + XPPopups[i].YPos -= (RenderDelta*62.f) * XPPopups[i].RandY; + + FadeAlpha = 255 * Cos(0.5f * Pi * EndTime/XPFadeOutTime); + if( XPPopups[i].Icon != None ) + { + Canvas.DrawColor = PlayerBarShadowColor; + Canvas.DrawColor.A = FadeAlpha; + + Canvas.SetPos(XPPopups[i].XPos+1, XPPopups[i].YPos+1); + Canvas.DrawRect(TextHeight*1.25f, TextHeight*1.25f, XPPopups[i].Icon); + + Canvas.DrawColor = XPPopups[i].IconColor; + Canvas.DrawColor.A = FadeAlpha; + + Canvas.SetPos(XPPopups[i].XPos, XPPopups[i].YPos); + Canvas.DrawRect(TextHeight*1.25f, TextHeight*1.25f, XPPopups[i].Icon); + + Canvas.SetDrawColor(255, 255, 255, FadeAlpha); + GUIStyle.DrawTextShadow(S, XPPopups[i].XPos+(TextHeight*1.25f)+(ScaledBorderSize*2), XPPopups[i].YPos, 1, Sc); + } + else + { + Canvas.SetDrawColor(255, 255, 255, FadeAlpha); + GUIStyle.DrawTextShadow(S, XPPopups[i].XPos, XPPopups[i].YPos, 1, Sc); + } + } +} + +function DrawDoshEarned(float X, float Y) +{ + local int i; + local float EndTime, TextWidth, TextHeight, Sc, FadeAlpha; + local string S; + local Color DoshColor; + + Canvas.Font = GUIStyle.PickFont(Sc); + + for( i=0; i DoshFadeOutTime ) + continue; + + S = (DoshPopups[i].Dosh > 0 ? "+" : "")$string(DoshPopups[i].Dosh); + Canvas.TextSize(S,TextWidth,TextHeight,Sc,Sc); + + if( DoshPopups[i].Dosh > 0 ) + DoshColor = GreenColor; + else DoshColor = RedColor; + + if( DoshPopups[i].bInit ) + { + DoshPopups[i].XPos = X; + DoshPopups[i].YPos = Y-(TextHeight*0.5f); + DoshPopups[i].bInit = false; + } + + if( DoshPopups[i].XPos > 0.f && DoshPopups[i].XPos > 0 ) + DoshPopups[i].XPos += Asin(0.25f * Pi * EndTime/DoshFadeOutTime) * (i % 2 == 0 ? -DoshPopups[i].RandX : DoshPopups[i].RandX); + else DoshPopups[i].XPos = FClamp(DoshPopups[i].XPos, 0, Canvas.ClipX); + + DoshPopups[i].YPos -= (RenderDelta*72.f) * DoshPopups[i].RandY; + + FadeAlpha = 255 * Cos(0.5f * Pi * EndTime/DoshFadeOutTime); + Canvas.DrawColor = PlayerBarShadowColor; + Canvas.DrawColor.A = FadeAlpha; + + Canvas.SetPos(DoshPopups[i].XPos+1, DoshPopups[i].YPos+1); + Canvas.DrawTile(DoshEarnedIcon, TextHeight*1.25f, TextHeight*1.25f, 0, 0, 256, 256); + + Canvas.DrawColor = DoshColor; + Canvas.DrawColor.A = FadeAlpha; + + Canvas.SetPos(DoshPopups[i].XPos, DoshPopups[i].YPos); + Canvas.DrawTile(DoshEarnedIcon, TextHeight*1.25f, TextHeight*1.25f, 0, 0, 256, 256); + + GUIStyle.DrawTextShadow(S, DoshPopups[i].XPos+(TextHeight*1.25f)+(ScaledBorderSize*2), DoshPopups[i].YPos, 1, Sc); + } +} + +function NotifyXPEarned( int XP, Texture2D Icon, Color IconColor ) +{ + XPPopups[NextXPPopupIndex].XP = XP; + XPPopups[NextXPPopupIndex].StartTime = WorldInfo.RealTimeSeconds; + XPPopups[NextXPPopupIndex].RandX = 2.f * FRand(); + XPPopups[NextXPPopupIndex].RandY = 1.f + FRand(); + XPPopups[NextXPPopupIndex].Icon = Icon; + XPPopups[NextXPPopupIndex].IconColor = IconColor; + XPPopups[NextXPPopupIndex].bInit = true; + + if( ++NextXPPopupIndex >= XPEARNED_COUNT) + NextXPPopupIndex=0; +} + +function NotifyDoshEarned( int Dosh ) +{ + DoshPopups[NextDoshPopupIndex].Dosh = Dosh; + DoshPopups[NextDoshPopupIndex].StartTime = WorldInfo.RealTimeSeconds; + DoshPopups[NextDoshPopupIndex].RandX = 2.f * FRand(); + DoshPopups[NextDoshPopupIndex].RandY = 1.f + FRand(); + DoshPopups[NextDoshPopupIndex].bInit = true; + + if( ++NextDoshPopupIndex >= DOSHEARNED_COUNT) + NextDoshPopupIndex=0; +} + +function DrawWeaponPickupInfo() +{ + local vector ScreenPos; + local bool bHasSingleForDual, bCanCarry; + local Inventory Inv; + local KFInventoryManager KFIM; + local string WeightText, S; + local class KFWC; + local int Weight; + local color CanCarryColor; + local FontRenderInfo FRI; + local float FontScale, ResModifier, IconSize; + local float TextWidth, TextHeight, TextYOffset, SecondaryBGWidth, SecondaryBGHeight; + local float InfoBaseX, InfoBaseY; + local float BGX, BGY, BGWidth, BGHeight; + + ScreenPos = Canvas.Project(WeaponPickup.Location + vect(0,0,25)); + if (ScreenPos.X < 0 || ScreenPos.X > Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY) + return; + + KFWC = class(WeaponPickup.InventoryClass); + if (KFWC.default.DualClass != None && PlayerOwner.Pawn != None && PlayerOwner.Pawn.InvManager != None) + { + Inv = PlayerOwner.Pawn.InvManager.FindInventoryType(KFWC); + if (KFWeapon(Inv) != None) + bHasSingleForDual = true; + } + + if (bHasSingleForDual) + { + Weight = KFWC.default.DualClass.default.InventorySize - KFWeapon(Inv).GetModifiedWeightValue(); + } + else Weight = KFWC.default.InventorySize; + + WeightText = string(Weight); + if (PlayerOwner.Pawn != None && KFInventoryManager(PlayerOwner.Pawn.InvManager) != None) + { + KFIM = KFInventoryManager(PlayerOwner.Pawn.InvManager); + if (KFIM.CanCarryWeapon(KFWC)) + { + if (KFWC.default.DualClass != None) + bCanCarry = !KFIM.ClassIsInInventory(KFWC.default.DualClass, Inv); + else bCanCarry = !KFIM.ClassIsInInventory(KFWC, Inv); + } + } + else bCanCarry = true; + + CanCarryColor = (bCanCarry ? WeaponIconColor : WeaponOverweightIconColor); + + FRI = Canvas.CreateFontRenderInfo(true); + + ResModifier = WorldInfo.static.GetResolutionBasedHUDScale(); + Canvas.Font = GUIStyle.PickFont(FontScale); + Canvas.TextSize(WeightText, TextWidth, TextHeight, FontScale, FontScale); + + IconSize = WeaponIconSize * ResModifier; + InfoBaseX = ScreenPos.X - ((IconSize * 1.5 + TextWidth) * 0.5); + InfoBaseY = ScreenPos.Y; + TextYOffset = (IconSize - TextHeight) * 0.5; + + BGWidth = IconSize * 2.0 + TextWidth; + BGX = InfoBaseX - (IconSize * 0.25); + BGHeight = IconSize * 1.5; + BGY = InfoBaseY + IconSize * 1.5 - (BGHeight * 0.125); + + GUIStyle.DrawRoundedBox(ScaledBorderSize*2, BGX, BGY, BGWidth, BGHeight, HudMainColor); + + Canvas.DrawColor = CanCarryColor; + Canvas.SetPos(InfoBaseX, InfoBaseY + IconSize * 1.5); + Canvas.DrawTile(WeaponWeightIcon, IconSize, IconSize, 0, 0, 256, 256); + + Canvas.DrawColor = WhiteColor; + Canvas.SetPos(InfoBaseX + IconSize * 1.5, InfoBaseY + IconSize * 1.5 + TextYOffset); + Canvas.DrawText(WeightText, , FontScale, FontScale, FRI); + + if( WeaponPickup.GetDisplayName() != "" ) + { + S = WeaponPickup.GetDisplayName(); + Canvas.TextSize(S, TextWidth, TextHeight, FontScale, FontScale); + + SecondaryBGWidth = TextWidth * 1.125; + SecondaryBGHeight = TextHeight * 1.125; + + BGY += BGHeight + (TextHeight/2); + BGX += (BGWidth/2) - (SecondaryBGWidth/2); + + GUIStyle.DrawRoundedBox(ScaledBorderSize*2, BGX, BGY, SecondaryBGWidth, SecondaryBGHeight, HudMainColor); + + Canvas.DrawColor = WhiteColor; + Canvas.SetPos(BGX + (SecondaryBGWidth/2) - (TextWidth/2), BGY + (SecondaryBGHeight/2) - (TextHeight/2)); + Canvas.DrawText(S, , FontScale, FontScale, FRI); + } +} + +function byte DrawToDistance(Actor A, optional float StartAlpha=255.f, optional float MinAlpha=90.f) +{ + local float Dist, fZoom; + + Dist = VSize(A.Location - PLCameraLoc); + if ( Dist <= HealthBarFullVisDist || PlayerOwner.PlayerReplicationInfo.bOnlySpectator ) + fZoom = 1.0; + else fZoom = FMax(1.0 - (Dist - HealthBarFullVisDist) / (HealthBarCutoffDist - HealthBarFullVisDist), 0.0); + + return Clamp(StartAlpha * fZoom, MinAlpha, StartAlpha); +} + +simulated function bool DrawFriendlyHumanPlayerInfo( KFPawn_Human KFPH ) +{ + local float Percentage; + local float BarHeight, BarLength; + local vector ScreenPos, TargetLocation; + local KFPlayerReplicationInfo KFPRI; + local float FontScale; + local float ResModifier; + local float PerkIconPosX, PerkIconPosY, SupplyIconPosX, SupplyIconPosY, PerkIconXL, BarY; + local color CurrentArmorColor, CurrentHealthColor; + local byte FadeAlpha, PerkLevel; + + ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale; + KFPRI = KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo); + + if( KFPRI == None ) + return false; + + BarLength = FMin(PlayerStatusBarLengthMax * (Canvas.ClipX / 1024.f), PlayerStatusBarLengthMax) * ResModifier; + BarHeight = FMin(8.f * (Canvas.ClipX / 1024.f), 8.f) * ResModifier; + + TargetLocation = KFPH.Mesh.GetPosition() + ( KFPH.CylinderComponent.CollisionHeight * vect(0,0,2.5f) ); + ScreenPos = Canvas.Project( TargetLocation ); + if( ScreenPos.X < 0 || ScreenPos.X > Canvas.ClipX || ScreenPos.Y < 0 || ScreenPos.Y > Canvas.ClipY ) + return false; + + FadeAlpha = DrawToDistance(KFPH); + + //Draw player name (Top) + Canvas.Font = GUIStyle.PickFont(FontScale); + FontScale *= FriendlyHudScale; + + //Player name text + Canvas.DrawColor = WhiteColor; + Canvas.DrawColor.A = FadeAlpha; + GUIStyle.DrawTextShadow(KFPRI.PlayerName, ScreenPos.X - (BarLength * 0.5f), ScreenPos.Y - 3.5f, 1, FontScale); + + //Info Color + CurrentArmorColor = ClassicPlayerInfo ? ClassicArmorColor : ArmorColor; + CurrentHealthColor = ClassicPlayerInfo ? ClassicHealthColor : HealthColor; + CurrentArmorColor.A = FadeAlpha; + CurrentHealthColor.A = FadeAlpha; + + BarY = ScreenPos.Y + BarHeight + (36 * FontScale * ResModifier); + + //Draw armor bar + Percentage = FMin(float(KFPH.Armor) / float(KFPH.MaxArmor), 100); + DrawPlayerInfo(KFPH, Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength * 0.5f), BarY, CurrentArmorColor, true); + + BarY += BarHeight + 5; + + //Draw health bar + Percentage = FMin(float(KFPH.Health) / float(KFPH.HealthMax), 100); + DrawPlayerInfo(KFPH, Percentage, BarLength, BarHeight, ScreenPos.X - (BarLength * 0.5f), BarY, CurrentHealthColor, true, true); + + BarY += BarHeight; + + if( KFPRI.CurrentPerkClass == none ) + return false; + + PerkLevel = KFPRI.GetActivePerkLevel(); + + //Draw perk level and name text + Canvas.DrawColor = WhiteColor; + Canvas.DrawColor.A = FadeAlpha; + GUIStyle.DrawTextShadow(PerkLevel@KFPRI.CurrentPerkClass.default.PerkName, ScreenPos.X - (BarLength * 0.5f), BarY, 1, FontScale); + + // drop shadow for perk icon + Canvas.DrawColor = PlayerBarShadowColor; + Canvas.DrawColor.A = FadeAlpha; + PerkIconXL = PlayerStatusIconSize * ResModifier; + PerkIconPosX = ScreenPos.X - (BarLength * 0.5f) - PerkIconXL + 1; + PerkIconPosY = ScreenPos.Y + (PerkIconXL/2) - (BarHeight/2) + 6; + SupplyIconPosX = ScreenPos.X + (BarLength * 0.5f) + 1; + SupplyIconPosY = PerkIconPosY + 4 * ResModifier; + DrawPerkIcons(KFPH, PerkIconXL, PerkIconPosX - (ScaledBorderSize*2), PerkIconPosY, SupplyIconPosX + (ScaledBorderSize*2), SupplyIconPosY, true); + + //draw perk icon + Canvas.DrawColor = WhiteColor; + Canvas.DrawColor.A = FadeAlpha; + PerkIconPosX = ScreenPos.X - (BarLength * 0.5f) - PerkIconXL; + PerkIconPosY = ScreenPos.Y + (PerkIconXL/2) - (BarHeight/2) + 5; + SupplyIconPosX = ScreenPos.X + (BarLength * 0.5f); + SupplyIconPosY = PerkIconPosY + 4 * ResModifier; + DrawPerkIcons(KFPH, PerkIconXL, PerkIconPosX - (ScaledBorderSize*2), PerkIconPosY, SupplyIconPosX + (ScaledBorderSize*2), SupplyIconPosY, false); + + return true; +} + +simulated function DrawPerkIcons(KFPawn_Human KFPH, float PerkIconXL, float PerkIconPosX, float PerkIconPosY, float SupplyIconPosX, float SupplyIconPosY, bool bDropShadow) +{ + local byte PrestigeLevel; + local KFPlayerReplicationInfo KFPRI; + local color TempColor; + local float ResModifier; + local byte FadeAlpha; + + KFPRI = KFPlayerReplicationInfo(KFPH.PlayerReplicationInfo); + if( KFPRI == None ) + return; + + PrestigeLevel = KFPRI.GetActivePerkPrestigeLevel(); + ResModifier = WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale; + FadeAlpha = Canvas.DrawColor.A; + + if (KFPRI.CurrentVoiceCommsRequest == VCT_NONE && KFPRI.CurrentPerkClass != none && PrestigeLevel > 0) + { + Canvas.SetPos(PerkIconPosX, PerkIconPosY); + Canvas.DrawTile(KFPRI.CurrentPerkClass.default.PrestigeIcons[PrestigeLevel - 1], PerkIconXL, PerkIconXL, 0, 0, 256, 256); + } + + if (PrestigeLevel > 0) + { + Canvas.SetPos(PerkIconPosX + (PerkIconXL * (1 - class'KFHUDBase'.default.PrestigeIconScale)) / 2, PerkIconPosY + PerkIconXL * 0.05f); + Canvas.DrawTile(KFPRI.GetCurrentIconToDisplay(), PerkIconXL * class'KFHUDBase'.default.PrestigeIconScale, PerkIconXL * class'KFHUDBase'.default.PrestigeIconScale, 0, 0, 256, 256); + } + else + { + Canvas.SetPos(PerkIconPosX, PerkIconPosY); + Canvas.DrawTile(KFPRI.GetCurrentIconToDisplay(), PerkIconXL, PerkIconXL, 0, 0, 256, 256); + } + + if (KFPRI.PerkSupplyLevel > 0 && KFPRI.CurrentPerkClass.static.GetInteractIcon() != none) + { + if (!bDropShadow) + { + if (KFPRI.PerkSupplyLevel == 2) + { + if (KFPRI.bPerkPrimarySupplyUsed && KFPRI.bPerkSecondarySupplyUsed) + { + TempColor = SupplierActiveColor; + } + else if (KFPRI.bPerkPrimarySupplyUsed || KFPRI.bPerkSecondarySupplyUsed) + { + TempColor = SupplierHalfUsableColor; + } + else + { + TempColor = SupplierUsableColor; + } + } + else if (KFPRI.PerkSupplyLevel == 1) + { + TempColor = KFPRI.bPerkPrimarySupplyUsed ? SupplierActiveColor : SupplierUsableColor; + } + + Canvas.DrawColor = TempColor; + Canvas.DrawColor.A = FadeAlpha; + } + + Canvas.SetPos(SupplyIconPosX, SupplyIconPosY); + Canvas.DrawTile(KFPRI.CurrentPerkClass.static.GetInteractIcon(), (PlayerStatusIconSize * 0.75) * ResModifier, (PlayerStatusIconSize * 0.75) * ResModifier, 0, 0, 256, 256); + } +} + +simulated function DrawPlayerInfo( KFPawn_Human P, float BarPercentage, float BarLength, float BarHeight, float XPos, float YPos, Color BarColor, optional bool bDrawOutline, optional bool bDrawingHealth ) +{ + if( bDrawOutline ) + { + Canvas.SetDrawColor(185, 185, 185, 255); + GUIStyle.DrawBoxHollow(XPos - 2, YPos - 2, BarLength + 4, BarHeight + 4, 1); + + Canvas.SetPos(XPos, YPos); + Canvas.DrawColor = PlayerBarBGColor; + Canvas.DrawTileStretched(PlayerStatusBarBGTexture, BarLength, BarHeight, 0, 0, 32, 32); + + Canvas.SetPos(XPos, YPos); + Canvas.DrawColor = BarColor; + Canvas.DrawTileStretched(PlayerStatusBarBGTexture, BarLength * BarPercentage, BarHeight, 0, 0, 32, 32); + } + else DrawKFBar(BarPercentage, BarLength, BarHeight, XPos, YPos, BarColor); +} + +function ShowQuickSyringe() +{ + if ( bDisplayQuickSyringe ) + { + if ( `TimeSince(QuickSyringeStartTime) > QuickSyringeFadeInTime ) + { + if ( `TimeSince(QuickSyringeStartTime) > QuickSyringeDisplayTime - QuickSyringeFadeOutTime ) + QuickSyringeStartTime = `TimeSince(QuickSyringeFadeInTime + ((QuickSyringeDisplayTime - `TimeSince(QuickSyringeStartTime)) * QuickSyringeFadeInTime)); + else QuickSyringeStartTime = `TimeSince(QuickSyringeFadeInTime); + } + } + else + { + bDisplayQuickSyringe = true; + QuickSyringeStartTime = WorldInfo.TimeSeconds; + } +} + +simulated function Tick( float Delta ) +{ + if( bDisplayingProgress ) + { + bDisplayingProgress = false; + if( VisualProgressBarLevelProgressBar ) + VisualProgressBar = FMax(VisualProgressBar-Delta,LevelProgressBar); + } + + Super.Tick(Delta); +} + +function DrawZedIcon( Pawn ZedPawn, vector PawnLocation, float NormalizedAngle ) +{ + DrawDirectionalIndicator(PawnLocation + (ZedPawn.CylinderComponent.CollisionHeight * vect(0, 0, 1)), GenericZedIconTexture, PlayerStatusIconSize * (WorldInfo.static.GetResolutionBasedHUDScale() * FriendlyHudScale) * 0.5f,,, GetNameOf(ZedPawn.Class)); +} + +defaultproperties +{ + DefaultHudMainColor=(R=0,B=0,G=0,A=195) + DefaultHudOutlineColor=(R=200,B=15,G=15,A=195) + DefaultFontColor=(R=255,B=50,G=50,A=255) + + BlueColor=(R=0,B=255,G=0,A=255) + + MedicLockOnIcon=Texture2D'UI_SecondaryAmmo_TEX.UI_FireModeSelect_ManualTarget' + MedicLockOnIconSize=40 + MedicLockOnColor=(R=0,G=255,B=255,A=192) + MedicPendingLockOnColor=(R=92,G=92,B=92,A=192) + + MedicWeaponRot=(Yaw=16384) + MedicWeaponHeight=88 + MedicWeaponBGColor=(R=0,G=0,B=0,A=128) + MedicWeaponNotChargedColor=(R=224,G=0,B=0,A=128) + MedicWeaponChargedColor=(R=0,G=224,B=224,A=128) + + InventoryFadeTime=1.25 + InventoryFadeInTime=0.1 + InventoryFadeOutTime=0.15 + + InventoryX=0.35 + InventoryY=0.025 + InventoryBoxWidth=0.1 + InventoryBoxHeight=0.075 + BorderSize=0.005 + + TraderArrow=Texture2D'UI_LevelChevrons_TEX.UI_LevelChevron_Icon_03' + TraderArrowLight=Texture2D'UI_Objective_Tex.UI_Obj_World_Loc' + VoiceChatIcon=Texture2D'UI_HUD.voip_icon' + DoshEarnedIcon=Texture2D'UI_Objective_Tex.UI_Obj_Dosh_Loc' + + PerkIconSize=16 + MaxPerkStars=5 + MaxStarsPerRow=5 + + PrestigeIconScale=0.6625 + + DamagePopupFadeOutTime=2.25 + XPFadeOutTime=1.0 + DoshFadeOutTime=2.0 + + MaxWeaponPickupDist=700 + WeaponPickupScanRadius=75 + ZedScanRadius=200 + WeaponAmmoIcon=Texture2D'UI_Menus.TraderMenu_SWF_I10B' + WeaponWeightIcon=Texture2D'UI_Menus.TraderMenu_SWF_I26' + WeaponIconSize=32 + WeaponIconColor=(R=192,G=192,B=192,A=255) + WeaponOverweightIconColor=(R=255,G=0,B=0,A=192) + + NonCriticalMessageDisplayTime=3.0 + NonCriticalMessageFadeInTime=0.65 + NonCriticalMessageFadeOutTime=0.5 + + HealthBarFullVisDist=350.0; + HealthBarCutoffDist=3500.0; + + RepObject=ObjectReferencer'KFClassicMode_Assets.ObjectRef.MainObj_List' + HUDClass=class'KF1_HUDWrapper' + PerkStarIcon=Texture2D'KFClassicMode_Assets.HUD.Hud_Perk_Star' + ScoreboardClass=class'KFScoreBoard' + + BossBattlePhaseColor=(R=0,B=0,G=150,A=175) + + BattlePhaseColors.Add((R=0,B=0,G=150,A=175)) + BattlePhaseColors.Add((R=255,B=18,G=176,A=175)) + BattlePhaseColors.Add((R=255,B=18,G=96,A=175)) + BattlePhaseColors.Add((R=173,B=17,G=22,A=175)) + BattlePhaseColors.Add((R=0,B=0,G=0,A=175)) + + DamageMsgColors[DMG_Fire]=(R=206,G=103,B=0,A=255) + DamageMsgColors[DMG_Toxic]=(R=58,G=232,B=0,A=255) + DamageMsgColors[DMG_Bleeding]=(R=255,G=100,B=100,A=255) + DamageMsgColors[DMG_EMP]=(R=32,G=138,B=255,A=255) + DamageMsgColors[DMG_Freeze]=(R=0,G=183,B=236,A=255) + DamageMsgColors[DMG_Flashbang]=(R=195,G=195,B=195,A=255) + DamageMsgColors[DMG_Generic]=(R=206,G=64,B=64,A=255) + DamageMsgColors[DMG_High]=(R=0,G=206,B=0,A=255) + DamageMsgColors[DMG_Medium]=(R=206,G=206,B=0,A=255) + DamageMsgColors[DMG_Unspecified]=(R=150,G=150,B=150,A=255) + + NewLineSeparator="|" + + NotificationBackground=Texture2D'KFClassicMode_Assets.HUD.Med_border_SlightTransparent' + NotificationShowTime=0.3 + NotificationHideTime=0.5 + NotificationHideDelay=3.5 + NotificationBorderSize=7.0 + NotificationIconSpacing=10.0 + NotificationPhase=PHASE_DONE +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/ClassicStyle.uc b/Src/KFClassicHUD/Classes/ClassicStyle.uc new file mode 100644 index 0000000..81f6fe3 --- /dev/null +++ b/Src/KFClassicHUD/Classes/ClassicStyle.uc @@ -0,0 +1,408 @@ +Class ClassicStyle extends KF2Style; + +function RenderFramedWindow( KFGUI_FloatingWindow P ) +{ + local int XS,YS,TitleHeight; + local float XL, YL, FontScale; + + XS = Canvas.ClipX-Canvas.OrgX; + YS = Canvas.ClipY-Canvas.OrgY; + TitleHeight = DefaultHeight; + + if( P.bWindowFocused ) + Canvas.SetDrawColor(105,105,105,255); + else Canvas.SetDrawColor(85,85,85,P.FrameOpacity); + + // Frame Header + Canvas.SetPos(0, 0); + Canvas.DrawTileStretched(TabTextures[`TAB_TOP],XS,TitleHeight,0,0,128,16); + + // Frame itself. + Canvas.SetPos(0, TitleHeight); + Canvas.DrawTileStretched(BorderTextures[`BOX_SMALL_SLIGHTTRANSPARENT],XS,YS-TitleHeight,0,0,128,128); + + // Title. + if( P.WindowTitle!="" ) + { + Canvas.Font = PickFont(FontScale); + Canvas.TextSize(P.WindowTitle,XL,YL,FontScale,FontScale); + Canvas.SetDrawColor(250,250,250,255); + Canvas.SetPos((XS*0.5)-(XL*0.5),0); + Canvas.DrawText(P.WindowTitle,,FontScale,FontScale); + } +} + +function RenderWindow( KFGUI_Page P ) +{ + local int XS,YS; + + XS = Canvas.ClipX-Canvas.OrgX; + YS = Canvas.ClipY-Canvas.OrgY; + + // Frame itself. + if( P.bWindowFocused ) + Canvas.SetDrawColor(105,105,105,255); + else Canvas.SetDrawColor(85,85,85,P.FrameOpacity); + + Canvas.SetPos(0, 0); + Canvas.DrawTileStretched(BorderTextures[`BOX_SMALL_SLIGHTTRANSPARENT],XS,YS,0,0,128,128); +} + +function RenderToolTip( KFGUI_Tooltip TT ) +{ + local int i; + local float X,Y,XS,YS,TX,TY,TS,DefFontHeight; + + Canvas.Font = PickFont(TS); + + // First compute textbox size. + TY = DefaultHeight*TT.Lines.Length; + for( i=0; iTT.Owner.ScreenSize.X ) + X = TT.Owner.ScreenSize.X-TX; + if( (Y+TY)>TT.Owner.ScreenSize.Y ) + Y = TT.CompPos[1]-TY; + + if( TT.CurrentAlpha<255 ) + TT.CurrentAlpha = Min(TT.CurrentAlpha+25,255); + + // Reset clipping. + Canvas.SetOrigin(0,0); + Canvas.SetClip(TT.Owner.ScreenSize.X,TT.Owner.ScreenSize.Y); + + // Draw frame. + Canvas.SetDrawColor(115,115,115,TT.CurrentAlpha); + Canvas.SetPos(X-2,Y-2); + DrawBoxHollow(X-2,Y-2,TX+4,TY+4,2); + Canvas.SetDrawColor(5,5,5,TT.CurrentAlpha); + Canvas.SetPos(X,Y); + DrawWhiteBox(TX,TY); + + DefFontHeight = DefaultHeight; + + // Draw text. + Canvas.SetDrawColor(255,255,255,TT.CurrentAlpha); + X+=TOOLTIP_BORDER; + Y+=TOOLTIP_BORDER; + for( i=0; i0.f && X0.f && Y=YP && Y<=(YP+YL) ) + { + bCheckMouse = false; + C.CurrentRow = i; + Canvas.SetPos(4.f,YP); + Canvas.SetDrawColor(128,48,48,255); + DrawWhiteBox(C.CompPos[2]-(Edge*2.f),YL); + } + Canvas.SetPos(Edge,YP); + + if( i==C.Combo.SelectedIndex ) + Canvas.DrawColor = C.Combo.SelectedTextColor; + else Canvas.DrawColor = C.Combo.TextColor; + + Canvas.DrawText(C.Combo.Values[i],,C.Combo.TextScale,C.Combo.TextScale,C.Combo.TextFontInfo); + + YP+=YL; + } + Canvas.PopMaskRegion(); + if( C.OldRow!=C.CurrentRow ) + { + C.OldRow = C.CurrentRow; + C.PlayMenuSound(MN_DropdownChange); + } +} + +function RenderRightClickMenu( KFGUI_RightClickMenu C ) +{ + local float X,Y,XL,YL,YP,Edge,TextScale; + local int i; + local bool bCheckMouse; + local string S; + + // Draw background. + Edge = C.EdgeSize; + DrawOutlinedBox(0.f,0.f,C.CompPos[2],C.CompPos[3],Edge,C.BoxColor,C.OutlineColor); + + // While rendering, figure out mouse focus row. + X = C.Owner.MousePosition.X - Canvas.OrgX; + Y = C.Owner.MousePosition.Y - Canvas.OrgY; + + bCheckMouse = (X>0.f && X0.f && Y=YP && Y<=(YP+YL) ) + { + bCheckMouse = false; + C.CurrentRow = i; + Canvas.SetPos(Edge,YP); + Canvas.SetDrawColor(128,0,0,255); + DrawWhiteBox(C.CompPos[2]-(Edge*2.f),YL); + } + + Canvas.SetPos(Edge*6,YP); + if( C.ItemRows[i].bSplitter ) + Canvas.SetDrawColor(255,255,255,255); + else + { + if( C.ItemRows[i].bDisabled ) + Canvas.SetDrawColor(148,148,148,255); + else Canvas.SetDrawColor(248,248,248,255); + } + Canvas.DrawText(S,,TextScale,TextScale); + + YP+=YL; + } + Canvas.PopMaskRegion(); + if( C.OldRow!=C.CurrentRow ) + { + C.OldRow = C.CurrentRow; + C.PlayMenuSound(MN_FocusHover); + } +} + +function RenderButton( KFGUI_Button B ) +{ + local float XL,YL,TS,AX,AY,GamepadTexSize; + local Texture2D Mat, ButtonTex; + local bool bDrawOverride; + + bDrawOverride = B.DrawOverride(Canvas, B); + if( !bDrawOverride ) + { + if( B.bDisabled ) + Mat = ButtonTextures[`BUTTON_DISABLED]; + else if( B.bPressedDown ) + Mat = ButtonTextures[`BUTTON_PRESSED]; + else if( B.bFocused || B.bIsHighlighted ) + Mat = ButtonTextures[`BUTTON_HIGHLIGHTED]; + else Mat = ButtonTextures[`BUTTON_NORMAL]; + + Canvas.SetPos(0.f,0.f); + Canvas.DrawTileStretched(Mat,B.CompPos[2],B.CompPos[3],0,0,32,32); + + if( B.OverlayTexture.Texture!=None ) + { + Canvas.SetPos(0.f,0.f); + Canvas.DrawTile(B.OverlayTexture.Texture,B.CompPos[2],B.CompPos[3],B.OverlayTexture.U,B.OverlayTexture.V,B.OverlayTexture.UL,B.OverlayTexture.VL); + } + } + + if( B.ButtonText!="" ) + { + Canvas.Font = MainFont; + + GamepadTexSize = B.CompPos[3] / 1.25; + + TS = GetFontScaler(); + TS *= B.FontScale; + + while( true ) + { + Canvas.TextSize(B.ButtonText,XL,YL,TS,TS); + if( XL<(B.CompPos[2]*0.9) && YL<(B.CompPos[3]*0.9) ) + break; + + TS -= 0.001; + } + + Canvas.SetPos((B.CompPos[2]-XL)*0.5,(B.CompPos[3]-YL)*0.5); + if( B.bDisabled ) + Canvas.DrawColor = B.TextColor*0.5f; + else Canvas.DrawColor = B.TextColor; + Canvas.DrawText(B.ButtonText,,TS,TS,B.TextFontInfo); + + if( B.GetUsingGamepad() ) + { + ButtonTex = Texture2D(DynamicLoadObject("UI_Controller."$B.GamepadButtonName$"_Asset", class'Texture2D')); + if( ButtonTex != None ) + { + B.GetRealtivePos(AX, AY); + while( (Canvas.CurX-(GamepadTexSize*1.25)) Type ) +{ + ClassicKFHUD(KFPC.MyHUD).AddNumberMsg(Count,Pos,Type); +} + +defaultproperties +{ + bOnlyRelevantToOwner=True +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/GUIStyleBase.uc b/Src/KFClassicHUD/Classes/GUIStyleBase.uc new file mode 100644 index 0000000..ab3170b --- /dev/null +++ b/Src/KFClassicHUD/Classes/GUIStyleBase.uc @@ -0,0 +1,865 @@ +Class GUIStyleBase extends Object + abstract; + +var Texture2D ItemTex; +var array BorderTextures, ArrowTextures, ButtonTextures, TabTextures, ItemBoxTextures, PerkBox, CheckBoxTextures, ProgressBarTextures, SliderTextures; +var Texture2D ScrollTexture,FavoriteIcon,BankNoteIcon; + +var SoundCue MenuDown, MenuDrag, MenuEdit, MenuFade, MenuClick, MenuHover, MenuUp; + +var() byte MaxFontScale; +var float DefaultHeight; // Default font text size. +var transient Canvas Canvas; +var transient KF2GUIController Owner; +var transient ClassicKFHUD HUDOwner; + +var Font MainFont, NumberFont, InfiniteFont; +var Color BlurColor, BlurColor2; + +struct FColorInfo +{ + var name Code; + var Color Color; +}; +var array ColorCodes; + +struct FTexturePreCache +{ + var string Path; + var Texture2D Tex; +}; +var array PrecachedTextures; + +function InitStyle() +{ + local FColorInfo ColorInfo; + + ItemTex=Texture2D(DynamicLoadObject("UI_LevelChevrons_TEX.UI_LevelChevron_Icon_02",class'Texture2D')); + if( ItemTex==None ) + ItemTex=Texture2D'EngineMaterials.DefaultWhiteGrid'; + + NumberFont = Font(DynamicLoadObject("UI_Canvas_Fonts.Font_General", class'Font')); + + BlurColor = MakeColor(60, 60, 60, 220); + BlurColor2 = MakeColor(40, 40, 40, 140); + + ColorInfo.Code='Q'; + ColorInfo.Color = MakeColor(0,140,0,255); // Dark Green + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='E'; + ColorInfo.Color = MakeColor(210,180,140,255); // Tan + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='R'; + ColorInfo.Color = MakeColor(128,0,0,255); // Dark Red + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='T'; + ColorInfo.Color = MakeColor(153,102,204,255); // Purple + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='U'; + ColorInfo.Color = MakeColor(128,128,128,255); // Dark Gray + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='I'; + ColorInfo.Color = MakeColor(255,170,0,255); // Orange + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='O'; + ColorInfo.Color = MakeColor(255,204,153,255); // Cream + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='P'; + ColorInfo.Color = MakeColor(209,216,168,255); // Olive + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='A'; + ColorInfo.Color = MakeColor(204,51,51,255); // Brick + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='S'; + ColorInfo.Color = MakeColor(153,102,51,255); // Brown + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='D'; + ColorInfo.Color = MakeColor(0,204,0,255); // Green + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='F'; + ColorInfo.Color = MakeColor(238,238,51,255); // Yellow + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='G'; + ColorInfo.Color = MakeColor(200,0,0,255); // Red + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='H'; + ColorInfo.Color = MakeColor(153,153,255,255); // Blue + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='J'; + ColorInfo.Color = MakeColor(192,192,192,255); // Silver + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='K'; + ColorInfo.Color = MakeColor(255,204,0,255); // Gold + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='C'; + ColorInfo.Color = MakeColor(255,255,255,255); // White + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='V'; + ColorInfo.Color = MakeColor(0,191,255,255); // Sky Blue + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='B'; + ColorInfo.Color = MakeColor(204,204,204,255); // Gray + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='N'; + ColorInfo.Color = MakeColor(0,128,255,255); // Dark Sky Blue + ColorCodes.AddItem(ColorInfo); + + ColorInfo.Code='M'; + ColorInfo.Color = MakeColor(18,18,18,255); // Black + ColorCodes.AddItem(ColorInfo); +} + +function RenderFramedWindow( KFGUI_FloatingWindow P ); +function RenderWindow( KFGUI_Page P ); +function RenderToolTip( KFGUI_Tooltip TT ); +function RenderButton( KFGUI_Button B ); +function RenderScrollBar( KFGUI_ScrollBarBase S ); +function RenderColumnHeader( KFGUI_ColumnTop C, float XPos, float Width, int Index, bool bFocus, bool bSort ); +function RenderRightClickMenu( KFGUI_RightClickMenu C ); +function RenderCheckbox( KFGUI_CheckBox C ); +function RenderComboBox( KFGUI_ComboBox C ); +function RenderComboList( KFGUI_ComboSelector C ); + +function Font PickFont( out float Scaler, optional bool bNumbersOnly, optional bool bInfinite ) +{ + Scaler = GetFontScaler(); + + if( bNumbersOnly ) + return NumberFont; + else if( bInfinite ) + return InfiniteFont; + + return MainFont; +} + +function PickDefaultFontSize( float YRes ) +{ + local int XL,YL; + local string S; + + S="ABC"; + PickFont(YRes).GetStringHeightAndWidth(S,YL,XL); + + DefaultHeight=float(YL)*YRes; +} +final function float ScreenScale( float Size, optional float MaxRes=1920.f ) +{ + return Size * ( HUDOwner.SizeX / MaxRes ); +} +final function float GetFontScaler(optional float Scaler=0.375f, optional float Min=0.175f, optional float Max=0.375f) +{ + return FClamp((HUDOwner.SizeX / 1920.f) * Scaler, Min, Max); +} +final function DrawText( coerce string S ) +{ + local float Scale; + + Canvas.Font=PickFont(Scale); + Canvas.DrawText(S,,Scale,Scale); +} +final function DrawCenteredText( coerce string S, float X, float Y, optional float Scale=1.f, optional bool bVertical, optional bool bUseOutline ) +{ + local float XL,YL; + + Canvas.TextSize(S,XL,YL); + if( bVertical ) + Canvas.SetPos(X,Y-(YL*Scale*0.5)); + else Canvas.SetPos(X-(XL*Scale*0.5),Y); + + if( bUseOutline ) + DrawTextShadow(S, Canvas.CurX, Canvas.CurY, 1, Scale); + else Canvas.DrawText(S,,Scale,Scale); +} +final function string StripColorTags( coerce string S ) +{ + local int Pos; + + Pos = InStr(S, "\\c"); + while( Pos != INDEX_NONE ) + { + S = Left(S,Pos) $ Mid(S,Pos+3); + Pos = InStr(S, "\\c"); + } + + return S; +} +final function DrawColoredText( coerce string S, float X, float Y, optional float Scale=1.f, optional bool bUseOutline ) +{ + local float XL,YL; + local int i, Index; + local array SArray; + local string T, PrevT; + local Color TextColor; + + if( InStr(S, "\\c") == INDEX_NONE ) + { + if( bUseOutline ) + DrawTextShadow(S, X, Y, 1, Scale); + else + { + Canvas.SetPos(X,Y); + Canvas.DrawText(S,,Scale,Scale); + } + } + else + { + SArray = SplitString(S, "\\c"); + + PrevT = Left(S,InStr(S, "\\c")); + if( Len(PrevT) > 0 ) + { + Canvas.TextSize(PrevT,XL,YL,Scale,Scale); + + if( bUseOutline ) + DrawTextShadow(PrevT, X, Y, 1, Scale); + else + { + Canvas.SetPos(X,Y); + Canvas.DrawText(PrevT,,Scale,Scale); + } + } + + for( i=0; i0 || Left(S, 2)~="\\c" ) + { + Index = ColorCodes.Find('Code', name(Left(T, 1))); + if( Index != INDEX_NONE ) + TextColor = ColorCodes[Index].Color; + else TextColor = class'HUD'.default.WhiteColor; + + TextColor.A = Canvas.DrawColor.A; + + T = Mid(T, 1); + } + + Canvas.DrawColor = TextColor; + Canvas.TextSize(T,XL,YL,Scale,Scale); + + if( bUseOutline ) + DrawTextShadow(T, X, Y, 1, Scale); + else + { + Canvas.SetPos(X,Y); + Canvas.DrawText(T,,Scale,Scale); + } + + X += XL; + } + } +} +final function DrawTextBlurry( coerce string S, float X, float Y, optional float Scale=1.f ) +{ + local Color OldDrawColor; + + OldDrawColor = Canvas.DrawColor; + BlurColor.A = OldDrawColor.A * 0.85; + BlurColor2.A = OldDrawColor.A * 0.55; + + Canvas.DrawColor = BlurColor; + Canvas.SetPos(X + Owner.FontBlurX, Y + Owner.FontBlurY); + Canvas.DrawText(S,,Scale,Scale); + + Canvas.DrawColor = BlurColor2; + Canvas.SetPos(X + Owner.FontBlurX2, Y + Owner.FontBlurY2); + Canvas.DrawText(S,,Scale,Scale); + + Canvas.DrawColor = OldDrawColor; + Canvas.SetPos(X, Y); + Canvas.DrawText(S,,Scale,Scale); +} +final function DrawTextOutline( coerce string S, float X, float Y, int Size, Color OutlineColor, optional float Scale=1.f, optional FontRenderInfo FRI ) +{ + local Color OldDrawColor; + local int XS, YS, Steps; + + OldDrawColor = Canvas.DrawColor; + OutlineColor.A = OldDrawColor.A; + + Size += 1; + Steps = (Size * 2) / 3; + if( Steps < 1 ) + { + Steps = 1; + } + + Canvas.DrawColor = OutlineColor; + for (XS = -Size; XS <= Size; XS+=Steps) + { + for (YS = -Size; YS <= Size; YS+=Steps) + { + Canvas.SetPos(X + XS, Y + YS); + Canvas.DrawText(S,, Scale, Scale, FRI); + } + } + + Canvas.DrawColor = OldDrawColor; + Canvas.SetPos(X, Y); + Canvas.DrawText(S,, Scale, Scale, FRI); +} +final function DrawTextShadow( coerce string S, float X, float Y, float ShadowSize, optional float Scale=1.f ) +{ + local Color OldDrawColor; + + OldDrawColor = Canvas.DrawColor; + + Canvas.SetPos(X + ShadowSize, Y + ShadowSize); + Canvas.SetDrawColor(0, 0, 0, OldDrawColor.A); + Canvas.DrawText(S,, Scale, Scale); + + Canvas.SetPos(X, Y); + Canvas.DrawColor = OldDrawColor; + Canvas.DrawText(S,, Scale, Scale); +} +final function DrawTexturedString( coerce string S, float X, float Y, optional float TextScaler=1.f, optional FontRenderInfo FRI, optional bool bUseOutline, optional bool bOnlyTexture ) +{ + local Texture2D Mat; + local string D; + local float XL, YL; + local int i,j; + local Color OrgC; + + OrgC = Canvas.DrawColor; + + Mat = FindNextTexture(S); + while( Mat != None ) + { + i = InStr(S,""); + + D = Left(S,i); + S = Mid(S,j+2); + + if( !bOnlyTexture ) + { + Canvas.TextSize(StripColorTags(D),XL,YL,TextScaler,TextScaler); + DrawColoredText(D,X,Y,TextScaler,bUseOutline); + + X += XL; + } + else Canvas.TextSize("W",XL,YL,TextScaler,TextScaler); + + Canvas.DrawColor = class'HUD'.default.WhiteColor; + Canvas.DrawColor.A = OrgC.A; + + Canvas.SetPos(X,Y+(Owner.HUDOwner.ScaledBorderSize/2)); + Canvas.DrawRect(YL-Owner.HUDOwner.ScaledBorderSize,YL-Owner.HUDOwner.ScaledBorderSize,Mat); + + X += YL-Owner.HUDOwner.ScaledBorderSize; + + Canvas.DrawColor = OrgC; + Mat = FindNextTexture(S); + } + + DrawColoredText(S,X,Y,TextScaler,bUseOutline); +} +final function Texture2D FindNextTexture(out string S) +{ + local int i, j; + local string Path; + local Texture2D Tex; + local FTexturePreCache Cache; + + Path = S; + i = InStr(Path,""); + if( i == INDEX_NONE ) + return None; + + j = InStr(Path,""); + S = Left(Path,i)$""$Mid(Path, j+6); + Path = Mid(Path, i+6, j-(i+6)); + + i = PrecachedTextures.Find('Path', Path); + if( i != INDEX_NONE ) + return PrecachedTextures[i].Tex; + + Tex = Texture2D(FindObject(Path, class'Texture2D')); + if( Tex != None ) + { + Cache.Path = Path; + Cache.Tex = Tex; + PrecachedTextures.AddItem(Cache); + + return Tex; + } + + Cache.Path = Path; + Cache.Tex = Texture2D(DynamicLoadObject(Path, class'Texture2D')); + PrecachedTextures.AddItem(Cache); + + return Cache.Tex; +} +final function string StripTextureFromString(string S, optional bool bNoStringAdd) +{ + local int i, j; + + while( true ) + { + i = InStr(S,""); + if( i == INDEX_NONE ) + break; + + j = InStr(S,""); + S = Left(S,i)$(bNoStringAdd ? "" : "W")$Mid(S, j+Len("")); + } + + return StripColorTags(S); +} +final function string GetTimeString(int Seconds) +{ + local int Minutes, Hours; + local string Time; + + if( Seconds > 3600 ) + { + Hours = Seconds / 3600; + Seconds -= Hours * 3600; + + Time = Hours$":"; + } + Minutes = Seconds / 60; + Seconds -= Minutes * 60; + + if( Minutes >= 10 ) + Time = Time $ Minutes $ ":"; + else Time = Time $ "0" $ Minutes $ ":"; + + if( Seconds >= 10 ) + Time = Time $ Seconds; + else Time = Time $ "0" $ Seconds; + + return Time; +} + +final function DrawCornerTexNU( int SizeX, int SizeY, byte Dir ) // Draw non-uniform corner. +{ + switch( Dir ) + { + case 0: // Up-left + Canvas.DrawTile(ItemTex,SizeX,SizeY,77,15,-66,58); + break; + case 1: // Up-right + Canvas.DrawTile(ItemTex,SizeX,SizeY,11,15,66,58); + break; + case 2: // Down-left + Canvas.DrawTile(ItemTex,SizeX,SizeY,77,73,-66,-58); + break; + default: // Down-right + Canvas.DrawTile(ItemTex,SizeX,SizeY,11,73,66,-58); + } +} +final function DrawCornerTex( int Size, byte Dir ) +{ + switch( Dir ) + { + case 0: // Up-left + Canvas.DrawTile(ItemTex,Size,Size,77,15,-66,58); + break; + case 1: // Up-right + Canvas.DrawTile(ItemTex,Size,Size,11,15,66,58); + break; + case 2: // Down-left + Canvas.DrawTile(ItemTex,Size,Size,77,73,-66,-58); + break; + default: // Down-right + Canvas.DrawTile(ItemTex,Size,Size,11,73,66,-58); + } +} +final function DrawWhiteBox( float XS, float YS, optional bool bClip ) +{ + Canvas.DrawTile(ItemTex,XS,YS,19,45,1,1,,bClip); +} + +final function DrawRectBox( float X, float Y, float XS, float YS, int Edge, optional byte Extrav ) +{ + if( Extrav==2 ) + Edge=Min(FMin(Edge,(XS)*0.5),YS);// Verify size. + else Edge=Min(FMin(Edge,(XS)*0.5),(YS)*0.5);// Verify size. + + Canvas.PreOptimizeDrawTiles(Extrav==0 ? 7 : 6, ItemTex); + + // Top left + Canvas.SetPos(X,Y); + DrawCornerTex(Edge,0); + + if( Extrav<=1 ) + { + if( Extrav==0 ) + { + // Top right + Canvas.SetPos(X+XS-Edge,Y); + DrawCornerTex(Edge,1); + + // Bottom right + Canvas.SetPos(X+XS-Edge,Y+YS-Edge); + DrawCornerTex(Edge,3); + + // Fill + Canvas.SetPos(X+Edge,Y); + DrawWhiteBox(XS-Edge*2,YS); + Canvas.SetPos(X,Y+Edge); + DrawWhiteBox(Edge,YS-Edge*2); + Canvas.SetPos(X+XS-Edge,Y+Edge); + DrawWhiteBox(Edge,YS-Edge*2); + } + else if( Extrav==1 ) + { + // Top right + Canvas.SetPos(X+XS,Y); + DrawCornerTex(Edge,3); + + // Bottom right + Canvas.SetPos(X+XS,Y+YS-Edge); + DrawCornerTex(Edge,1); + + // Fill + Canvas.SetPos(X+Edge,Y); + DrawWhiteBox(XS-Edge,YS); + Canvas.SetPos(X,Y+Edge); + DrawWhiteBox(Edge,YS-Edge*2); + } + + // Bottom left + Canvas.SetPos(X,Y+YS-Edge); + DrawCornerTex(Edge,2); + } + else + { + // Top right + Canvas.SetPos(X+XS-Edge,Y); + DrawCornerTex(Edge,1); + + // Bottom right + Canvas.SetPos(X+XS-Edge,Y+YS); + DrawCornerTex(Edge,2); + + // Bottom left + Canvas.SetPos(X,Y+YS); + DrawCornerTex(Edge,3); + + // Fill + Canvas.SetPos(X,Y+Edge); + DrawWhiteBox(XS,YS-Edge); + Canvas.SetPos(X+Edge,Y); + DrawWhiteBox(XS-Edge*2,Edge); + } +} + +final function DrawBoxHollow( float X, float Y, float Width, float Height, float Thickness ) +{ + Canvas.PreOptimizeDrawTiles(4, ItemTex); + + Canvas.SetPos(X + Thickness, Y); + DrawWhiteBox(Width - Thickness * 2, Thickness); + + Canvas.SetPos(X + Thickness, Y+Height-Thickness); + DrawWhiteBox(Width - Thickness * 2, Thickness); + + Canvas.SetPos(X, Y); + DrawWhiteBox(Thickness, Height); + + Canvas.SetPos(X + Width - Thickness, Y); + DrawWhiteBox(Thickness, Height); +} + +final function DrawOutlinedBox( float X, float Y, float Width, float Height, float Thickness, Color BoxColor, Color OutlineColor ) +{ + Canvas.DrawColor = BoxColor; + Canvas.SetPos(X + Thickness, Y + Thickness); + DrawWhiteBox(Width - (Thickness*2), Height - (Thickness*2)); + + Canvas.DrawColor = OutlineColor; + DrawBoxHollow(X, Y, Width, Height, Thickness); +} + +final function DrawBoxCorners(float BorderSize, float X, float Y, float W, float H, optional bool TopLeft, optional bool TopRight, optional bool BottomLeft, optional bool BottomRight) +{ + // Top left + Canvas.SetPos(X,Y); + if( TopLeft ) + DrawCornerTex(BorderSize,0); + else DrawWhiteBox(BorderSize, BorderSize); + + // Top right + Canvas.SetPos(X+W-BorderSize,Y); + if( TopRight ) + DrawCornerTex(BorderSize,1); + else DrawWhiteBox(BorderSize, BorderSize); + + // Bottom left + Canvas.SetPos(X,Y+H-BorderSize); + if( BottomLeft ) + DrawCornerTex(BorderSize,2); + else DrawWhiteBox(BorderSize, BorderSize); + + // Bottom right + Canvas.SetPos(X+W-BorderSize,Y+H-BorderSize); + if( BottomRight ) + DrawCornerTex(BorderSize,3); + else DrawWhiteBox(BorderSize, BorderSize); +} + +final function DrawRoundedBox( float BorderSize, float X, float Y, float W, float H, Color BoxColor ) +{ + DrawRoundedBoxEx(BorderSize, X, Y, W, H, BoxColor, true, true, true, true); +} + +final function DrawRoundedBoxEx( float BorderSize, float X, float Y, float W, float H, Color BoxColor, optional bool TopLeft, optional bool TopRight, optional bool BottomLeft, optional bool BottomRight ) +{ + Canvas.DrawColor = BoxColor; + + if( BorderSize <= 0 ) + { + Canvas.SetPos(X, Y); + DrawWhiteBox(W, H); + return; + } + + Canvas.PreOptimizeDrawTiles(7, ItemTex); + + BorderSize = Min(FMin(BorderSize,(W)*0.5),(H)*0.5); + + Canvas.SetPos(X + BorderSize, Y); + DrawWhiteBox(W - BorderSize * 2, H); + + Canvas.SetPos(X, Y + BorderSize); + DrawWhiteBox(BorderSize, H - BorderSize * 2); + + Canvas.SetPos(X + W - BorderSize, Y + BorderSize); + DrawWhiteBox(BorderSize, H - BorderSize * 2); + + DrawBoxCorners(BorderSize, X, Y, W, H, TopLeft, TopRight, BottomLeft, BottomRight); +} + +final function DrawRoundedBoxHollow( float BorderSize, float X, float Y, float W, float H, Color BoxColor ) +{ + DrawRoundedBoxHollowEx(BorderSize, X, Y, W, H, BoxColor, true, true, true, true); +} + +final function DrawRoundedBoxHollowEx( float BorderSize, float X, float Y, float W, float H, Color BoxColor, optional bool TopLeft, optional bool TopRight, optional bool BottomLeft, optional bool BottomRight ) +{ + Canvas.PreOptimizeDrawTiles(8, ItemTex); + + BorderSize = Min(FMin(BorderSize,(W)*0.5),(H)*0.5); + + Canvas.DrawColor = BoxColor; + + Canvas.SetPos(X + BorderSize, Y); + DrawWhiteBox(W - BorderSize * 2, BorderSize); + + Canvas.SetPos(X + BorderSize, Y+H-BorderSize); + DrawWhiteBox(W - BorderSize * 2, BorderSize); + + Canvas.SetPos(X, Y + BorderSize); + DrawWhiteBox(BorderSize, H - BorderSize * 2); + + Canvas.SetPos(X + W - BorderSize, Y + BorderSize); + DrawWhiteBox(BorderSize, H - BorderSize * 2); + + DrawBoxCorners(BorderSize, X, Y, W, H, TopLeft, TopRight, BottomLeft, BottomRight); +} + +final function DrawRoundedBoxOutlined( float BorderSize, float X, float Y, float Width, float Height, Color BoxColor, Color OutlineColor ) +{ + Canvas.DrawColor = BoxColor; + Canvas.SetPos(X + BorderSize, Y + BorderSize); + DrawWhiteBox(Width - (BorderSize*2), Height - (BorderSize*2)); + + DrawRoundedBoxHollow(BorderSize, X, Y, Width, Height, OutlineColor); +} + +final function DrawRoundedBoxOutlinedEx( float BorderSize, float X, float Y, float Width, float Height, Color BoxColor, Color OutlineColor, optional bool TopLeft, optional bool TopRight, optional bool BottomLeft, optional bool BottomRight ) +{ + Canvas.DrawColor = BoxColor; + Canvas.SetPos(X + BorderSize, Y + BorderSize); + DrawWhiteBox(Width - (BorderSize*2), Height - (BorderSize*2)); + + DrawRoundedBoxHollowEx(BorderSize, X, Y, Width, Height, OutlineColor, TopLeft, TopRight, BottomLeft, BottomRight); +} + +final function DrawArrowBox( int Direction, float X, float Y, float Width, float Height ) +{ + local Texture2D DirectionMat; + + switch( Direction ) + { + case 0: + DirectionMat=ArrowTextures[`ARROW_UP]; + break; + case 1: + DirectionMat=ArrowTextures[`ARROW_RIGHT]; + break; + case 2: + DirectionMat=ArrowTextures[`ARROW_DOWN]; + break; + case 3: + DirectionMat=ArrowTextures[`ARROW_LEFT]; + break; + default: + DirectionMat=ArrowTextures[`ARROW_UP]; + break; + } + + DrawTileStretched(ScrollTexture,X,Y,Width,Height); + DrawTileStretched(DirectionMat,X,Y,Width,Height); +} + +final function DrawTileStretched( Texture Tex, float X, float Y, float XS, float YS ) +{ + local float mW,mH,MidX,MidY,SmallTileW,SmallTileH,fX,fY; + local int OptimizeTiles; + + if( Tex==None ) Tex = Texture2D'EngineMaterials.DefaultDiffuse'; + + // Get the size of the image + mW = Tex.GetSurfaceWidth(); + mH = Tex.GetSurfaceHeight(); + + // Get the midpoints of the image + MidX = int(mW/2); + MidY = int(mH/2); + + // Grab info about the scaled image + SmallTileW = XS - mW; + SmallTileH = YS - mH; + + // Optimized + OptimizeTiles = 4; + + if( mWYS) + fY = YS/2; + else + fY = MidY; + + Canvas.SetPos(X+fX,Y); + Canvas.DrawTile(Tex,SmallTileW,fY,MidX,0,1,fY); + Canvas.SetPos(X+fX,Y+YS-fY); + Canvas.DrawTile(Tex,SmallTileW,fY,MidX,mH-fY,1,fY); + } + else + fX = XS / 2; + + // Left and Right + if (mH X2-X1 ) + CurX = 0; + else CurX = ((X2-X1) / 2) - (XL/2); + } + else if( Justification == 2 ) + { + CurX = (X2-X1) - XL; + } + + Canvas.SetPos(CurX, CurY); + Canvas.DrawText(S,,XS, YS); +} + +static final function float TimeFraction( float Start, float End, float Current ) +{ + return FClamp((Current - Start) / (End - Start), 0.f, 1.f); +} + +static final function string LTrim(coerce string S) +{ + while (Left(S, 1) == " ") + S = Right(S, Len(S) - 1); + return S; +} + +static final function string RTrim(coerce string S) +{ + while (Right(S, 1) == " ") + S = Left(S, Len(S) - 1); + return S; +} + +static final function string Trim(coerce string S) +{ + return LTrim(RTrim(S)); +} + +defaultproperties +{ + MainFont=Font'KFClassicMode_Assets.Font.KFMainFont' + NumberFont=Font'UI_Canvas_Fonts.Font_General' + InfiniteFont=Font'KFClassicMode_Assets.Font.KFInfiniteFont' +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KF1HUD_BossHealthBar.uc b/Src/KFClassicHUD/Classes/KF1HUD_BossHealthBar.uc new file mode 100644 index 0000000..f52f0a2 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF1HUD_BossHealthBar.uc @@ -0,0 +1,84 @@ +class KF1HUD_BossHealthBar extends KFGFxWidget_BossHealthBar; + +function TickHud(float DeltaTime) +{ + local ClassicKFHUD HUD; + + HUD = ClassicKFHUD(KFPC.MyHUD); + if(KFPC.bHideBossHealthBar != bLastHideValue) + { + bLastHideValue = KFPC.bHideBossHealthBar; + + if(KFPC.bHideBossHealthBar && HUD.ScriptedPawn == none) + HUD.bDisplayImportantHealthBar = false; + else if(HUD.BossPawn != none || HUD.ScriptedPawn != none) + HUD.bDisplayImportantHealthBar = true; + } +} + +function SetEscortPawn(KFPawn_Scripted NewPawn) +{ + local ClassicKFHUD HUD; + + HUD = ClassicKFHUD(KFPC.MyHUD); + if (NewPawn == none) + return; + + EscortPawn = NewPawn; + + HUD.bDisplayImportantHealthBar = true; + HUD.BossInfoIcon = Texture2D(DynamicLoadObject(NewPawn.GetIconPath(),class'Texture2D')); + HUD.ScriptedPawn = NewPawn; +} + +function SetBossPawn(KFInterface_MonsterBoss NewBoss) +{ + BossPawn = NewBoss; + if(NewBoss == None || KFPC.bHideBossHealthBar) + return; + + ClassicKFHUD(KFPC.MyHUD).BossInfoIcon = Texture2D(DynamicLoadObject(NewBoss.GetIconPath(),class'Texture2D')); + ClassicKFHUD(KFPC.MyHUD).BossPawn = NewBoss; +} + +function UpdateBossShield(float NewShieldPercect) +{ + ClassicKFHUD(KFPC.MyHUD).BossShieldPct = NewShieldPercect; +} + +function UpdateBossBattlePhase(int BattlePhase) +{ + ClassicKFHUD(KFPC.MyHUD).BossBattlePhaseColor = ClassicKFHUD(KFPC.MyHUD).BattlePhaseColors[Max(BattlePhase - 1, 0)]; +} + +function OnNamePlateHidden() +{ + local ClassicKFHUD HUD; + + HUD = ClassicKFHUD(KFPC.MyHUD); + if(KFPC.bHideBossHealthBar && HUD.ScriptedPawn == none) + return; + + if(HUD.BossPawn != None) + HUD.bDisplayImportantHealthBar = true; + else HUD.bDisplayImportantHealthBar = false; +} + +simulated function Deactivate() +{ + local ClassicKFHUD HUD; + + HUD = ClassicKFHUD(KFPC.MyHUD); + + HUD.BossInfoIcon = None; + HUD.BossPawn = None; + HUD.BossShieldPct = 0.f; + HUD.BossBattlePhaseColor = HUD.default.BossBattlePhaseColor; + HUD.ScriptedPawn = None; + + HUD.bDisplayImportantHealthBar = false; +} + +DefaultProperties +{ +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KF1HUD_ChatBoxWidget.uc b/Src/KFClassicHUD/Classes/KF1HUD_ChatBoxWidget.uc new file mode 100644 index 0000000..520ce42 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF1HUD_ChatBoxWidget.uc @@ -0,0 +1,13 @@ +class KF1HUD_ChatBoxWidget extends KFGFxHUD_ChatBoxWidget; + +function AddChatMessage(string NewMessage, string HexVal) +{ + Super.AddChatMessage(NewMessage, HexVal); + if( InStr(NewMessage, "<"$class'KFCommon_LocalizedStrings'.default.TeamString$">") != INDEX_NONE || InStr(NewMessage, "<"$class'KFCommon_LocalizedStrings'.default.AllString$">") != INDEX_NONE ) + LocalPlayer(GetPC().Player).ViewportClient.ViewportConsole.OutputText(NewMessage); +} + +defaultproperties +{ +} + diff --git a/Src/KFClassicHUD/Classes/KF1HUD_MusicNotification.uc b/Src/KFClassicHUD/Classes/KF1HUD_MusicNotification.uc new file mode 100644 index 0000000..455e2a1 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF1HUD_MusicNotification.uc @@ -0,0 +1,25 @@ +class KF1HUD_MusicNotification extends KFGFxWidget_MusicNotification; + +function ShowSongInfo(string SongInfoString) +{ + local KFGameEngine KFEngine; + local ClassicKFHUD HUD; + local PopupMessage Msg; + + HUD = ClassicKFHUD(GetPC().MyHUD); + KFEngine = KFGameEngine(Class'Engine'.static.GetEngine()); + + if(KFEngine != none && KFEngine.MusicVolumeMultiplier > 0) + { + Msg.Body = SongInfoString; + Msg.Image = Texture2D'UI_HUD.InGameHUD_SWF_IBC'; + Msg.MsgPosition = PP_TOP_CENTER; + + HUD.AddPopupMessage(Msg); + } +} + +DefaultProperties +{ + +} diff --git a/Src/KFClassicHUD/Classes/KF1HUD_PlayerStatus.uc b/Src/KFClassicHUD/Classes/KF1HUD_PlayerStatus.uc new file mode 100644 index 0000000..36577f5 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF1HUD_PlayerStatus.uc @@ -0,0 +1,14 @@ +class KF1HUD_PlayerStatus extends KFGFxHUD_PlayerStatus; + +function UpdateXP(int XPDelta, int XPPercent, bool bLevelUp, Class PerkClass) +{ + if(!bLevelUp && MyPC.GetPerkLevelFromPerkList(PerkClass) < `MAX_PERK_LEVEL) + ClassicKFHUD(MyPC.MyHUD).NotifyXPEarned(XPDelta,PerkClass.default.PerkIcon,MakeColor(255, 255 * (KFPlayerReplicationInfo(MyPC.PlayerReplicationInfo).GetActivePerkLevel()/`MAX_PERK_LEVEL), 0, 255)); + + Super.UpdateXP(XPDelta, XPPercent, bLevelUp, PerkClass); +} + +DefaultProperties +{ + +} diff --git a/Src/KFClassicHUD/Classes/KF1HUD_WeaponSelectWidget.uc b/Src/KFClassicHUD/Classes/KF1HUD_WeaponSelectWidget.uc new file mode 100644 index 0000000..54b802e --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF1HUD_WeaponSelectWidget.uc @@ -0,0 +1,38 @@ +class KF1HUD_WeaponSelectWidget extends KFGFxHUD_WeaponSelectWidget; + +function SetSelectedWeapon(int GroupIndex, int SelectedIndex) +{ + local ClassicKFHUD HUD; + + HUD = ClassicKFHUD(GetPC().MyHUD); + if( !HUD.bDisplayInventory ) + { + HUD.bDisplayInventory = true; + HUD.InventoryFadeStartTime = GetPC().WorldInfo.TimeSeconds; + } + else HUD.RefreshInventory(); + + HUD.SelectedInventoryCategory = GroupIndex; + HUD.SelectedInventoryIndex = SelectedIndex; +} + +function InitializeObject(); +function SetThowButton(); +simulated function RefreshWeaponSelect(); +simulated function UpdateWeaponGroupOnHUD( byte GroupIndex ); +simulated function SetWeaponGroupList(out array WeaponList, byte GroupIndex); +simulated function SetWeaponList( GFxObject WeaponList, int GroupIndex ); +function Weapon GetSelectedWeapon(); +function UpdateIndex(); +function Hide(); +function SetWeaponCategories(); +function SendWeaponIndex( int GroupIndex, int SelectedIndex ); +function ShowOnlyHUDGroup( byte GroupIndex ); +function ShowAllHUDGroups(); +function FadeOut(); +function RefreshTimer(); +function SetWeaponSwitchStayOpen(bool bStayOpen); + +DefaultProperties +{ +} diff --git a/Src/KFClassicHUD/Classes/KF1_HUDWrapper.uc b/Src/KFClassicHUD/Classes/KF1_HUDWrapper.uc new file mode 100644 index 0000000..f8ab9fe --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF1_HUDWrapper.uc @@ -0,0 +1,227 @@ +class KF1_HUDWrapper extends KFGFxMoviePlayer_HUD; + +event bool WidgetInitialized(name WidgetName, name WidgetPath, GFxObject Widget) +{ + local bool Ret; + + if( WidgetName == 'ObjectiveContainer' ) + return false; + + Ret = Super.WidgetInitialized(WidgetName, WidgetPath, Widget); + + if( WaveInfoWidget != None ) + { + WaveInfoWidget.SetVisible(false); + } + + if( MusicNotification != None ) + { + MusicNotification.SetVisible(false); + } + + if( TraderCompassWidget != None ) + { + TraderCompassWidget.SetVisible(false); + } + + if( KeyboardWeaponSelectWidget != None ) + { + KeyboardWeaponSelectWidget.SetVisible(false); + } + + return Ret; +} + +function TickHud(float DeltaTime) +{ + local ASDisplayInfo DI; + + Super.TickHud(DeltaTime); + + if( PlayerStatusContainer != None ) + { + DI = PlayerStatusContainer.GetDisplayInfo(); + if( DI.Visible ) + { + DI.Visible = false; + PlayerStatusContainer.SetDisplayInfo(DI); + } + } + + if( PlayerBackpackContainer != None ) + { + DI = PlayerBackpackContainer.GetDisplayInfo(); + if( DI.Visible ) + { + DI.Visible = false; + PlayerBackpackContainer.SetDisplayInfo(DI); + } + } + + if( WaveInfoWidget != None ) + { + DI = WaveInfoWidget.GetDisplayInfo(); + if( DI.Visible ) + { + DI.Visible = false; + WaveInfoWidget.SetDisplayInfo(DI); + } + } + + if( TraderCompassWidget != None ) + { + DI = TraderCompassWidget.GetDisplayInfo(); + if( DI.Visible ) + { + DI.Visible = false; + TraderCompassWidget.SetDisplayInfo(DI); + } + } + + if( KeyboardWeaponSelectWidget != None ) + { + DI = KeyboardWeaponSelectWidget.GetDisplayInfo(); + if( DI.Visible ) + { + DI.Visible = false; + KeyboardWeaponSelectWidget.SetDisplayInfo(DI); + } + } +} + +function DisplayPriorityMessage(string InPrimaryMessageString, string InSecondaryMessageString, int LifeTime, optional KFLocalMessage_Priority.EGameMessageType MessageType) +{ + local KFGameReplicationInfo KFGRI; + local int ModifierIndex; + local FPriorityMessage PriorityMsg; + local KFWeeklyOutbreakInformation WeeklyInfo; + + KFGRI = KFGameReplicationInfo(class'WorldInfo'.static.GetWorldInfo().GRI); + + PriorityMsg.PrimaryText = InPrimaryMessageString; + PriorityMsg.SecondaryText = InSecondaryMessageString; + PriorityMsg.SecondaryAlign = PR_BOTTOM; + PriorityMsg.LifeTime = LifeTime; + + switch ( MessageType ) + { + case GMT_WaveStartSpecial: + if( KFGRI.IsSpecialWave(ModifierIndex) ) + { + PriorityMsg.SecondaryText = Localize("Zeds", SpecialWaveLocKey[ModifierIndex], "KFGame"); + PriorityMsg.Icon = Texture2D(DynamicLoadObject(SpecialWaveIconPath[ModifierIndex], class'Texture2D')); + } + break; + case GMT_WaveStartWeekly: + if( KFGRI.IsWeeklyWave(ModifierIndex) ) + { + WeeklyInfo = class'KFMission_LocalizedStrings'.static.GetWeeklyOutbreakInfoByIndex(ModifierIndex); + + PriorityMsg.SecondaryText = WeeklyInfo.FriendlyName; + PriorityMsg.Icon = Texture2D(DynamicLoadObject(WeeklyInfo.IconPath, class'Texture2D')); + } + break; + case GMT_WaveEnd: + PriorityMsg.Icon = Texture2D'DailyObjective_UI.KF2_Dailies_Icon_ZED'; + break; + case GMT_WaveStart: + PriorityMsg.Icon = Texture2D'DailyObjective_UI.KF2_Dailies_Icon_ZED'; + PriorityMsg.SecondaryIcon = Texture2D'UI_Widgets.MenuBarWidget_SWF_I11'; + PriorityMsg.SecondaryText = GetExpandedWaveInfo(); + break; + case GMT_WaveSBoss: + PriorityMsg.Icon = Texture2D'DailyObjective_UI.KF2_Dailies_Icon_ZED'; + PriorityMsg.SecondaryText = class'KFGFxHUD_WaveInfo'.default.BossWaveString; + break; + case GMT_MatchWon: + PriorityMsg.Icon = Texture2D'UI_Award_Team.UI_Award_Team-Kills'; + break; + case GMT_MatchLost: + PriorityMsg.Icon = Texture2D'UI_Award_ZEDs.UI_Award_ZED_Kills'; + break; + case GMT_LastPlayerStanding: + PriorityMsg.LifeTime *= 1.5f; + PriorityMsg.Icon = Texture2D'DailyObjective_UI.KF2_Dailies_Icon_ZED'; + break; + } + + ClassicKFHUD(KFPC.myHUD).ShowPriorityMessage(PriorityMsg); +} + +function string GetExpandedWaveInfo() +{ + local KFGameReplicationInfo KFGRI; + local int Wave; + + KFGRI = KFGameReplicationInfo(KFPC.WorldInfo.GRI); + if( KFPC.WorldInfo.NetMode == NM_StandAlone ) + Wave = KFGRI.WaveNum; + else Wave = KFGRI.WaveNum+1; + + if (KFGRI.default.bEndlessMode) + return class'KFGFxHUD_WaveInfo'.default.WaveString@string(KFGRI.WaveNum+1); + else + { + if( Wave == KFGRI.GetFinalWaveNum() ) + return class'KFGFxHUD_WaveInfo'.default.FinalWaveString; + else return class'KFGFxHUD_WaveInfo'.default.WaveString@Wave$"/"$KFGRI.GetFinalWaveNum(); + } + + return ""; +} + +function ShowKillMessage(PlayerReplicationInfo PRI1, PlayerReplicationInfo PRI2, optional bool bDeathMessage=false, optional Object OptionalObject) +{ + local bool bHumanDeath; + local string KilledName, KillerName; + local class KFPM; + + if(KFPC == none) + return; + + KFPM = class(OptionalObject); + + if( KFGXHUDManager != none ) + { + if(bDeathMessage) + { + if(KFPM != none) + KillerName=KFPM.static.GetLocalizedName(); + } + else + { + if(KFPM != none) + { + KilledName=KFPM.static.GetLocalizedName(); + bHumanDeath=false; + } + else if(PRI1 != none) + KillerName=PRI1.PlayerName; + } + + if(PRI2 != none) + { + if(PRI2.GetTeamNum() == class'KFTeamInfo_Human'.default.TeamIndex) + bHumanDeath=true; + else bHumanDeath=false; + KilledName=PRI2.PlayerName; + } + + ClassicKFHUD(KFPC.myHUD).ShowKillMessage(PRI1, PRI2, bHumanDeath, KilledName, KillerName); + } +} + +DefaultProperties +{ + WidgetBindings.Remove((WidgetName="PlayerStatWidgetMC",WidgetClass=class'KFGFxHUD_PlayerStatus')) + WidgetBindings.Add((WidgetName="PlayerStatWidgetMC",WidgetClass=class'KF1HUD_PlayerStatus')) + + WidgetBindings.Remove((WidgetName="WeaponSelectContainer",WidgetClass=class'KFGFxHUD_WeaponSelectWidget')) + WidgetBindings.Add((WidgetName="WeaponSelectContainer",WidgetClass=class'KF1HUD_WeaponSelectWidget')) + + WidgetBindings.Remove((WidgetName="MusicNotification", WidgetClass=class'KFGFxWidget_MusicNotification')) + WidgetBindings.Add((WidgetName="MusicNotification", WidgetClass=class'KF1HUD_MusicNotification')) + + WidgetBindings.Remove((WidgetName="ChatBoxWidget", WidgetClass=class'KFGFxHUD_ChatBoxWidget')) + WidgetBindings.Add((WidgetName="ChatBoxWidget", WidgetClass=class'KF1HUD_ChatBoxWidget')) +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KF2GUIController.uc b/Src/KFClassicHUD/Classes/KF2GUIController.uc new file mode 100644 index 0000000..b42c72a --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF2GUIController.uc @@ -0,0 +1,990 @@ +Class KF2GUIController extends Info + transient; + +var() class DefaultStyle; + +var PlayerController PlayerOwner; +var ClassicKFHUD HUDOwner; +var transient KF2GUIInput CustomInput; +var transient PlayerInput BackupInput; +var transient GameViewportClient ClientViewport; + +var delegate OldOnReceivedNativeInputKey; +var delegate OldOnReceivedNativeInputAxis; +var delegate OldOnReceivedNativeInputChar; + +var delegate OldHandleInputAxis; + +var array ActiveMenus,PersistentMenus; +var transient KFGUI_Base MouseFocus,InputFocus,KeyboardFocus; +var IntPoint MousePosition,ScreenSize,OldMousePos,LastMousePos,LastClickPos[2]; +var transient float MousePauseTime,MenuTime,LastClickTimes[2]; +var transient GUIStyleBase CurrentStyle; + +var transient Console OrgConsole; +var transient KFGUIConsoleHack HackConsole; + +var array CursorTextures; +var Color CursorColor; +var int CurrentCursorIndex, CursorSize; + +var Texture DefaultPens[3]; +var byte CursorFade, FastCursorFade, CursorFlash; +var int CursorStep, FastCursorStep; +var int FontBlurX,FontBlurX2,FontBlurY,FontBlurY2,FastFontBlurX,FastFontBlurX2,FastFontBlurY,FastFontBlurY2; + +var bool bMouseWasIdle,bIsInMenuState,bAbsorbInput,bIsInvalid,bFinishedReplication,bHideCursor,bUsingGamepad,bForceEngineCursor,bNoInputReset; + +static function KF2GUIController GetGUIController( PlayerController PC ) +{ + local KF2GUIController G; + + if( PC.Player==None ) + { + return None; + } + + foreach PC.ChildActors(class'KFClassicHUD.KF2GUIController',G) + { + if( !G.bIsInvalid ) + { + break; + } + } + + if( G==None ) + { + G = PC.Spawn(class'KFClassicHUD.KF2GUIController',PC); + } + + return G; +} + +simulated function PostBeginPlay() +{ + PlayerOwner = PlayerController(Owner); + ClientViewport = LocalPlayer(PlayerOwner.Player).ViewportClient; + HUDOwner = ClassicKFHUD(PlayerOwner.myHUD); + + CurrentStyle = new (None) DefaultStyle; + CurrentStyle.InitStyle(); + CurrentStyle.Owner = self; + + SetTimer(0.1, true, 'SetupFontBlur'); + SetTimer(0.05, true, 'SetupFastFontBlur'); + + SetTimer(0.25, true, 'SetupStyleTextures'); + SetupStyleTextures(); + + SetTimer(0.75, true, 'SetupCursorFlash'); +} + +simulated function SetupCursorFlash() +{ + if( CursorFlash == 255 ) + CursorFlash = 0; + else CursorFlash = 255; +} + +simulated function SetupStyleTextures() +{ + local ObjectReferencer RepObject; + + RepObject = HUDOwner.RepObject; + if( RepObject != None ) + { + CurrentStyle.MainFont = Font(RepObject.ReferencedObjects[104]); + CurrentStyle.InfiniteFont = Font(RepObject.ReferencedObjects[155]); + + CurrentStyle.BorderTextures[`BOX_INNERBORDER] = Texture2D(RepObject.ReferencedObjects[35]); + CurrentStyle.BorderTextures[`BOX_INNERBORDER_TRANSPARENT] = Texture2D(RepObject.ReferencedObjects[36]); + CurrentStyle.BorderTextures[`BOX_MEDIUM] = Texture2D(RepObject.ReferencedObjects[46]); + CurrentStyle.BorderTextures[`BOX_MEDIUM_SLIGHTTRANSPARENT] = Texture2D(RepObject.ReferencedObjects[47]); + CurrentStyle.BorderTextures[`BOX_MEDIUM_TRANSPARENT] = Texture2D(RepObject.ReferencedObjects[48]); + CurrentStyle.BorderTextures[`BOX_LARGE] = Texture2D(RepObject.ReferencedObjects[79]); + CurrentStyle.BorderTextures[`BOX_LARGE_SLIGHTTRANSPARENT] = Texture2D(RepObject.ReferencedObjects[80]); + CurrentStyle.BorderTextures[`BOX_LARGE_TRANSPARENT] = Texture2D(RepObject.ReferencedObjects[81]); + CurrentStyle.BorderTextures[`BOX_SMALL] = Texture2D(RepObject.ReferencedObjects[82]); + CurrentStyle.BorderTextures[`BOX_SMALL_SLIGHTTRANSPARENT] = Texture2D(RepObject.ReferencedObjects[83]); + CurrentStyle.BorderTextures[`BOX_SMALL_TRANSPARENT] = Texture2D(RepObject.ReferencedObjects[84]); + CurrentStyle.BorderTextures[`BOX_CORNER_8] = Texture2D(RepObject.ReferencedObjects[160]); + CurrentStyle.BorderTextures[`BOX_CORNER_16] = Texture2D(RepObject.ReferencedObjects[156]); + CurrentStyle.BorderTextures[`BOX_CORNER_32] = Texture2D(RepObject.ReferencedObjects[157]); + CurrentStyle.BorderTextures[`BOX_CORNER_64] = Texture2D(RepObject.ReferencedObjects[159]); + CurrentStyle.BorderTextures[`BOX_CORNER_512] = Texture2D(RepObject.ReferencedObjects[158]); + + CurrentStyle.ArrowTextures[`ARROW_DOWN] = Texture2D(RepObject.ReferencedObjects[10]); + CurrentStyle.ArrowTextures[`ARROW_LEFT] = Texture2D(RepObject.ReferencedObjects[45]); + CurrentStyle.ArrowTextures[`ARROW_RIGHT] = Texture2D(RepObject.ReferencedObjects[69]); + CurrentStyle.ArrowTextures[`ARROW_UP] = Texture2D(RepObject.ReferencedObjects[87]); + + CurrentStyle.ButtonTextures[`BUTTON_NORMAL] = Texture2D(RepObject.ReferencedObjects[3]); + CurrentStyle.ButtonTextures[`BUTTON_DISABLED] = Texture2D(RepObject.ReferencedObjects[4]); + CurrentStyle.ButtonTextures[`BUTTON_HIGHLIGHTED] = Texture2D(RepObject.ReferencedObjects[5]); + CurrentStyle.ButtonTextures[`BUTTON_PRESSED] = Texture2D(RepObject.ReferencedObjects[6]); + + CurrentStyle.TabTextures[`TAB_TOP] = Texture2D(RepObject.ReferencedObjects[76]); + CurrentStyle.TabTextures[`TAB_BOTTOM] = Texture2D(RepObject.ReferencedObjects[77]); + + CurrentStyle.ItemBoxTextures[`ITEMBOX_NORMAL] = Texture2D(RepObject.ReferencedObjects[40]); + CurrentStyle.ItemBoxTextures[`ITEMBOX_DISABLED] = Texture2D(RepObject.ReferencedObjects[41]); + CurrentStyle.ItemBoxTextures[`ITEMBOX_HIGHLIGHTED] = Texture2D(RepObject.ReferencedObjects[42]); + + CurrentStyle.ItemBoxTextures[`ITEMBOX_BAR_NORMAL] = Texture2D(RepObject.ReferencedObjects[37]); + CurrentStyle.ItemBoxTextures[`ITEMBOX_BAR_DISABLED] = Texture2D(RepObject.ReferencedObjects[38]); + CurrentStyle.ItemBoxTextures[`ITEMBOX_BAR_HIGHLIGHTED] = Texture2D(RepObject.ReferencedObjects[39]); + + CurrentStyle.CheckBoxTextures[`CHECKMARK_NORMAL] = Texture2D(RepObject.ReferencedObjects[7]); + CurrentStyle.CheckBoxTextures[`CHECKMARK_DISABLED] = Texture2D(RepObject.ReferencedObjects[8]); + CurrentStyle.CheckBoxTextures[`CHECKMARK_HIGHLIGHTED] = Texture2D(RepObject.ReferencedObjects[9]); + + CurrentStyle.PerkBox[`PERK_BOX_SELECTED] = Texture2D(RepObject.ReferencedObjects[60]); + CurrentStyle.PerkBox[`PERK_BOX_UNSELECTED] = Texture2D(RepObject.ReferencedObjects[61]); + + CurrentStyle.ScrollTexture = Texture2D(RepObject.ReferencedObjects[71]); + CurrentStyle.FavoriteIcon = Texture2D(RepObject.ReferencedObjects[105]); + CurrentStyle.BankNoteIcon = Texture2D(RepObject.ReferencedObjects[106]); + + CurrentStyle.ProgressBarTextures[`PROGRESS_BAR_NORMAL] = Texture2D(RepObject.ReferencedObjects[103]); + CurrentStyle.ProgressBarTextures[`PROGRESS_BAR_SELECTED] = Texture2D(RepObject.ReferencedObjects[68]); + + CurrentStyle.SliderTextures[`SLIDER_NORMAL] = Texture2D(RepObject.ReferencedObjects[110]); + CurrentStyle.SliderTextures[`SLIDER_GRIP] = Texture2D(RepObject.ReferencedObjects[111]); + CurrentStyle.SliderTextures[`SLIDER_DISABLED] = Texture2D(RepObject.ReferencedObjects[112]); + + CurrentStyle.MenuDown = SoundCue(RepObject.ReferencedObjects[49]); + CurrentStyle.MenuDrag = SoundCue(RepObject.ReferencedObjects[50]); + CurrentStyle.MenuEdit = SoundCue(RepObject.ReferencedObjects[51]); + CurrentStyle.MenuFade = SoundCue(RepObject.ReferencedObjects[52]); + CurrentStyle.MenuClick = SoundCue(RepObject.ReferencedObjects[53]); + CurrentStyle.MenuHover = SoundCue(RepObject.ReferencedObjects[54]); + CurrentStyle.MenuUp = SoundCue(RepObject.ReferencedObjects[55]); + + DefaultPens[`PEN_WHITE] = Texture2D(RepObject.ReferencedObjects[108]); + DefaultPens[`PEN_BLACK] = Texture2D(RepObject.ReferencedObjects[107]); + DefaultPens[`PEN_GRAY] = Texture2D(RepObject.ReferencedObjects[109]); + + /* + CursorTextures[`CURSOR_DEFAULT] = Texture2D(RepObject.ReferencedObjects[119]); + CursorTextures[`CURSOR_RESIZEVERT] = Texture2D(RepObject.ReferencedObjects[120]); + CursorTextures[`CURSOR_RESIZEHORZ] = Texture2D(RepObject.ReferencedObjects[121]); + */ + + bFinishedReplication = true; + ClearTimer('SetupStyleTextures'); + } +} + +simulated function SetupFastFontBlur() +{ + FastFontBlurX = RandRange(-8, 8); + FastFontBlurX2 = RandRange(-8, 8); + FastFontBlurY = RandRange(-8, 8); + FastFontBlurY2 = RandRange(-8, 8); +} + +simulated function SetupFontBlur() +{ + FontBlurX = RandRange(-8, 8); + FontBlurX2 = RandRange(-8, 8); + FontBlurY = RandRange(-8, 8); + FontBlurY2 = RandRange(-8, 8); +} + +simulated function Tick(float DT) +{ + Super.Tick(DT); + + DT /= WorldInfo.TimeDilation; + + CursorFade += 255 * DT * CursorStep; + if( CursorFade<=0 ) + { + CursorFade = 0; + CursorStep = 1; + } + else if( CursorFade>=255 ) + { + CursorFade = 255; + CursorStep = -1; + } + + FastCursorFade += 8192 * DT * FastCursorStep; + if( FastCursorFade<=0 ) + { + FastCursorFade = 0; + FastCursorStep = 1; + } + else if( FastCursorFade>=255 ) + { + FastCursorFade = 255; + FastCursorStep = -1; + } +} + +simulated function Destroyed() +{ + if( PlayerOwner!=None ) + SetMenuState(false); +} + +simulated function HandleDrawMenu() +{ + if( HackConsole==None ) + { + HackConsole = new(ClientViewport)class'KFClassicHUD.KFGUIConsoleHack'; + HackConsole.OutputObject = Self; + } + if( HackConsole!=ClientViewport.ViewportConsole ) + { + OrgConsole = ClientViewport.ViewportConsole; + ClientViewport.ViewportConsole = HackConsole; + + // Make sure nothing overrides these settings while menu is being open. + // PlayerOwner.PlayerInput = CustomInput; + } +} +simulated function RenderMenu( Canvas C ) +{ + local int i; + local float OrgX,OrgY,ClipX,ClipY; + + if( !bFinishedReplication || KFPlayerController(PlayerOwner).MyGFxManager.bMenusActive ) + return; + + ClientViewport.ViewportConsole = OrgConsole; + + ScreenSize.X = C.SizeX; + ScreenSize.Y = C.SizeY; + CurrentStyle.Canvas = C; + CurrentStyle.PickDefaultFontSize(C.SizeY); + + HUDOwner.Canvas = C; + HUDOwner.RenderKFHUD(KFPawn_Human(PlayerOwner.Pawn)); + + OrgX = C.OrgX; + OrgY = C.OrgY; + ClipX = C.ClipX; + ClipY = C.ClipY; + + for( i=(HUDOwner.HUDWidgets.Length-1); i>=0; --i ) + { + HUDOwner.HUDWidgets[i].InputPos[0] = 0.f; + HUDOwner.HUDWidgets[i].InputPos[1] = 0.f; + HUDOwner.HUDWidgets[i].InputPos[2] = ScreenSize.X; + HUDOwner.HUDWidgets[i].InputPos[3] = ScreenSize.Y; + HUDOwner.HUDWidgets[i].Canvas = C; + HUDOwner.HUDWidgets[i].PreDraw(); + } + + C.SetOrigin(OrgX,OrgY); + C.SetClip(ClipX,ClipY); + + if( bIsInMenuState ) + { + for( i=(ActiveMenus.Length-1); i>=0; --i ) + { + ActiveMenus[i].bWindowFocused = (i==0); + ActiveMenus[i].InputPos[0] = 0.f; + ActiveMenus[i].InputPos[1] = 0.f; + ActiveMenus[i].InputPos[2] = ScreenSize.X; + ActiveMenus[i].InputPos[3] = ScreenSize.Y; + ActiveMenus[i].Canvas = C; + ActiveMenus[i].PreDraw(); + } + if( InputFocus!=None && InputFocus.bFocusedPostDrawItem ) + { + InputFocus.InputPos[0] = 0.f; + InputFocus.InputPos[1] = 0.f; + InputFocus.InputPos[2] = ScreenSize.X; + InputFocus.InputPos[3] = ScreenSize.Y; + InputFocus.Canvas = C; + InputFocus.PreDraw(); + } + C.SetOrigin(OrgX,OrgY); + C.SetClip(ClipX,ClipY); + + if (!bHideCursor) + { + DrawCursor(C, MousePosition.X, MousePosition.Y); + } + } + + if( OrgConsole!=None ) + OrgConsole.PostRender_Console(C); + OrgConsole = None; +} + +simulated function DrawCursor(Canvas C, float PosX, float PosY) +{ + C.SetPos(PosX, PosY); + C.DrawColor = CursorColor; + C.DrawTile(CursorTextures[CurrentCursorIndex], CurrentStyle.ScreenScale(CursorSize), CurrentStyle.ScreenScale(CursorSize), 0.f, 0.f, CursorTextures[CurrentCursorIndex].SizeX, CursorTextures[CurrentCursorIndex].SizeY,, true); +} + +simulated final function InventoryChanged(optional KFWeapon Wep, optional bool bRemove) +{ + local int i; + + for( i=(ActiveMenus.Length-1); i>=0; --i ) + { + ActiveMenus[i].InventoryChanged(Wep,bRemove); + } +} + +simulated final function SetMenuState( bool bActive ) +{ + if( PlayerOwner.PlayerInput==None ) + { + NotifyLevelChange(); + bActive = false; + } + + if( bIsInMenuState==bActive ) + return; + bIsInMenuState = bActive; + bHideCursor = !bActive; + + if( bActive ) + { + if( CustomInput==None ) + { + CustomInput = new (KFPlayerController(PlayerOwner)) class'KFClassicHUD.KF2GUIInput'; + CustomInput.ControllerOwner = Self; + CustomInput.OnReceivedNativeInputKey = ReceivedInputKey; + CustomInput.BaseInput = PlayerOwner.PlayerInput; + BackupInput = PlayerOwner.PlayerInput; + PlayerOwner.Interactions.AddItem(CustomInput); + } + + OldOnReceivedNativeInputKey = BackupInput.OnReceivedNativeInputKey; + OldOnReceivedNativeInputAxis = BackupInput.OnReceivedNativeInputAxis; + OldOnReceivedNativeInputChar = BackupInput.OnReceivedNativeInputChar; + + BackupInput.OnReceivedNativeInputKey = ReceivedInputKey; + BackupInput.OnReceivedNativeInputAxis = ReceivedInputAxis; + BackupInput.OnReceivedNativeInputChar = ReceivedInputChar; + + OldHandleInputAxis = ClientViewport.HandleInputAxis; + ClientViewport.HandleInputAxis = ReceivedInputAxis; + + PlayerOwner.PlayerInput = CustomInput; + + if( LastMousePos != default.LastMousePos ) + ClientViewport.SetMouse(LastMousePos.X,LastMousePos.Y); + } + else + { + LastMousePos = MousePosition; + + ClientViewport.HandleInputAxis = None; + + if( BackupInput!=None ) + { + PlayerOwner.PlayerInput = BackupInput; + BackupInput.OnReceivedNativeInputKey = OldOnReceivedNativeInputKey; + BackupInput.OnReceivedNativeInputAxis = OldOnReceivedNativeInputAxis; + BackupInput.OnReceivedNativeInputChar = OldOnReceivedNativeInputChar; + + ClientViewport.HandleInputAxis = OldHandleInputAxis; + } + LastClickTimes[0] = 0; + LastClickTimes[1] = 0; + } + + if( !bNoInputReset ) + { + PlayerOwner.PlayerInput.ResetInput(); + } +} + +simulated function NotifyLevelChange() +{ + local int i; + + if( bIsInvalid ) + return; + bIsInvalid = true; + + if( InputFocus!=None ) + { + InputFocus.LostInputFocus(); + InputFocus = None; + } + + for( i=(ActiveMenus.Length-1); i>=0; --i ) + ActiveMenus[i].NotifyLevelChange(); + for( i=(PersistentMenus.Length-1); i>=0; --i ) + PersistentMenus[i].NotifyLevelChange(); + + SetMenuState(false); +} + +simulated function MenuInput(float DeltaTime) +{ + local int i; + local vector2D V; + + if( PlayerOwner.PlayerInput==None ) + { + NotifyLevelChange(); + return; + } + if( InputFocus!=None ) + InputFocus.MenuTick(DeltaTime); + for( i=0; i5.f || Abs(MousePosition.Y-OldMousePos.Y)>5.f || (bMouseWasIdle && MousePauseTime<0.5f) ) + { + if( bMouseWasIdle ) + { + bMouseWasIdle = false; + if( InputFocus!=None ) + InputFocus.InputMouseMoved(); + } + OldMousePos = MousePosition; + MousePauseTime = 0.f; + } + else if( !bMouseWasIdle && (MousePauseTime+=DeltaTime)>0.5f ) + { + bMouseWasIdle = true; + if( MouseFocus!=None ) + MouseFocus.NotifyMousePaused(); + } + + if( ActiveMenus.Length>0 ) + MenuTime+=DeltaTime; + + V = ClientViewport.GetMousePosition(); + + MousePosition.X = Clamp(V.X, 0, ScreenSize.X); + MousePosition.Y = Clamp(V.Y, 0, ScreenSize.Y); + + MouseMove(); +} + +simulated function MouseMove() +{ + local int i; + local KFGUI_Base F; + + // Capture mouse for GUI + if( InputFocus!=None && InputFocus.bCanFocus ) + { + if( InputFocus.CaptureMouse() ) + { + F = InputFocus.GetMouseFocus(); + if( F!=MouseFocus ) + { + MousePauseTime = 0; + if( MouseFocus!=None ) + MouseFocus.MouseLeave(); + MouseFocus = F; + F.MouseEnter(); + } + } + else i = ActiveMenus.Length; + } + else + { + for( i=0; i GUIClass ) +{ + local KFGUI_Base Widget; + + if( GUIClass==None ) + return None; + + Widget = New(None) GUIClass; + + if( Widget==None ) + return None; + + HUDOwner.HUDWidgets.AddItem(Widget); + + Widget.Owner = Self; + Widget.HUDOwner = HUDOwner; + Widget.InitMenu(); + Widget.ShowMenu(); + Widget.bIsHUDWidget = true; + + return Widget; +} +simulated function KFGUI_Page OpenMenu( class MenuClass ) +{ + local int i; + local KFGUI_Page M; + + if( MenuClass==None ) + return None; + + if( KeyboardFocus!=None ) + GrabInputFocus(None); + if( InputFocus!=None ) + { + InputFocus.LostInputFocus(); + InputFocus = None; + } + + // Enable mouse on UI if disabled. + SetMenuState(true); + + // Check if should use pre-excisting menu. + if( MenuClass.Default.bUnique ) + { + for( i=0; i0 && ActiveMenus[i].BringPageToFront() ) // Sort it upfront. + { + M = ActiveMenus[i]; + ActiveMenus.Remove(i,1); + i = GetFreeIndex(M.bAlwaysTop); + ActiveMenus[i] = M; + } + return M; + } + + if( MenuClass.Default.bPersistant ) + { + for( i=0; i MenuClass, optional bool bCloseAll ) +{ + local int i, j; + local KFGUI_Page M; + + if( !bCloseAll && MenuClass==None ) + return; + + if( KeyboardFocus!=None ) + GrabInputFocus(None); + if( InputFocus!=None ) + { + InputFocus.LostInputFocus(); + InputFocus = None; + } + for( i=(ActiveMenus.Length-1); i>=0; --i ) + { + if( bCloseAll || ActiveMenus[i].Class==MenuClass ) + { + M = ActiveMenus[i]; + ActiveMenus.Remove(i,1); + M.CloseMenu(); + + for( j=0; j=0; --i ) + if( ActiveMenus[i]==Item ) + { + M = ActiveMenus[i]; + ActiveMenus.Remove(i,1); + M.CloseMenu(); + + // Cache menu. + if( M.bPersistant && M.bUnique ) + PersistentMenus[PersistentMenus.Length] = M; + break; + } + if( ActiveMenus.Length==0 ) + SetMenuState(false); +} +simulated function BringMenuToFront( KFGUI_Page Page ) +{ + local int i; + + if( ActiveMenus[0].bAlwaysTop && !Page.bAlwaysTop ) + return; // Can't override this menu. + + // Try to remove from current position at stack. + for( i=(ActiveMenus.Length-1); i>=0; --i ) + if( ActiveMenus[i]==Page ) + { + ActiveMenus.Remove(i,1); + break; + } + if( i==-1 ) + return; // Page isn't open. + + // Put on front of stack. + ActiveMenus.Insert(0,1); + ActiveMenus[0] = Page; +} +simulated final function bool MenuIsOpen( optional class MenuClass ) +{ + local int i; + + for( i=(ActiveMenus.Length-1); i>=0; --i ) + if( MenuClass==None || ActiveMenus[i].Class==MenuClass ) + return true; + return false; +} +simulated final function GrabInputFocus( KFGUI_Base Comp, optional bool bForce ) +{ + if( Comp==KeyboardFocus && !bForce ) + return; + + if( KeyboardFocus!=None ) + KeyboardFocus.LostKeyFocus(); + + if( Comp==None ) + { + OnInputKey = InternalInputKey; + OnReceivedInputChar = InternalReceivedInputChar; + } + else if( KeyboardFocus==None ) + { + OnInputKey = Comp.NotifyInputKey; + OnReceivedInputChar = Comp.NotifyInputChar; + OnReceivedInputAxis = Comp.NotifyInputAxis; + } + KeyboardFocus = Comp; +} + +simulated final function GUI_InputMouse( bool bPressed, bool bRight ) +{ + local byte i; + + MousePauseTime = 0; + + if( bPressed ) + { + if( KeyboardFocus!=None && KeyboardFocus!=MouseFocus ) + { + GrabInputFocus(None); + LastClickTimes[0] = 0; + LastClickTimes[1] = 0; + } + if( MouseFocus!=None ) + { + if( MouseFocus!=InputFocus && !MouseFocus.bClickable && !MouseFocus.IsTopMenu() && MouseFocus.BringPageToFront() ) + { + BringMenuToFront(MouseFocus.GetPageTop()); + LastClickTimes[0] = 0; + LastClickTimes[1] = 0; + } + else + { + i = byte(bRight); + if( (MenuTime-LastClickTimes[i])<0.2 && Abs(LastClickPos[i].X-MousePosition.X)<5 && Abs(LastClickPos[i].Y-MousePosition.Y)<5 ) + { + LastClickTimes[i] = 0; + MouseFocus.DoubleMouseClick(bRight); + } + else + { + MouseFocus.MouseClick(bRight); + LastClickTimes[i] = MenuTime; + LastClickPos[i] = MousePosition; + } + } + } + else if( InputFocus!=None ) + { + InputFocus.LostInputFocus(); + InputFocus = None; + LastClickTimes[0] = 0; + LastClickTimes[1] = 0; + } + } + else + { + if( InputFocus!=None ) + InputFocus.MouseRelease(bRight); + else if( MouseFocus!=None ) + MouseFocus.MouseRelease(bRight); + } +} +simulated final function bool CheckMouse( name Key, EInputEvent Event ) +{ + if ( Event == IE_Pressed ) + { + switch( Key ) + { + case 'XboxTypeS_A': + case 'LeftMouseButton': + GUI_InputMouse(true,false); + return true; + case 'XboxTypeS_B': + case 'RightMouseButton': + GUI_InputMouse(true,true); + return true; + } + } + else if ( Event == IE_Released ) + { + switch( Key ) + { + case 'XboxTypeS_A': + case 'LeftMouseButton': + GUI_InputMouse(false,false); + return true; + case 'XboxTypeS_B': + case 'RightMouseButton': + GUI_InputMouse(false,true); + return true; + } + } + return false; +} +simulated function bool ReceivedInputKey( int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad ) +{ + local KFPlayerInput KFInput; + local KeyBind BoundKey; + + if( !bIsInMenuState ) + return false; + + bUsingGamepad = bGamepad; + + KFInput = KFPlayerInput(BackupInput); + if( KFInput == None ) + { + KFInput = KFPlayerInput(PlayerOwner.PlayerInput); + } + + if( KeyboardFocus == None ) + { + if( KFInput != None ) + { + KFInput.GetKeyBindFromCommand(BoundKey, "GBA_VoiceChat", false); + if( string(Key) ~= KFInput.GetBindDisplayName(BoundKey) ) + { + if( Event == IE_Pressed ) + { + KFInput.StartVoiceChat(true); + } + else if( Event == IE_Released ) + { + KFInput.StopVoiceChat(); + } + + return true; + } + } + } + + if( !CheckMouse(Key,Event) && !OnInputKey(ControllerId,Key,Event,AmountDepressed,bGamepad) ) + { + if( bGamepad ) + { + if( ActiveMenus[0].ReceievedControllerInput(ControllerId, Key, Event) ) + return true; + } + + switch( Key ) + { + case 'XboxTypeS_Start': + case 'Escape': + if( Event==IE_Pressed ) + ActiveMenus[0].UserPressedEsc(); // Pop top menu if possible. // IE_Released + return true; + case 'XboxTypeS_DPad_Up': + case 'XboxTypeS_DPad_Down': + case 'XboxTypeS_DPad_Left': + case 'XboxTypeS_DPad_Right': + case 'MouseScrollDown': + case 'MouseScrollUp': + if( Event==IE_Pressed && MouseFocus!=None ) + MouseFocus.ScrollMouseWheel(Key=='MouseScrollUp' || Key=='XboxTypeS_DPad_Up' || Key=='XboxTypeS_DPad_Left'); + return true; + } + + return bAbsorbInput; + } + + return true; +} +simulated function bool ReceivedInputAxis( int ControllerId, name Key, float Delta, float DeltaTime, bool bGamepad ) +{ + local Vector2D V; + local KFPlayerInput KFInput; + local float GamepadSensitivity,OldMouseX,OldMouseY,MoveDelta,MoveDeltaInvert; + + if( !bIsInMenuState ) + return false; + + if( bGamepad ) + { + if( Abs(Delta) > 0.2f ) + { + bUsingGamepad = true; + + V = ClientViewport.GetMousePosition(); + OldMouseX = V.X; + OldMouseY = V.Y; + + KFInput = KFPlayerInput(BackupInput); + GamepadSensitivity = KFInput.GamepadSensitivityScale * 10; + MoveDelta = Delta * (KFInput.bInvertController ? -GamepadSensitivity : GamepadSensitivity); + MoveDeltaInvert = Delta * (KFInput.bInvertController ? GamepadSensitivity : -GamepadSensitivity); + + switch(Key) + { + case 'XboxTypeS_LeftX': + case 'XboxTypeS_RightX': + if( Delta < 0 ) + V.X = Clamp(V.X - MoveDeltaInvert, 0, ScreenSize.X); + else V.X = Clamp(V.X + MoveDelta, 0, ScreenSize.X); + break; + case 'XboxTypeS_LeftY': + if( Delta < 0 ) + V.Y = Clamp(V.Y + MoveDeltaInvert, 0, ScreenSize.Y); + else V.Y = Clamp(V.Y - MoveDelta, 0, ScreenSize.Y); + break; + case 'XboxTypeS_RightY': + if( Delta < 0 ) + V.Y = Clamp(V.Y - MoveDeltaInvert, 0, ScreenSize.Y); + else V.Y = Clamp(V.Y + MoveDelta, 0, ScreenSize.Y); + break; + } + + if( OldMouseX != V.X || OldMouseY != V.Y ) + ClientViewport.SetMouse(V.X, V.Y); + } + } + return OnReceivedInputAxis(ControllerId, Key, Delta, DeltaTime, bGamepad); +} +simulated function bool ReceivedInputChar( int ControllerId, string Unicode ) +{ + if( !bIsInMenuState ) + return false; + return OnReceivedInputChar(ControllerId,Unicode); +} + +simulated Delegate bool OnInputKey( int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad ) +{ + return false; +} +simulated Delegate bool OnReceivedInputAxis( int ControllerId, name Key, float Delta, float DeltaTime, bool bGamepad ) +{ + return false; +} +simulated Delegate bool OnReceivedInputChar( int ControllerId, string Unicode ) +{ + return false; +} +simulated Delegate bool InternalInputKey( int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad ) +{ + return false; +} +simulated Delegate bool InternalReceivedInputChar( int ControllerId, string Unicode ) +{ + return false; +} + +defaultproperties +{ + CursorSize=24 + CursorColor=(R=255,G=255,B=255,A=255) + CursorTextures[`CURSOR_DEFAULT]=Texture2D'UI_Managers.LoaderManager_SWF_I13' + CurrentCursorIndex=`CURSOR_DEFAULT + + DefaultStyle=class'ClassicStyle' + bAbsorbInput=false + bAlwaysTick=true + bHideCursor=true +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KF2GUIInput.uc b/Src/KFClassicHUD/Classes/KF2GUIInput.uc new file mode 100644 index 0000000..7a1afb9 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF2GUIInput.uc @@ -0,0 +1,62 @@ +// Input while in a menu. +class KF2GUIInput extends KFPlayerInput; + +var KF2GUIController ControllerOwner; +var PlayerInput BaseInput; + +function DrawHUD( HUD H ) +{ + //ControllerOwner.RenderMenu(H.Canvas); +} +function PostRender( Canvas Canvas ) +{ + if( ControllerOwner.bIsInMenuState ) + ControllerOwner.HandleDrawMenu(); + //ControllerOwner.RenderMenu(Canvas); +} + +// Postprocess the player's input. +function PlayerInput( float DeltaTime ) +{ + // Do not move. + ControllerOwner.MenuInput(DeltaTime); + + if( !ControllerOwner.bAbsorbInput ) + { + aMouseX = 0; + aMouseY = 0; + aBaseX = BaseInput.aBaseX; + aBaseY = BaseInput.aBaseY; + aBaseZ = BaseInput.aBaseZ; + aForward = BaseInput.aForward; + aTurn = BaseInput.aTurn; + aStrafe = BaseInput.aStrafe; + aUp = BaseInput.aUp; + aLookUp = BaseInput.aLookUp; + Super.PlayerInput(DeltaTime); + } + else + { + aMouseX = 0; + aMouseY = 0; + aBaseX = 0; + aBaseY = 0; + aBaseZ = 0; + aForward = 0; + aTurn = 0; + aStrafe = 0; + aUp = 0; + aLookUp = 0; + } +} + +function PreClientTravel( string PendingURL, ETravelType TravelType, bool bIsSeamlessTravel) +{ + `Log("PreClientTravel"@PendingURL@TravelType@bIsSeamlessTravel); + ControllerOwner.BackupInput.PreClientTravel(PendingURL,TravelType,bIsSeamlessTravel); // Let original mod do stuff too! + ControllerOwner.NotifyLevelChange(); // Close menu NOW! +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KF2Style.uc b/Src/KFClassicHUD/Classes/KF2Style.uc new file mode 100644 index 0000000..3cb9bdc --- /dev/null +++ b/Src/KFClassicHUD/Classes/KF2Style.uc @@ -0,0 +1,452 @@ +Class KF2Style extends GUIStyleBase; + +var Texture2D LoadedTex[2]; +const TOOLTIP_BORDER=4; + +function InitStyle() +{ + local byte i; + + Super.InitStyle(); + + LoadedTex[0] = Texture2D(DynamicLoadObject("EditorMaterials.CASC_ModuleEnable",class'Texture2D')); + LoadedTex[1] = Texture2D(DynamicLoadObject("EditorMaterials.Tick",class'Texture2D')); + for( i=0; iTT.Owner.ScreenSize.X ) + X = TT.Owner.ScreenSize.X-TX; + if( (Y+TY)>TT.Owner.ScreenSize.Y ) + Y = TT.CompPos[1]-TY; + + if( TT.CurrentAlpha<255 ) + TT.CurrentAlpha = Min(TT.CurrentAlpha+25,255); + + // Reset clipping. + Canvas.SetOrigin(0,0); + Canvas.SetClip(TT.Owner.ScreenSize.X,TT.Owner.ScreenSize.Y); + + // Draw frame. + Canvas.SetDrawColor(200,200,80,TT.CurrentAlpha); + Canvas.SetPos(X-2,Y-2); + DrawBoxHollow(X-2,Y-2,TX+4,TY+4,2); + Canvas.SetDrawColor(80,10,80,TT.CurrentAlpha); + Canvas.SetPos(X,Y); + DrawWhiteBox(TX,TY); + + DefFontHeight = DefaultHeight; + + // Draw text. + Canvas.SetDrawColor(255,255,255,TT.CurrentAlpha); + X+=TOOLTIP_BORDER; + Y+=TOOLTIP_BORDER; + for( i=0; i0.f && X0.f && Y=YP && Y<=(YP+YL) ) + { + bCheckMouse = false; + C.CurrentRow = i; + Canvas.SetPos(4.f,YP); + Canvas.SetDrawColor(128,48,48,255); + DrawWhiteBox(C.CompPos[2]-(Edge*2.f),YL); + } + Canvas.SetPos(Edge,YP); + + if( i==C.Combo.SelectedIndex ) + Canvas.DrawColor = C.Combo.SelectedTextColor; + else Canvas.DrawColor = C.Combo.TextColor; + + Canvas.DrawText(C.Combo.Values[i],,C.Combo.TextScale,C.Combo.TextScale,C.Combo.TextFontInfo); + + YP+=YL; + } + Canvas.PopMaskRegion(); + if( C.OldRow!=C.CurrentRow ) + { + C.OldRow = C.CurrentRow; + C.PlayMenuSound(MN_DropdownChange); + } +} +function RenderRightClickMenu( KFGUI_RightClickMenu C ) +{ + local float X,Y,YP,Edge,TextScale,TexDefHieght; + local int i; + local bool bCheckMouse; + + // Draw background. + Edge = C.EdgeSize; + Canvas.SetDrawColor(148,4,4,255); + DrawBoxHollow(0.f,0.f,C.CompPos[2],C.CompPos[3],Edge); + Canvas.SetPos(Edge,Edge); + Canvas.SetDrawColor(64,4,4,200); + DrawWhiteBox(C.CompPos[2]-(Edge*2.f),C.CompPos[3]-(Edge*2.f)); + + // While rendering, figure out mouse focus row. + X = C.Owner.MousePosition.X - Canvas.OrgX; + Y = C.Owner.MousePosition.Y - Canvas.OrgY; + + bCheckMouse = (X>0.f && X0.f && Y=YP && Y<=(YP+TexDefHieght) ) + { + bCheckMouse = false; + C.CurrentRow = i; + Canvas.SetPos(4.f,YP); + Canvas.SetDrawColor(128,48,48,255); + DrawWhiteBox(C.CompPos[2]-(Edge*2.f),TexDefHieght); + } + + Canvas.SetPos(Edge,YP); + if( C.ItemRows[i].bSplitter ) + { + Canvas.SetDrawColor(0,0,0,255); + Canvas.DrawText("-------",,TextScale,TextScale); + } + else + { + if( C.ItemRows[i].bDisabled ) + Canvas.SetDrawColor(148,148,148,255); + else Canvas.SetDrawColor(248,248,248,255); + Canvas.DrawText(C.ItemRows[i].Text,,TextScale,TextScale); + } + + YP+=TexDefHieght; + } + Canvas.PopMaskRegion(); + if( C.OldRow!=C.CurrentRow ) + { + C.OldRow = C.CurrentRow; + C.PlayMenuSound(MN_DropdownChange); + } +} +function RenderButton( KFGUI_Button B ) +{ + local float XL,YL,TS; + local byte i; + + if( B.bDisabled ) + Canvas.SetDrawColor(32,0,0,255); + else if( B.bPressedDown ) + Canvas.SetDrawColor(255,64,64,255); + else if( B.bFocused ) + Canvas.SetDrawColor(180,45,45,255); + else Canvas.SetDrawColor(164,8,8,255); + + if( B.bIsHighlighted ) + { + Canvas.DrawColor.R = Min(Canvas.DrawColor.R+25,255); + Canvas.DrawColor.G = Min(Canvas.DrawColor.G+25,255); + Canvas.DrawColor.B = Min(Canvas.DrawColor.B+25,255); + } + + Canvas.SetPos(0.f,0.f); + if( B.ExtravDir==255 ) + DrawWhiteBox(B.CompPos[2],B.CompPos[3]); + else DrawRectBox(0,0,B.CompPos[2],B.CompPos[3],Min(B.CompPos[2],B.CompPos[3])*0.2,B.ExtravDir); + + if( B.OverlayTexture.Texture!=None ) + { + Canvas.SetPos(0.f,0.f); + Canvas.DrawTile(B.OverlayTexture.Texture,B.CompPos[2],B.CompPos[3],B.OverlayTexture.U,B.OverlayTexture.V,B.OverlayTexture.UL,B.OverlayTexture.VL); + } + if( B.ButtonText!="" ) + { + // Chose the best font to fit this button. + i = Min(B.FontScale,MaxFontScale); + while( true ) + { + Canvas.Font = PickFont(TS); + Canvas.TextSize(B.ButtonText,XL,YL,TS,TS); + if( i==0 || (XL<(B.CompPos[2]*0.95) && YL<(B.CompPos[3]*0.95)) ) + break; + --i; + } + Canvas.SetPos((B.CompPos[2]-XL)*0.5,(B.CompPos[3]-YL)*0.5); + if( B.bDisabled ) + Canvas.DrawColor = B.TextColor*0.5f; + else Canvas.DrawColor = B.TextColor; + Canvas.DrawText(B.ButtonText,,TS,TS,B.TextFontInfo); + } +} + +defaultproperties +{ + MaxFontScale=5 +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFColorHelper.uc b/Src/KFClassicHUD/Classes/KFColorHelper.uc new file mode 100644 index 0000000..5196cdc --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFColorHelper.uc @@ -0,0 +1,120 @@ +//All code here was done by Mr Evil. +class KFColorHelper extends Object + transient; + +struct HSVColour +{ + var() float H, S, V, A; + + structdefaultproperties + { + A=1.0 + } +}; + +static final function HSVColour RGBToHSV(const LinearColor RGB) +{ + local float Max; + local float Min; + local float Chroma; + local HSVColour HSV; + + Min = FMin(FMin(RGB.R, RGB.G), RGB.B); + Max = FMax(FMax(RGB.R, RGB.G), RGB.B); + Chroma = Max - Min; + + //If Chroma is 0, then S is 0 by definition, and H is undefined but 0 by convention. + if(Chroma != 0) + { + if(RGB.R == Max) + { + HSV.H = (RGB.G - RGB.B) / Chroma; + + if(HSV.H < 0.0) + { + HSV.H += 6.0; + } + } + else if(RGB.G == Max) + { + HSV.H = ((RGB.B - RGB.R) / Chroma) + 2.0; + } + else //RGB.B == Max + { + HSV.H = ((RGB.R - RGB.G) / Chroma) + 4.0; + } + + HSV.H *= 60.0; + HSV.S = Chroma / Max; + } + + HSV.V = Max; + HSV.A = RGB.A; + + return HSV; +} + +static final function LinearColor HSVToRGB(const HSVColour HSV) +{ + local float Min; + local float Chroma; + local float Hdash; + local float X; + local LinearColor RGB; + + Chroma = HSV.S * HSV.V; + Hdash = HSV.H / 60.0; + X = Chroma * (1.0 - Abs((Hdash % 2.0) - 1.0)); + + if(Hdash < 1.0) + { + RGB.R = Chroma; + RGB.G = X; + } + else if(Hdash < 2.0) + { + RGB.R = X; + RGB.G = Chroma; + } + else if(Hdash < 3.0) + { + RGB.G = Chroma; + RGB.B = X; + } + else if(Hdash < 4.0) + { + RGB.G= X; + RGB.B = Chroma; + } + else if(Hdash < 5.0) + { + RGB.R = X; + RGB.B = Chroma; + } + else if(Hdash < 6.0) + { + RGB.R = Chroma; + RGB.B = X; + } + + Min = HSV.V - Chroma; + + RGB.R += Min; + RGB.G += Min; + RGB.B += Min; + RGB.A = HSV.A; + + return RGB; +} + +static final function Color LinearColorToColor(const LinearColor RGB) +{ + local Color TrueRGB; + + TrueRGB.R = RGB.R * 255; + TrueRGB.G = RGB.G * 255; + TrueRGB.B = RGB.B * 255; + TrueRGB.A = RGB.A * 255; + + return TrueRGB; +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUIConsoleHack.uc b/Src/KFClassicHUD/Classes/KFGUIConsoleHack.uc new file mode 100644 index 0000000..f1279f6 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUIConsoleHack.uc @@ -0,0 +1,9 @@ +// Ugly hack to draw ontop of flash UI! +Class KFGUIConsoleHack extends Console; + +var KF2GUIController OutputObject; + +function PostRender_Console(Canvas Canvas) +{ + OutputObject.RenderMenu(Canvas); +} diff --git a/Src/KFClassicHUD/Classes/KFGUI_Base.uc b/Src/KFClassicHUD/Classes/KFGUI_Base.uc new file mode 100644 index 0000000..aeb28d1 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_Base.uc @@ -0,0 +1,344 @@ +// Menu system written by Marco. +Class KFGUI_Base extends Object + abstract; + +var KF2GUIController Owner; +var ClassicKFHUD HUDOwner; +var KFGUI_Base ParentComponent; // Parent component if any. +var transient Canvas Canvas; + +enum EMenuSound +{ + MN_Focus, + MN_LostFocus, + MN_FocusHover, + MN_ClickButton, + MN_ClickCheckboxOn, + MN_ClickCheckboxOff, + MN_Dropdown, + MN_DropdownChange, +}; + +var() float XPosition,YPosition,XSize,YSize; +var() name ID; // Just for internal purposes, you can give the components unique ID values. +var() int IDValue; // Integer ID value. +var transient float CompPos[4],InputPos[4]; + +var transient KFGUI_Base MouseArea; // Next in recurse line of the mouse pointer focus area. + +var() bool bDisabled,bClickable,bCanFocus; +var bool bFocusedPostDrawItem; // If this component has been given input focus, should it receive draw menu call after everything else been drawn? +var transient bool bFocused,bTextureInit,bVisible; +var bool bIsHUDWidget,bEnableInputs,bNoLookInputs; +var array TimerNames; + +function InitMenu(); // Menu was initialized for the first time. +function ShowMenu(); // Menu was opened. +function PreDraw() +{ + if( !bVisible ) + return; + + ComputeCoords(); + Canvas.SetDrawColor(255,255,255); + Canvas.SetOrigin(CompPos[0],CompPos[1]); + Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]); + DrawMenu(); +} +function DrawMenu(); // Draw menu now. +function CloseMenu(); // Menu was closed. +function InventoryChanged(optional KFWeapon Wep, optional bool bRemove); // Called when a players inventory is changed. +function MenuTick( float DeltaTime ); + +final function SetTimer(float InRate, optional bool inbLoop, optional Name inTimerFunc='Timer') +{ + if( InRate <= 0.f ) + { + ClearTimer(inTimerFunc); + return; + } + + if( TimerNames.Find(inTimerFunc) == INDEX_NONE ) + { + TimerNames.AddItem(inTimerFunc); + } + + `TimerHelper.SetTimer( InRate, inbLoop, inTimerFunc, self ); +} +final function ClearTimer(optional Name inTimerFunc='Timer') +{ + if( TimerNames.Find(inTimerFunc) != INDEX_NONE ) + { + TimerNames.RemoveItem(inTimerFunc); + } + + `TimerHelper.ClearTimer( inTimerFunc, self ); +} +function Timer(); + +function MouseEnter() +{ + bFocused = true; + OnFocus(Self,True); +} +function MouseLeave() +{ + bFocused = false; + OnFocus(Self,False); +} +function MouseClick( bool bRight ); +function MouseRelease( bool bRight ); +function DoubleMouseClick( bool bRight ) // User rapidly double clicked this component. +{ + MouseClick(bRight); +} + +function ScrollMouseWheel( bool bUp ); + +function bool ReceievedControllerInput(int ControllerId, name Key, EInputEvent Event) +{ + return false; +} + +final function PlayerController GetPlayer() +{ + return Owner.PlayerOwner; +} + +function SetDisabled( bool bDisable ) +{ + bDisabled = bDisable; +} + +Delegate OnFocus( KFGUI_Base Sender, bool bBecame ); + +final function ComputeCoords() +{ + CompPos[0] = XPosition*InputPos[2]+InputPos[0]; + CompPos[1] = YPosition*InputPos[3]+InputPos[1]; + CompPos[2] = XSize*InputPos[2]; + CompPos[3] = YSize*InputPos[3]; +} + +function bool CaptureMouse() +{ + return bVisible && ( Owner.MousePosition.X>=CompPos[0] && Owner.MousePosition.Y>=CompPos[1] && Owner.MousePosition.X<=(CompPos[0]+CompPos[2]) && Owner.MousePosition.Y<=(CompPos[1]+CompPos[3]) ); +} + +final function KFGUI_Base GetMouseFocus() +{ + local KFGUI_Base M; + + for( M=Self; M.MouseArea!=None; M=M.MouseArea ) + {} + return M; +} + +function SetVisibility(bool Visible) +{ + bVisible = Visible; +} + +function DoClose() +{ + local int i; + + for( i=0; i0 && GetPageTop()==Owner.ActiveMenus[0]); +} +final function KFGUI_Page GetPageTop() +{ + local KFGUI_Base M; + + for( M=Self; M.ParentComponent!=None; M=M.ParentComponent ) + {} + return KFGUI_Page(M); +} +function KFGUI_Base FindComponentID( name InID ) +{ + if( ID==InID ) + return Self; + return None; +} +function FindAllComponentID( name InID, out array Res ) +{ + if( ID==InID ) + Res[Res.Length] = Self; +} +function RemoveComponent( KFGUI_Base B ); + +function GetInputFocus() +{ + if( Owner.InputFocus!=None ) + Owner.InputFocus.LostInputFocus(); + Owner.InputFocus = Self; +} +function DropInputFocus() +{ + if( Owner.InputFocus==Self ) + { + Owner.InputFocus.LostInputFocus(); + Owner.InputFocus = None; + } +} +function LostInputFocus(); + +// Obtain keyboard focus. +final function GrabKeyFocus() +{ + Owner.GrabInputFocus(Self); +} +final function ReleaseKeyFocus() +{ + if( Owner.KeyboardFocus==Self ) + Owner.GrabInputFocus(None); +} +function LostKeyFocus(); + +function bool NotifyInputKey( int ControllerId, name Key, EInputEvent Event, float AmountDepressed, bool bGamepad ) +{ + if( bIsHUDWidget && bEnableInputs ) + { + switch( Key ) + { + case 'XboxTypeS_Start': + case 'Escape': + if( Event==IE_Pressed ) + UserPressedEsc(); + return true; + case 'XboxTypeS_DPad_Up': + case 'XboxTypeS_DPad_Down': + case 'XboxTypeS_DPad_Left': + case 'XboxTypeS_DPad_Right': + case 'MouseScrollDown': + case 'MouseScrollUp': + case 'MouseScrollDown': + case 'MouseScrollUp': + if( Event==IE_Pressed ) + ScrollMouseWheel(Key=='MouseScrollUp' || Key=='XboxTypeS_DPad_Up' || Key=='XboxTypeS_DPad_Left'); + return true; + } + } + + return false; +} +function bool NotifyInputAxis( int ControllerId, name Key, float Delta, float DeltaTime, bool bGamepad ) +{ + return false; +} +function bool NotifyInputChar( int ControllerId, string Unicode ) +{ + return false; +} + +// While on input focus mode, notify that mouse just moved over the threshold. +function InputMouseMoved(); + +// Notify any focused menu element that mouse has been idle over it. +function NotifyMousePaused(); + +final function GetActualPos( out float X, out float Y ) +{ + X = ((XPosition+X)*InputPos[2]) + InputPos[0]; + Y = ((YPosition+Y)*InputPos[3]) + InputPos[1]; +} +final function GetRealtivePos( out float X, out float Y ) +{ + X = X / CompPos[2]; + Y = Y / CompPos[2]; +} + +simulated final function PlayMenuSound( EMenuSound Slot ) +{ + local SoundCue S; + local KFGameEngine Engine; + + Engine = KFGameEngine(class'Engine'.static.GetEngine()); + + switch( Slot ) + { + case MN_FocusHover: + case MN_Focus: + S = Owner.CurrentStyle.MenuHover; + break; + case MN_LostFocus: + S = Owner.CurrentStyle.MenuFade; + break; + case MN_ClickButton: + case MN_ClickCheckboxOff: + S = Owner.CurrentStyle.MenuClick; + break; + case MN_Dropdown: + S = Owner.CurrentStyle.MenuDown; + break; + case MN_DropdownChange: + S = Owner.CurrentStyle.MenuEdit; + break; + } + + if( S!=None ) + { + S.VolumeMultiplier = (Engine.SFxVolumeMultiplier/100.f) * (Engine.MasterVolumeMultiplier/100.f); + GetPlayer().PlaySound(S,true,,false); + } +} + +// Pre level change notification. +function NotifyLevelChange(); + +final function SetPosition( float X, float Y, float XS, float YS ) +{ + XPosition = X; + YPosition = Y; + XSize = XS; + YSize = YS; +} + +static final function string MakeSortStr( int Value ) +{ + local string S; + local int i; + + // Prefix with zeroes to properly sort this string. + S = string(Value); + i = Len(S); + if( i<10 ) + return Mid("0000000000",i)$S; + return S; +} + +defaultproperties +{ + XSize=1 + YSize=1 + bCanFocus=true + bVisible=true +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_Button.uc b/Src/KFClassicHUD/Classes/KFGUI_Button.uc new file mode 100644 index 0000000..939b1af --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_Button.uc @@ -0,0 +1,41 @@ +Class KFGUI_Button extends KFGUI_Clickable; + +var() Canvas.CanvasIcon OverlayTexture; +var() string ButtonText,GamepadButtonName; +var() color TextColor; +var() Canvas.FontRenderInfo TextFontInfo; +var() byte FontScale,ExtravDir; +var bool bIsHighlighted; + +function DrawMenu() +{ + Owner.CurrentStyle.RenderButton(Self); +} + +function bool GetUsingGamepad() +{ + return Owner.bUsingGamepad && GamepadButtonName != ""; +} + +function HandleMouseClick( bool bRight ) +{ + if( bRight ) + OnClickRight(Self); + else OnClickLeft(Self); +} + +Delegate OnClickLeft( KFGUI_Button Sender ); +Delegate OnClickRight( KFGUI_Button Sender ); + +Delegate bool DrawOverride(Canvas C, KFGUI_Button B) +{ + return false; +} + +defaultproperties +{ + ButtonText="Button!" + TextColor=(R=0,G=0,B=0,A=255) + TextFontInfo=(bClipText=true,bEnableShadow=true) + FontScale=1 +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_CategoryButton.uc b/Src/KFClassicHUD/Classes/KFGUI_CategoryButton.uc new file mode 100644 index 0000000..2e69fc0 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_CategoryButton.uc @@ -0,0 +1,80 @@ +class KFGUI_CategoryButton extends KFGUI_Button; + +var transient bool bOpened; +var Texture2D Icon; +var Color IconColor; + +function DrawMenu() +{ + local float XL,YL,TS,TextX,TextY; + local Texture2D Mat; + local bool bDrawOverride; + + bDrawOverride = DrawOverride(Canvas, Self); + if( !bDrawOverride ) + { + if( bDisabled ) + Mat = Owner.CurrentStyle.ButtonTextures[`BUTTON_DISABLED]; + else if( bPressedDown ) + Mat = Owner.CurrentStyle.ButtonTextures[`BUTTON_PRESSED]; + else if( bFocused || bIsHighlighted ) + Mat = Owner.CurrentStyle.ButtonTextures[`BUTTON_NORMAL]; + else Mat = Owner.CurrentStyle.ButtonTextures[`BUTTON_HIGHLIGHTED]; + + Canvas.SetPos(0.f,0.f); + Canvas.DrawTileStretched(Mat,CompPos[2],CompPos[3],0,0,32,32); + + if( OverlayTexture.Texture!=None ) + { + Canvas.SetPos(0.f,0.f); + Canvas.DrawTile(OverlayTexture.Texture,CompPos[2],CompPos[3],OverlayTexture.U,OverlayTexture.V,OverlayTexture.UL,OverlayTexture.VL); + } + } + + if( ButtonText!="" ) + { + Canvas.Font = Owner.CurrentStyle.MainFont; + + TS = Owner.CurrentStyle.GetFontScaler(); + TS *= FontScale; + + while( true ) + { + Canvas.TextSize(ButtonText,XL,YL,TS,TS); + if( XL<(CompPos[2]*0.9) && YL<(CompPos[3]*0.9) ) + break; + + TS -= 0.001; + } + + TextX = (CompPos[2]-XL)*0.5; + TextY = (CompPos[3]-YL)*0.5; + + Canvas.SetPos(TextX, TextY); + if( bDisabled ) + Canvas.DrawColor = TextColor*0.5f; + else Canvas.DrawColor = TextColor; + Canvas.DrawText(ButtonText,,TS,TS,TextFontInfo); + + if( Icon != None ) + { + Canvas.DrawColor = IconColor; + + Canvas.SetPos(TextX-CompPos[3], 0.f); + Canvas.DrawRect(CompPos[3], CompPos[3], Icon); + + Canvas.SetPos(TextX+XL, 0.f); + Canvas.DrawRect(CompPos[3], CompPos[3], Icon); + } + } + + Canvas.DrawColor = class'HUD'.default.WhiteColor; + Canvas.SetPos(0.f,0.f); + Canvas.DrawRect(CompPos[3], CompPos[3], bOpened ? Owner.CurrentStyle.ArrowTextures[`ARROW_DOWN] : Owner.CurrentStyle.ArrowTextures[`ARROW_RIGHT]); + Canvas.SetPos(CompPos[2]-CompPos[3], 0.f); + Canvas.DrawRect(CompPos[3], CompPos[3], bOpened ? Owner.CurrentStyle.ArrowTextures[`ARROW_DOWN] : Owner.CurrentStyle.ArrowTextures[`ARROW_LEFT]); +} + +defaultproperties +{ +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_CategoryList.uc b/Src/KFClassicHUD/Classes/KFGUI_CategoryList.uc new file mode 100644 index 0000000..db97e35 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_CategoryList.uc @@ -0,0 +1,89 @@ +class KFGUI_CategoryList extends KFGUI_ComponentList; + +// Broken, does not work correctly when closing a menu and re-opening it if a category is open +struct FCategoryItems +{ + var name ID; + var KFGUI_Base Item; +}; +var array CategoryItems; + +function AddCategory(name CatID, string CatName, optional Texture2D IconMat, optional Color IconClr, optional float XS=1.f, optional float YS=1.f) +{ + local KFGUI_CategoryButton B; + + B = KFGUI_CategoryButton(AddListComponent(class'KFGUI_CategoryButton', XS, YS)); + B.ButtonText = CatName; + B.ID = CatID; + B.Icon = IconMat; + B.IconColor = IconClr; + B.OnClickLeft = SelectedCategory; + B.OnClickRight = SelectedCategory; +} + +function KFGUI_Base AddItemToCategory(name CatID, class Item) +{ + local FCategoryItems CatItem; + local KFGUI_Base G; + + G = CreateComponent(Item); + G.ID = CatID; + G.Owner = Owner; + G.ParentComponent = Self; + + CatItem.ID = CatID; + CatItem.Item = G; + CategoryItems.AddItem(CatItem); + + return G; +} + +function SelectedCategory(KFGUI_Button Sender) +{ + local int i, j, Index; + local KFGUI_CategoryButton CatB; + + CatB = KFGUI_CategoryButton(Sender); + if( CatB == None ) + return; + + Index = ItemComponents.Find(Sender); + if( Index != INDEX_NONE ) + { + if( !CatB.bOpened ) + { + CatB.bOpened = true; + j = Index+1; + for( i=0; i Columns; +var() class ListItemClass; +var() float FontSize; +var() color FocusedLineColor,SelectedLineColor; +var() float EdgeSize; +var KFGUI_ColumnTop ColumnComp; +var Canvas.FontRenderInfo LineFontInfo; + +var int SelectedRowIndex; +var int LastSortedColumn; + +var transient float TextHeight,ScalerSize,TextScaler; +var transient int OldItemsPerFrame; + +var KFGUI_ListItem FirstItem,UnusedItem; + +var transient bool bListSizeDirty; +var bool bLastSortedReverse; +var() bool bShouldSortList; // Should sort any new items added to the list instantly. +var() bool bCanSortColumn; // Allow user to sort columns. + +delegate OnSelectedRow( KFGUI_ListItem Item, int Row, bool bRight, bool bDblClick ); + +function KFGUI_ListItem AddLine( string Value, optional int iValue, optional string SortValue, optional int Index=-1 ) +{ + local KFGUI_ListItem N,O; + local int i; + + // Allocate list item object. + if( UnusedItem!=None ) + { + N = UnusedItem; + UnusedItem = N.Next; + N.Next = None; + } + else N = new (None) ListItemClass; + + // Setup column text value. + N.SetValue(Value,iValue,SortValue); + + // Insert into list. + if( bShouldSortList && Index==-1 ) + { + N.Temp = N.GetSortStr(LastSortedColumn); + + if( ListCount==0 ) // No sorting needed yet. + { + N.Next = FirstItem; + FirstItem = N; + } + else if( bLastSortedReverse ) + { + if( FirstItem.TempN.Temp ) + { + N.Next = FirstItem; + FirstItem = N; + } + else + { + for( O=FirstItem; O!=None; O=O.Next ) + { + if( O.Next==None || O.Next.Temp>N.Temp ) + { + N.Next = O.Next; + O.Next = N; + break; + } + } + } + } + else if( Index==-1 || Index>ListCount ) + Index = ListCount; + if( Index==0 ) + { + N.Next = FirstItem; + FirstItem = N; + } + else + { + i = 0; + for( O=FirstItem; O!=None; O=O.Next ) + { + if( (++i)==Index ) + { + N.Next = O.Next; + O.Next = N; + break; + } + } + } + UpdateListSize(); + + return N; +} +final function RemoveLine( KFGUI_ListItem I ) +{ + local KFGUI_ListItem N; + + if( I.Index==-1 ) + return; + + // Update selected row info. + if( SelectedRowIndex==I.Index ) + SelectedRowIndex = -1; + else if( SelectedRowIndex>I.Index ) + --SelectedRowIndex; + + // Remove from list. + if( FirstItem==I ) + FirstItem = I.Next; + else + { + for( N=FirstItem; N!=None; N=N.Next ) + if( N.Next==I ) + { + N.Next = I.Next; + break; + } + } + + // Add to unused list. + I.Next = UnusedItem; + UnusedItem = I; + I.Index = -1; + + UpdateListSize(); +} +final function EmptyList() +{ + local KFGUI_ListItem N,I; + + for( I=FirstItem; I!=None; I=N ) + { + N = I.Next; + + // Add to unused list. + I.Next = UnusedItem; + UnusedItem = I; + I.Index = -1; + } + + FirstItem = None; + UpdateListSize(); +} + +final function KFGUI_ListItem GetFromIndex( int Index ) +{ + local KFGUI_ListItem N; + + if( Index<0 || Index>=ListCount ) + return None; + for( N=FirstItem; N!=None; N=N.Next ) + if( (Index--)==0 ) + return N; + return None; +} + +function SortColumn( int Column, optional bool bReverse ) +{ + local array List; + local KFGUI_ListItem Sel,N,P; + local int i; + + if( !bCanSortColumn || Column<0 || Column>=Columns.Length ) + return; + + LastSortedColumn = Column; + bLastSortedReverse = bReverse; + bShouldSortList = true; + + // Allocate memory space first. + List.Length = ListCount; + List.Length = 0; + + // Grab current selected line. + Sel = GetFromIndex(SelectedRowIndex); + SelectedRowIndex = -1; + + // Slow, sort it all. + for( N=FirstItem; N!=None; N=N.Next ) + { + N.Temp = N.GetSortStr(Column); + + if( bReverse ) + { + for( i=0; iN.Temp ) + break; + } + List.Insert(i,1); + List[i] = N; + } + + // Rebuild list. + FirstItem = None; + P = None; + for( i=0; i=ListCount ) + SelectedRowIndex = -1; + OldItemsPerFrame = ListItemsPerPage; + bListSizeDirty = false; + UpdateListVis(); + } + + // Draw vertical scrollbar + ScrollBar.Canvas = Canvas; + ScrollBar.PreDraw(); + + // Draw self. + Canvas.SetOrigin(CompPos[0],CompPos[1]); + Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]); + DrawMenu(); + + // Reset scaling to allow mouse to capture input. + CompPos[1] -= ColumnComp.CompPos[3]; + CompPos[2] += SpaceX; + CompPos[3] += ColumnComp.CompPos[3]; +} +function InternalClickedItem( int Index, bool bRight, int MouseX, int MouseY ) +{ + SelectedRowIndex = Index; + OnSelectedRow(GetFromIndex(Index),Index,bRight,false); +} +function InternalDblClickedItem( int Index, bool bRight, int MouseX, int MouseY ) +{ + SelectedRowIndex = Index; + OnSelectedRow(GetFromIndex(Index),Index,bRight,true); +} + +defaultproperties +{ + ListItemClass=class'KFGUI_ListItem' + OnClickedItem=InternalClickedItem + OnDblClickedItem=InternalDblClickedItem + SelectedRowIndex=-1 + FontSize=1.f + EdgeSize=5.f + bClickable=true + FocusedLineColor=(R=64,G=3,B=48,A=255) + SelectedLineColor=(R=84,G=26,B=128,A=255) + bCanSortColumn=true + + Begin Object Class=KFGUI_ColumnTop Name=ColumnComps + XPosition=0 + YPosition=0 + XSize=1 + YSize=0.04 + ID="Columns" + End Object + Components.Add(ColumnComps) + + LineFontInfo=(bClipText=true,bEnableShadow=false) +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ColumnTop.uc b/Src/KFClassicHUD/Classes/KFGUI_ColumnTop.uc new file mode 100644 index 0000000..32dcd58 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ColumnTop.uc @@ -0,0 +1,206 @@ +// Do not use this on your own, it is used by ColumnList +Class KFGUI_ColumnTop extends KFGUI_Base; + +var() float ColumnMinSize; // Minimum pixels width allowed. +var KFGUI_ColumnList ListOwner; + +var transient int PrevSortedColumn,MouseColumn,ScalingColumn; +var transient byte PressedDown[2]; +var transient bool bPressedDown,bScaleColumn,bMouseScaler; + +function InitMenu() +{ + Super.InitMenu(); + ListOwner = KFGUI_ColumnList(ParentComponent); +} + +function DrawMenu() +{ + local int i,j; + local float X,XS,MouseX,GrabWidth,MinSize,Wd; + local bool bCheckMouse; + + bClickable = ListOwner.bClickable; + MinSize = ColumnMinSize / CompPos[2]; + + // Scale column + if( bScaleColumn ) + { + MouseX = Owner.MousePosition.X - CompPos[0]; + for( i=0; i=(1.f-MinSize) ) + { + MouseX = X-(1.f-MinSize); // Grab overshoot. + + // Then push back! + for( j=i; j>=0; --j ) + { + if( (ListOwner.Columns[j].Width-MouseX)>MinSize ) // This column has enough space to retract. + { + ListOwner.Columns[j].Width-=MouseX; + MouseX = 0; + break; + } + else if( ListOwner.Columns[j].Width>MinSize ) // This column has limited space to retract. + { + MouseX-=(ListOwner.Columns[j].Width-MinSize); + ListOwner.Columns[j].Width = MinSize; + } + } + X = (1.f-MinSize); // Continue at maximum size. + } + } + } + + // Init mouse check. + MouseColumn = -1; + bCheckMouse = (bClickable && bFocused); + if( bCheckMouse ) + { + GrabWidth = CompPos[3]*0.175; + MouseX = Owner.MousePosition.X - CompPos[0] - GrabWidth; + GrabWidth *= -2.f; + } + + // Draw the columns and compute the scalings. + X = 0; + j = (ListOwner.bShouldSortList ? ListOwner.LastSortedColumn : -1); + for( i=0; i=GrabWidth) && ((i+1)=CompPos[2] ) + ListOwner.Columns[i].bHidden = true; + else + { + ListOwner.Columns[i].bHidden = false; + //Canvas.SetClip(X+Wd,CompPos[1]+CompPos[3]); + + // Draw column. + if( i==j ) + { + if( MouseColumn==i && !bMouseScaler ) + Canvas.SetDrawColor(175,240,8,255); + else Canvas.SetDrawColor(128,200,56,255); + } + else if( MouseColumn==i && !bMouseScaler ) + Canvas.SetDrawColor(220,220,8,255); + + XS = Owner.CurrentStyle.DefaultHeight*0.5; + Canvas.SetPos(X,0.f); + Canvas.DrawTileStretched(Owner.CurrentStyle.TabTextures[`TAB_TOP],Min(Wd,CompPos[2]-X),CompPos[3],0,0,128,16); + + Canvas.SetDrawColor(250,250,250,255); + Canvas.SetPos(X+XS,(CompPos[3]-ListOwner.TextHeight)*0.5f); + ListOwner.DrawStrClipped(ListOwner.Columns[i].Text); + } + X+=Wd; + } +} + +function MouseClick( bool bRight ) +{ + if( !ListOwner.bDisabled && bClickable ) + { + PressedDown[byte(bRight)] = 1; + bPressedDown = true; + + if( !bRight && bMouseScaler ) + { + PlayMenuSound(MN_ClickButton); + bScaleColumn = true; + ScalingColumn = MouseColumn; + GetInputFocus(); + } + } +} +function MouseRelease( bool bRight ) +{ + if( bScaleColumn && !bRight ) + { + bScaleColumn = false; + DropInputFocus(); + return; + } + if( !bDisabled && bClickable && PressedDown[byte(bRight)]==1 ) + { + PlayMenuSound(MN_ClickButton); + PressedDown[byte(bRight)] = 0; + bPressedDown = (PressedDown[0]!=0 || PressedDown[1]!=0); + + if( MouseColumn>=0 ) + { + ListOwner.SortColumn(MouseColumn,(PrevSortedColumn==MouseColumn)); + if( PrevSortedColumn==MouseColumn ) + PrevSortedColumn = -1; + else PrevSortedColumn = MouseColumn; + } + } +} +function byte GetCursorStyle() +{ + if( bClickable ) + return (bMouseScaler ? 2 : 1); + return 0; +} +function MouseLeave() +{ + Super.MouseLeave(); + if( !bScaleColumn ) + { + PressedDown[0] = 0; + PressedDown[1] = 0; + bPressedDown = false; + } +} +function MouseEnter() +{ + Super.MouseEnter(); +} + +function LostInputFocus() +{ + bScaleColumn = false; + PressedDown[0] = 0; + PressedDown[1] = 0; + bPressedDown = false; +} + +defaultproperties +{ + bClickable=true + ColumnMinSize=8 +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ComboBox.uc b/Src/KFClassicHUD/Classes/KFGUI_ComboBox.uc new file mode 100644 index 0000000..5752943 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ComboBox.uc @@ -0,0 +1,64 @@ +Class KFGUI_ComboBox extends KFGUI_EditControl; + +var KFGUI_ComboSelector Selection; + +var float BorderSize; +var() array Values; +var() int SelectedIndex; +var() color SelectedTextColor,TextColor; +var() bool bButtonStretched; + +function UpdateSizes() +{ + // Update height. + if( bScaleByFontSize ) + YSize = (TextHeight + (BorderSize*2)) / InputPos[3]; +} + +function DrawMenu() +{ + Owner.CurrentStyle.RenderComboBox(Self); +} + +function HandleMouseClick( bool bRight ) +{ + PlayMenuSound(MN_Dropdown); + if( Selection==None ) + { + Selection = New(None)Class'KFGUI_ComboSelector'; + Selection.Owner = Owner; + Selection.Combo = Self; + Selection.InitMenu(); + } + Selection.XPosition = CompPos[0] / Owner.ScreenSize.X; + Selection.YPosition = (CompPos[1]+CompPos[3]) / Owner.ScreenSize.Y; + Selection.XSize = CompPos[2] / Owner.ScreenSize.X; + Selection.YSize = (TextHeight / Owner.ScreenSize.Y) * Values.Length + ((BorderSize*2) / Owner.ScreenSize.Y); + if( (Selection.YPosition+Selection.YSize)>1.f ) + Selection.YPosition-=((Selection.YPosition+Selection.YSize)-1.f); + Selection.GetInputFocus(); +} +final function string GetCurrent() +{ + if( SelectedIndex=0 ) + { + Combo.SelectedIndex = CurrentRow; + Combo.OnComboChanged(Combo); + } +} + +defaultproperties +{ + CurrentRow=-1 + OldRow=-1 + bFocusedPostDrawItem=true +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ComponentList.uc b/Src/KFClassicHUD/Classes/KFGUI_ComponentList.uc new file mode 100644 index 0000000..358178a --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ComponentList.uc @@ -0,0 +1,222 @@ +// List box with components as items. +Class KFGUI_ComponentList extends KFGUI_List; + +var int VisRange[2]; +var() int NumColumns; +var array ItemComponents; + +// REMEMBER to call InitMenu() on the newly created component after values are init!!! +final function KFGUI_Base AddListComponent( class CompClass, optional float XS=1.f, optional float YS=1.f ) +{ + return AddComponentAtIndex(ItemComponents.Length, CompClass, XS, YS); +} + +final function KFGUI_Base CreateComponent(class CompClass, optional float XS=1.f, optional float YS=1.f) +{ + local KFGUI_Base G; + + G = new(Self)CompClass; + if( G==None ) + return None; + + G.XPosition = (1.f - XS) * 0.5f; + G.YPosition = (1.f - YS) * 0.5f; + G.XSize = XS; + G.YSize = YS; + + return G; +} + +final function AddItem( KFGUI_Base Item ) +{ + AddItemAtIndex(ItemComponents.Length, Item); +} + +final function AddItemAtIndex( int i, KFGUI_Base Item ) +{ + ItemComponents.InsertItem(i, Item); +} + +final function KFGUI_Base AddComponentAtIndex( int i, class CompClass, optional float XS=1.f, optional float YS=1.f ) +{ + local KFGUI_Base G; + + G = CreateComponent(CompClass, XS, YS); + G.Owner = Owner; + G.ParentComponent = Self; + ItemComponents.InsertItem(i, G); + + return G; +} + +function EmptyList() +{ + ItemComponents.Length = 0; +} + +function InitMenu() +{ + Super.InitMenu(); + ListCount = 0; + NumColumns = Max(NumColumns,1); +} + +function DrawMenu() +{ + if( bDrawBackground ) + { + Canvas.SetDrawColor(250,250,250,255); + Canvas.SetPos(0.f,0.f); + Canvas.DrawTileStretched(Owner.CurrentStyle.BorderTextures[`BOX_INNERBORDER],CompPos[2],CompPos[3],0,0,128,128); + } +} + +function PreDraw() +{ + local int i; + local byte j; + + if( !bVisible ) + return; + + ComputeCoords(); + + // Update list size + i = ItemComponents.Length / NumColumns; + if( i!=NumColumns ) + { + ListCount = i; + UpdateListVis(); + } + + if( !ScrollBar.bDisabled && !ScrollBar.bHideScrollbar ) + { + // First draw scrollbar to allow it to resize itself. + for( j=0; j<4; ++j ) + ScrollBar.InputPos[j] = CompPos[j]; + if( OldXSize!=InputPos[2] ) + { + OldXSize = InputPos[2]; + } + ScrollBar.Canvas = Canvas; + ScrollBar.PreDraw(); + + // Then downscale our selves to give room for scrollbar. + CompPos[2] -= ScrollBar.CompPos[2]; + Canvas.SetOrigin(CompPos[0],CompPos[1]); + Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]); + DrawMenu(); + PreDrawListItems(); + CompPos[2] += ScrollBar.CompPos[2]; + } + else + { + Canvas.SetOrigin(CompPos[0],CompPos[1]); + Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]); + DrawMenu(); + PreDrawListItems(); + } +} + +function PreDrawListItems() +{ + local int i,XNum,r; + local float XS,YS; + + XNum = 0; + r = 0; + XS = CompPos[2] / NumColumns; + YS = CompPos[3] / ListItemsPerPage; + VisRange[0] = (ScrollBar.CurrentScroll*NumColumns); + VisRange[1] = ItemComponents.Length; + for( i=VisRange[0]; i 0 ) + { + for( i=VisRange[1] - 1; i>=VisRange[0] && i=0) ) + { + if ( (MaxWidth==0) || (Len(TextStr) 0) + { + Character = Asc(Left(Text, 1)); + Text = Mid(Text, 1); + + if (Character >= 0x20 && Character < 0x100) + { + SetInputText(Left(TextStr, CaretPos) $ Chr(Character) $ Right(TextStr, Len(TextStr) - CaretPos)); + CaretPos += 1; + } + } +} + +function bool ProcessControlKey(name Key, EInputEvent Event) +{ + if (Key == 'LeftControl' || Key == 'RightControl') + { + if (Event == IE_Released) + { + bCtrl = false; + } + else if (Event == IE_Pressed) + { + bCtrl = true; + } + + return true; + } + else if (bCtrl && Event == IE_Pressed && GetPlayer() != None) + { + if (Key == 'V') + { + // paste + AppendInputText(GetPlayer().PasteFromClipboard()); + return true; + } + else if (Key == 'C') + { + // copy + GetPlayer().CopyToClipboard(TextStr); + return true; + } + else if (Key == 'X') + { + // cut + if (TextStr != "") + { + GetPlayer().CopyToClipboard(TextStr); + SetInputText(""); + CaretPos = 0; + } + return true; + } + } + + return false; +} + +function bool NotifyInputKey(int ControllerId, name Key, EInputEvent Event, float AmountDepressed, bool bGamepad) +{ + local string Temp; + + if( bReadOnly ) + { + return false; + } + + if (ProcessControlKey(Key, Event)) + { + return false; + } + else if( Key == 'Escape' && Event == IE_Pressed ) + { + if( TextStr!="" ) + { + SetInputText(""); + CaretPos = 0; + return true; + } + else + { + if( ParentComponent != None ) + { + ParentComponent.UserPressedEsc(); + return true; + } + } + } + else if( Key=='Enter' && Event == IE_Released ) + { + if( TextStr!="" ) + { + Temp = TextStr; + OnTextFinished(self, Temp); + if( !bNoClearOnEnter ) + { + SetInputText(""); + CaretPos = 0; + } + } + + return true; + } + else if ( Key=='Home' ) + { + CaretPos = 0; + return true; + } + else if ( Key=='End' ) + { + CaretPos = Len(TextStr); + return true; + } + else if( Event == IE_Pressed || Event == IE_Repeat ) + { + if( Key=='Backspace' || Key=='Delete' ) + { + if( bAllSelected ) + { + SetInputText(""); + CaretPos = 0; + } + else if( CaretPos>0 ) + { + SetInputText(Left(TextStr,CaretPos-1) $ Right(TextStr, Len(TextStr) - CaretPos)); + CaretPos -= 1; + } + + return true; + } + else if ( Key=='Left' ) + { + CaretPos = Max(0, CaretPos - 1); + return true; + } + else if ( Key=='Right' ) + { + CaretPos = Min(Len(TextStr), CaretPos + 1); + return true; + } + } + + return true; +} + +function string ConvertIllegal(string InputStr) +{ + local int i, Max; + local string Retval; + local string C; + + i = 0; + Max = Len(InputStr); + while ( i < Max ) + { + C = Mid(InputStr,i,1); + if ( AllowedCharSet != "" && InStr(AllowedCharSet,C) < 0 ) + { + C = ""; + } + if ( bConvertSpaces && + ((C == " ") || (C =="?") || (C=="\\") )) + { + C = "_"; + } + Retval = Retval $ C; + i++; + } + + if (MaxWidth > 0) + return Left(Retval,MaxWidth); + + return Retval; +} + +function string GetText() +{ + return TextStr; +} + +function TextChanged() +{ + OnChange(Self); +} + +function DrawMenu() +{ + local string Storage,FinalDraw,TmpString; + local int MaskIndex,StorageLength; + local float XL,YL,BoxWidth,FontScale,CursorY,BorderSize; + local FontRenderInfo FRI; + + Super.DrawMenu(); + + if( bDrawBackground ) + { + Canvas.SetDrawColor(250,250,250,255); + Canvas.SetPos(0.f,0.f); + Canvas.DrawTileStretched(Owner.CurrentStyle.BorderTextures[`BOX_SMALL],CompPos[2],CompPos[3],0,0,Owner.CurrentStyle.BorderTextures[`BOX_SMALL].GetSurfaceWidth(),Owner.CurrentStyle.BorderTextures[`BOX_SMALL].GetSurfaceHeight()); + } + + BorderSize = Owner.CurrentStyle.ScreenScale(4.f); + + FRI.bClipText = true; + FRI.bEnableShadow = true; + + Storage = TextStr; + + if ( bMaskText && Len(Storage)>0 ) + { + StorageLength = Len(Storage); + + Storage = ""; + for(MaskIndex=1; MaskIndex <= StorageLength; MaskIndex++ ) + { + Storage $= "*"; + } + } + + Canvas.Font = Owner.CurrentStyle.PickFont(FontScale); + FontScale *= TextScale; + + BoxWidth=CompPos[2]*0.9875; + + if ( (Len(Storage) != LastLength) || (CaretPos!=LastCaret) ) + { + if (CaretPos<=FirstVis) + FirstVis = Max(0,CaretPos-1); + else + { + FinalDraw = Mid(Storage, FirstVis, CaretPos-FirstVis); + Canvas.TextSize(FinalDraw, XL, YL, FontScale, FontScale); + + while ( (XL>=BoxWidth) && (FirstVisMaxX ) + { + --i; + break; + } + X+=XL; + } + Canvas.DrawText(Left(S,i),,TScale,TScale,TextFontInfo); +} + +defaultproperties +{ + LableColor=(R=255,G=255,B=255,A=255) + FontScale=1 + LableWidth=0.5 + bScaleByFontSize=true + TextFontInfo=(bClipText=true,bEnableShadow=true) + + Begin Object Class=KFGUI_TextLable Name=MyBoxLableText + AlignX=0 + AlignY=1 + TextFontInfo=(bClipText=true,bEnableShadow=true) + End Object + TextLable=MyBoxLableText +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_FloatingWindow.uc b/Src/KFClassicHUD/Classes/KFGUI_FloatingWindow.uc new file mode 100644 index 0000000..a7e7535 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_FloatingWindow.uc @@ -0,0 +1,107 @@ +Class KFGUI_FloatingWindow extends KFGUI_Page + abstract; + +var() string WindowTitle; // Title of this window. +var float DragOffset[2], OpenAnimSpeed; +var KFGUI_FloatingWindowHeader HeaderComp; +var bool bDragWindow,bUseAnimation; + +var float WindowFadeInTime; +var transient float OpenStartTime,OpenEndTime; + +function InitMenu() +{ + Super.InitMenu(); + HeaderComp = new (Self) class'KFGUI_FloatingWindowHeader'; + AddComponent(HeaderComp); +} +function ShowMenu() +{ + Super.ShowMenu(); + + OpenStartTime = GetPlayer().WorldInfo.RealTimeSeconds; + OpenEndTime = GetPlayer().WorldInfo.RealTimeSeconds + OpenAnimSpeed; +} +function DrawMenu() +{ + local float TempSize; + + if( bUseAnimation ) + { + TempSize = `TimeSinceEx(GetPlayer(), OpenStartTime); + if ( WindowFadeInTime - TempSize > 0 && FrameOpacity != default.FrameOpacity ) + FrameOpacity = (1.f - ((WindowFadeInTime - TempSize) / WindowFadeInTime)) * default.FrameOpacity; + } + + Owner.CurrentStyle.RenderFramedWindow(Self); + + if( HeaderComp!=None ) + { + HeaderComp.CompPos[3] = Owner.CurrentStyle.DefaultHeight; + HeaderComp.YSize = HeaderComp.CompPos[3] / CompPos[3]; // Keep header height fit the window height. + } +} +function SetWindowDrag( bool bDrag ) +{ + bDragWindow = bDrag; + if( bDrag ) + { + DragOffset[0] = Owner.MousePosition.X-CompPos[0]; + DragOffset[1] = Owner.MousePosition.Y-CompPos[1]; + } +} +function bool CaptureMouse() +{ + local int i; + + if( bDragWindow && HeaderComp!=None ) // Always keep focus on window frame now! + { + MouseArea = HeaderComp; + return true; + } + + for( i=0; i 0 && FrameOpacity != default.FrameOpacity ) + FrameOpacity = (1.f - ((WindowFadeInTime - TempSize) / WindowFadeInTime)) * default.FrameOpacity; + } + + if( bDrawBackground ) + { + OnDrawFrame(Canvas, CompPos[2], CompPos[3]); + } +} + +delegate OnDrawFrame(Canvas C, float W, Float H) +{ + local float T,XL,YL,HeaderH; + local FontRenderInfo FRI; + + if( FrameTex == None ) + { + return; + } + + C.SetDrawColor(255,255,255,FrameOpacity); + if( bUseLegacyDrawTile ) + { + Owner.CurrentStyle.DrawTileStretched(FrameTex,0,0,W,H); + } + else + { + Canvas.SetPos(0.f, 0.f); + Canvas.DrawTileStretched(FrameTex,W,H,0,0,FrameTex.GetSurfaceWidth(),FrameTex.GetSurfaceHeight()); + } + + if( bDrawHeader && WindowTitle!="" ) + { + FRI.bClipText = true; + FRI.bEnableShadow = true; + + C.Font = Owner.CurrentStyle.MainFont; + T = Owner.CurrentStyle.ScreenScale(FontScale); + + C.SetDrawColor(250,250,250,FrameOpacity); + C.TextSize(WindowTitle, XL, YL, T, T); + + HeaderH = EdgeSize[1]-HeaderSize[1]; + if( bHeaderCenter ) + C.SetPos((W/2) - (XL/2),(HeaderH/2) - (YL/2)); + else C.SetPos(HeaderSize[0],(HeaderH/2) - (YL/2)); + + C.DrawText(WindowTitle,,T,T,FRI); + } +} + +function PreDraw() +{ + local int i; + local byte j; + local float Frac, CenterX, CenterY; + + if( !bVisible ) + return; + + if( bUseAnimation ) + { + Frac = Owner.CurrentStyle.TimeFraction(OpenStartTime, OpenEndTime, GetPlayer().WorldInfo.RealTimeSeconds); + XSize = Lerp(default.XSize*0.75, default.XSize, Frac); + YSize = Lerp(default.YSize*0.75, default.YSize, Frac); + + CenterX = (default.XPosition + default.XSize * 0.5) - ((default.XSize*0.75)/2); + CenterY = (default.YPosition + default.YSize * 0.5) - ((default.YSize*0.75)/2); + + XPosition = Lerp(CenterX, default.XPosition, Frac); + YPosition = Lerp(CenterY, default.YPosition, Frac); + } + + ComputeCoords(); + Canvas.SetDrawColor(255,255,255); + Canvas.SetOrigin(CompPos[0],CompPos[1]); + Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]); + DrawMenu(); + + for( i=0; i=ListCount ) + break; + if( bCheckMouse && FocusMouseItem==-1 ) + { + if( MouseYHit=0 ) + OnMouseRest(FocusMouseItem); +} + +Delegate OnMouseRest( int Item ); + +defaultproperties +{ + ListItemsPerPage=7 + ListCount=1 + BackgroundColor=(R=0,G=0,B=0,A=75) + bDrawBackground=false + bUseFocusSound=false + + Begin Object Class=KFGUI_ScrollBarV Name=ListScroller + XPosition=0.96 + YPosition=0 + XSize=0.04 + YSize=1.05 + ID="Scrollbar" + End Object + Components.Add(ListScroller) +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ListHorz.uc b/Src/KFClassicHUD/Classes/KFGUI_ListHorz.uc new file mode 100644 index 0000000..8bc56ac --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ListHorz.uc @@ -0,0 +1,225 @@ +Class KFGUI_ListHorz extends KFGUI_MultiComponent; + +var() bool bDrawBackground, bHideScrollbar, bUseFocusSound; +var() protected int ListCount; +var() int ListItemsPerPage; +var() float ButtonScale; +var() color BackgroundColor; +var KFGUI_ScrollBarH ScrollBar; + +var transient float OldYSize,ItemWidth,MouseXHit; +var transient int FocusMouseItem,LastFocusItem; + +var byte PressedDown[2]; +var bool bPressedDown; + +delegate OnDrawItem( Canvas C, int Index, float XOffset, float Height, float Width, bool bFocus ); + +// Requires bClickable=true to receive this event. +delegate OnClickedItem( int Index, bool bRight, int MouseX, int MouseY ); +delegate OnDblClickedItem( int Index, bool bRight, int MouseX, int MouseY ); + +function InitMenu() +{ + Super.InitMenu(); + ScrollBar = KFGUI_ScrollBarH(FindComponentID('Scrollbar')); + ScrollBar.bHideScrollbar = bHideScrollbar; + ScrollBar.ButtonScale = ButtonScale <= 0.f ? 1.f : ButtonScale; + UpdateListVis(); +} + +function DrawMenu() +{ + local int i,n; + local float X; + local bool bCheckMouse; + + if( bDrawBackground ) + { + //Canvas.DrawColor = BackgroundColor; + Canvas.SetDrawColor(250,250,250,255); + Canvas.SetPos(0.f,0.f); + Canvas.DrawTileStretched(Owner.CurrentStyle.BorderTextures[`BOX_INNERBORDER],CompPos[2],CompPos[3],0,0,128,128); + } + + // Mouse focused item check. + bCheckMouse = bClickable && bFocused; + FocusMouseItem = -1; + if( bCheckMouse ) + MouseXHit = Owner.MousePosition.X - CompPos[0]; + + n = ScrollBar.CurrentScroll; + ItemWidth = CompPos[2] / ListItemsPerPage; + X = 0.f; + for( i=0; i=ListCount ) + break; + if( bCheckMouse && FocusMouseItem==-1 ) + { + if( MouseXHit=0 ) + OnMouseRest(FocusMouseItem); +} + +Delegate OnMouseRest( int Item ); + +defaultproperties +{ + ListItemsPerPage=7 + ListCount=1 + BackgroundColor=(R=0,G=0,B=0,A=75) + bDrawBackground=false + bUseFocusSound=false + + Begin Object Class=KFGUI_ScrollBarH Name=ListScroller + XPosition=0 + YPosition=0.96 + XSize=1 + YSize=0.04 + ID="Scrollbar" + End Object + Components.Add(ListScroller) +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ListItem.uc b/Src/KFClassicHUD/Classes/KFGUI_ListItem.uc new file mode 100644 index 0000000..4a71bba --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ListItem.uc @@ -0,0 +1,44 @@ +Class KFGUI_ListItem extends Object + transient; + +var KFGUI_ListItem Next; +var array Columns,SortColumns; +var int Index,Value; + +var transient string Temp; // Cache sorting key. + +function SetValue( string S, int i, string SortStr ) +{ + ParseStringIntoArray(S,Columns,"\n",false); + if( SortStr=="" ) + SortColumns.Length = 0; + else ParseStringIntoArray(Caps(SortStr),SortColumns,"\n",false); + Value = i; +} + +// Return string to draw on HUD. +function string GetDisplayStr( int Column ) +{ + if( Column0 ) + { + if( Column Components; + +function InitMenu() +{ + local int i; + + for( i=0; i=0; i-- ) + { + if( Components[i].CaptureMouse() ) + { + MouseArea = Components[i]; + return true; + } + } + MouseArea = None; + return Super.CaptureMouse(); // check with frame itself. +} +function bool ReceievedControllerInput(int ControllerId, name Key, EInputEvent Event) +{ + local int i; + + for( i=Components.Length - 1; i>=0; i-- ) + { + if( Components[i].ReceievedControllerInput(ControllerId, Key, Event) ) + { + return true; + } + } + + return Super.ReceievedControllerInput(ControllerId, Key, Event); +} +function KFGUI_Base FindComponentID( name InID ) +{ + local int i; + local KFGUI_Base Result; + + if( ID==InID ) + Result = Self; + else + { + for( i=0; i Res ) +{ + local int i; + + if( ID==InID ) + Res[Res.Length] = Self; + for( i=0; i 0.0 && Width > 0 && Len(Caption) > 0) + { + W = CaptionWidth; + + if( W < 1.0 ) + { + W *= Width; + } + + if( W > Width ) + { + W = Width; + } + + // Draw the label + Owner.CurrentStyle.DrawTextJustified(CaptionAlign, Left, Top, Left + W, Top + Height, Caption, Sc, Sc); + Left += W; + Width -= W; + } + + if ( (bShowHigh || bShowValue) && ValueRightWidth > 0.0 && Width > 0.0) + { + W = ValueRightWidth; + + if( W < 1.0 ) + { + W *= Width; + } + + if( W > Width ) + { + W = Width; + } + + if( bShowValue && bShowHigh ) + { + S = int(Value)$"/"$int(High); + } + else if (bShowValue) + { + S = string(int(Value)); + } + else + { + S = string(int(High)); + } + + Owner.CurrentStyle.DrawTextJustified(ValueRightAlign, Left + Width - W, Top, Left + Width, Top + Height, S, Sc, Sc); + + Width -= W; + } + + if (Width > GraphicMargin) + { + Width -= GraphicMargin; + Left += GraphicMargin / 2; + } + + Canvas.SetDrawColor(255, 255, 255, 255); + if( Width > 0.0 && BarBack != None ) + { + Owner.CurrentStyle.DrawTileStretched(BarBack, Left, Top, Width, Height); + } + + if( Width > 0.0 && BarTop != None && Value > Low ) + { + Canvas.DrawColor = BarColor; + Owner.CurrentStyle.DrawTileStretched(BarTop, Left + BorderSize, Top + BorderSize, (Width - (BorderSize * 2)) * (Value/High), Height - (BorderSize * 2)); + } +} + +function SetValue(float val) +{ + Value=val; +} + +function float GetValue() +{ + return Value; +} + +defaultproperties +{ + BarColor=(R=255,G=255,B=255,A=255) + Low=0.f + High=100.f + Value=0.f + bShowLow=false + bShowHigh=false + bShowValue=true + CaptionWidth=0.45 + ValueRightWidth=0.2 + ValueRightAlign=0 + NumDecimals=0 +} diff --git a/Src/KFClassicHUD/Classes/KFGUI_RightClickMenu.uc b/Src/KFClassicHUD/Classes/KFGUI_RightClickMenu.uc new file mode 100644 index 0000000..9ff777f --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_RightClickMenu.uc @@ -0,0 +1,163 @@ +Class KFGUI_RightClickMenu extends KFGUI_Clickable; + +struct FRowItem +{ + var string Text,ToolTip; + var bool bSplitter,bDisabled; +}; +var array ItemRows; +var int CurrentRow,OldRow; +var int EdgeSize; +var int OldSizeX; +var transient bool bDrawToolTip; +var Color BoxColor,OutlineColor; + +function OpenMenu( KFGUI_Base Menu ) +{ + Owner = Menu.Owner; + InitMenu(); + PlayMenuSound(MN_Dropdown); + GetInputFocus(); + OldSizeX = 0; +} +final function ComputeSize() +{ + local float XS,YS,XL,YL,Scalar; + local int i; + local string S; + + if( OldSizeX == Owner.ScreenSize.X ) + return; + + if( ItemRows.Length==0 ) + { + YS = 0; + XS = 50; + } + else + { + Canvas.Font = Owner.CurrentStyle.PickFont(Scalar); + for( i=0; i1.f ) + YPosition = (float(Owner.MousePosition.X) / Owner.ScreenSize.X) - XSize; // Move to left side of mouse pointer. + if( (YPosition+YSize)>1.f ) + YPosition-=((YPosition+YSize)-1.f); // Move up until fit on screen. +} +final function AddRow( string Text, bool bDisable, optional string AltToolTip ) +{ + local int i; + + i = ItemRows.Length; + ItemRows.Length = i+1; + if( Text=="-" ) + ItemRows[i].bSplitter = true; + else + { + ItemRows[i].Text = Text; + ItemRows[i].ToolTip = AltToolTip; + ItemRows[i].bDisabled = bDisable; + } +} +function PreDraw() +{ + ComputeSize(); + Super.PreDraw(); +} +function DrawMenu() +{ + Owner.CurrentStyle.RenderRightClickMenu(Self); + + if( bDrawToolTip ) + { + if( OldRow != CurrentRow ) + bDrawToolTip = false; + DrawToolTip(); + } +} +function DrawToolTip() +{ + local float X,Y,XL,YL,BoxW,BoxH,TextX,TextY,Scalar,CursorSize; + local string S; + + Canvas.Reset(); + Canvas.SetClip(float(Owner.ScreenSize.X), float(Owner.ScreenSize.Y)); + + S = ItemRows[CurrentRow].ToolTip; + Canvas.Font = Owner.CurrentStyle.PickFont(Scalar); + Canvas.TextSize(S,XL,YL,Scalar,Scalar); + + CursorSize = Owner.CurrentStyle.ScreenScale(Owner.CursorSize); + X = Owner.MousePosition.X+CursorSize; + Y = Owner.MousePosition.Y+CursorSize; + BoxW = XL * 1.05f; + BoxH = YL * 1.25f; + + while( (X + BoxW) > Canvas.ClipX ) + { + X -= 0.01; + } + + Owner.CurrentStyle.DrawOutlinedBox(X, Y, BoxW, BoxH, EdgeSize, MakeColor(5,5,5,255), MakeColor(115,115,115,255)); + + TextX = X + (BoxW/2) - (XL/2) - (EdgeSize/2); + TextY = Y + (BoxH/2) - (YL/2) - (EdgeSize/2); + + Canvas.DrawColor = class'HUD'.default.WhiteColor; + Canvas.SetPos(TextX, TextY); + Canvas.DrawText(S,,Scalar,Scalar); +} +function HandleMouseClick( bool bRight ) +{ + if( CurrentRow>=0 && (ItemRows[CurrentRow].bSplitter || ItemRows[CurrentRow].bDisabled) ) + return; + OnSelectedItem(CurrentRow); + PlayMenuSound(MN_ClickButton); + DropInputFocus(); +} +function LostInputFocus() +{ + OnBecameHidden(Self); + OldRow = -1; + CurrentRow = -1; +} +function NotifyMousePaused() +{ + if(CurrentRow != -1 && ItemRows[CurrentRow].ToolTip != "") + bDrawToolTip = true; +} + +Delegate OnSelectedItem( int Index ); +Delegate OnBecameHidden( KFGUI_RightClickMenu M ); + +defaultproperties +{ + CurrentRow=-1 + OldRow=-1 + bFocusedPostDrawItem=true + bHoverSound=false + EdgeSize=2 + BoxColor=(R=5,G=5,B=5,A=200) + OutlineColor=(R=115,G=115,B=115,A=255) +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ScrollBarBase.uc b/Src/KFClassicHUD/Classes/KFGUI_ScrollBarBase.uc new file mode 100644 index 0000000..c3d26a1 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ScrollBarBase.uc @@ -0,0 +1,123 @@ +Class KFGUI_ScrollBarBase extends KFGUI_Clickable + abstract; + +var() int MinRange,MaxRange,ScrollStride,PageStep; +var() float ButtonScale; // Button width (scaled by default font height). +var int CurrentScroll; + +// In-runtime values. +var transient float CalcButtonScale; +var transient int SliderScale,ButtonOffset,GrabbedOffset; +var transient bool bGrabbedScroller; + +var bool bVertical, bHideScrollbar; + +final function UpdateScrollSize( int Current, int MxRange, int Stride, int StepStride, optional int MnRange ) +{ + MaxRange = MxRange; + MinRange = MnRange; + ScrollStride = Stride; + PageStep = StepStride; + SetValue(Current); +} +final function AddValue( int V ) +{ + SetValue(CurrentScroll+V); +} +final function SetValue( int V ) +{ + CurrentScroll = Clamp((V / ScrollStride) * ScrollStride,MinRange,MaxRange); + OnScrollChange(Self,CurrentScroll); +} +final function int GetValue() +{ + return CurrentScroll; +} +Delegate OnScrollChange( KFGUI_ScrollBarBase Sender, int Value ); + +// Get UI width. +function float GetWidth() +{ + CalcButtonScale = ButtonScale*Owner.CurrentStyle.DefaultHeight; + return CalcButtonScale / (bVertical ? InputPos[2] : InputPos[3]); +} +function PreDraw() +{ + // Auto scale to match width to screen size. + if( bVertical ) + XSize = GetWidth(); + else YSize = GetWidth(); + Super.PreDraw(); +} +function DrawMenu() +{ + if( !bHideScrollbar ) + { + Owner.CurrentStyle.RenderScrollBar(Self); + } +} +function MouseClick( bool bRight ) +{ + if( bRight || bDisabled ) + return; + bPressedDown = true; + PlayMenuSound(MN_ClickButton); + + if( bVertical ) + { + if( Owner.MousePosition.Y>=(CompPos[1]+ButtonOffset) && Owner.MousePosition.Y<=(CompPos[1]+ButtonOffset+SliderScale) ) // Grabbed scrollbar! + { + GrabbedOffset = Owner.MousePosition.Y - (CompPos[1]+ButtonOffset); + bGrabbedScroller = true; + GetInputFocus(); + } + else if( Owner.MousePosition.Y<(CompPos[1]+ButtonOffset) ) // Page up. + AddValue(-PageStep); + else AddValue(PageStep); + } + else + { + if( Owner.MousePosition.X>=(CompPos[0]+ButtonOffset) && Owner.MousePosition.X<=(CompPos[0]+ButtonOffset+SliderScale) ) // Grabbed scrollbar! + { + GrabbedOffset = Owner.MousePosition.X - (CompPos[0]+ButtonOffset); + bGrabbedScroller = true; + GetInputFocus(); + } + else if( Owner.MousePosition.X<(CompPos[0]+ButtonOffset) ) // Page left. + AddValue(-PageStep); + else AddValue(PageStep); + } +} +function MouseRelease( bool bRight ) +{ + if( !bRight ) + DropInputFocus(); +} + +function LostInputFocus() +{ + bGrabbedScroller = false; + bPressedDown = false; +} + +function ScrollMouseWheel( bool bUp ) +{ + if( bDisabled ) + return; + if( bUp ) + AddValue(-ScrollStride); + else AddValue(ScrollStride); +} + +function SetVisibility(bool Visible) +{ + bHideScrollbar = Visible; +} + +defaultproperties +{ + MaxRange=100 + ScrollStride=1 + PageStep=10 + ButtonScale=1 +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ScrollBarH.uc b/Src/KFClassicHUD/Classes/KFGUI_ScrollBarH.uc new file mode 100644 index 0000000..d7a9e19 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ScrollBarH.uc @@ -0,0 +1,6 @@ +Class KFGUI_ScrollBarH extends KFGUI_ScrollBarBase; + +defaultproperties +{ + bVertical=false +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_ScrollBarV.uc b/Src/KFClassicHUD/Classes/KFGUI_ScrollBarV.uc new file mode 100644 index 0000000..e840c9c --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_ScrollBarV.uc @@ -0,0 +1,6 @@ +Class KFGUI_ScrollBarV extends KFGUI_ScrollBarBase; + +defaultproperties +{ + bVertical=true +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_Slider.uc b/Src/KFClassicHUD/Classes/KFGUI_Slider.uc new file mode 100644 index 0000000..bbb8aab --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_Slider.uc @@ -0,0 +1,52 @@ +class KFGUI_Slider extends KFGUI_MultiComponent; + +var KFGUI_ScrollBarH ScrollBar; + +var int MinValue,MaxValue; +var transient int CurrentValue; + +delegate OnValueChanged(KFGUI_Slider Sender, int Value); + +function InitMenu() +{ + Super.InitMenu(); + ScrollBar = KFGUI_ScrollBarH(FindComponentID('Scrollbar')); + ScrollBar.OnScrollChange = ValueChanged; +} + +function int GetValue() +{ + return CurrentValue; +} + +function SetValue(int Value) +{ + CurrentValue = Clamp(Value, MinValue, MaxValue); + OnValueChanged(self, CurrentValue); +} + +function ValueChanged(KFGUI_ScrollBarBase Sender, int Value) +{ + SetValue(Value); +} + +function UpdateListVis() +{ + ScrollBar.UpdateScrollSize(CurrentValue,MaxValue,1,1,MinValue); +} + +function ScrollMouseWheel( bool bUp ) +{ + if( !ScrollBar.bDisabled ) + ScrollBar.ScrollMouseWheel(bUp); +} + +defaultproperties +{ + Begin Object Class=KFGUI_ScrollBarH Name=SliderScroll + XSize=1 + YSize=0.5 + ID="Scrollbar" + End Object + Components.Add(SliderScroll) +} diff --git a/Src/KFClassicHUD/Classes/KFGUI_SwitchMenuBar.uc b/Src/KFClassicHUD/Classes/KFGUI_SwitchMenuBar.uc new file mode 100644 index 0000000..66587b0 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_SwitchMenuBar.uc @@ -0,0 +1,165 @@ +// Same as SwitchComponent, but with buttons. +Class KFGUI_SwitchMenuBar extends KFGUI_MultiComponent; + +var array SubPages; +var() byte ButtonPosition; // 0 = top, 1 = bottom, 2 = left, 3 = right +var() float BorderWidth,ButtonAxisSize; // Width for buttons. +var() float PagePadding; // Padding for pages + +var int NumButtons,CurrentPageNum,PageComponentIndex; +var array PageButtons; + +function ShowMenu() +{ + GrabKeyFocus(); + Super.ShowMenu(); +} + +function CloseMenu() +{ + ReleaseKeyFocus(); + Super.CloseMenu(); +} + +// Remember to call InitMenu() on the newly created page after. +final function KFGUI_Base AddPage( class PageClass, string Caption, string Hint, optional out KFGUI_Button Button ) +{ + local KFGUI_Base P; + local KFGUI_Button B; + + // Add page. + P = new (Self) PageClass; + P.Owner = Owner; + P.ParentComponent = Self; + SubPages.AddItem(P); + + // Add page switch button. + B = new (Self) class'KFGUI_Button'; + B.ButtonText = Caption; + B.ToolTip = Hint; + B.OnClickLeft = PageSwitched; + B.OnClickRight = PageSwitched; + B.IDValue = NumButtons; + + if( ButtonPosition<2 ) + { + B.XPosition = NumButtons*ButtonAxisSize; + B.XSize = ButtonAxisSize*0.99; + + if( ButtonPosition==0 ) + B.YPosition = 0.f; + else B.YPosition = YSize-BorderWidth*0.99; + B.YSize = BorderWidth*0.99; + + if( NumButtons>0 ) + PageButtons[PageButtons.Length-1].ExtravDir = 1; + } + else + { + if( ButtonPosition==2 ) + B.XPosition = 0.f; + else B.XPosition = XSize-BorderWidth*0.99; + B.XSize = BorderWidth*0.99; + + B.YPosition = NumButtons*ButtonAxisSize; + B.YSize = ButtonAxisSize*0.99; + if( NumButtons>0 ) + PageButtons[PageButtons.Length-1].ExtravDir = 2; + } + + ++NumButtons; + PageButtons.AddItem(B); + AddComponent(B); + Button = B; + return P; +} + +function PageSwitched( KFGUI_Button Sender ) +{ + SelectPage(Sender.IDValue); +} + +final function SelectPage( int Index ) +{ + PlayMenuSound(MN_LostFocus); + + if( CurrentPageNum>=0 ) + { + PageButtons[CurrentPageNum].bIsHighlighted = false; + SubPages[CurrentPageNum].CloseMenu(); + Components.Remove(PageComponentIndex,1); + PageComponentIndex = -1; + } + CurrentPageNum = (Index>=0 && Index=0 ) + { + PageButtons[CurrentPageNum].bIsHighlighted = true; + SubPages[CurrentPageNum].ShowMenu(); + PageComponentIndex = Components.Length; + Components.AddItem(SubPages[CurrentPageNum]); + } +} + +function PreDraw() +{ + local int i; + local byte j; + + if( !bVisible ) + return; + + if( CurrentPageNum==-1 && NumButtons>0 ) + SelectPage(0); + ComputeCoords(); + Canvas.SetOrigin(CompPos[0],CompPos[1]); + Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]); + DrawMenu(); + for( i=0; i Text; + var float Y; +}; +var KFGUI_ScrollBarV ScrollBar; + +var() string LineSplitter; +var() protected string Text; +var() Color TextColor; +var() Canvas.FontRenderInfo TextFontInfo; +var() float FontScale,MessageDisplayTime,MessageFadeInTime,MessageFadeOutTime; +var() bool bNoReset,bFadeInOut,bUseOutlineText; +var() int MaxHistory, OutlineSize; +var protected transient array Lines,OrgLines; +var transient float MaxHeight,ScrollWidth,OldSize[2],InitFontScale,TextHeight,FadeStartTime; +var transient Font InitFont; +var transient bool bShowScrollbar,bTextParsed; + +function SetText( string S ) +{ + if( Text==S ) + return; + Text = S; + OldSize[0] = -1; // Force to refresh. + Lines.Length = 0; + OrgLines.Length = 0; + bTextParsed = false; +} +function AddText( string S, optional bool bIgnoreSpam ) +{ + Text $= S; + OldSize[0] = -1; + Lines.Length = 0; + OrgLines.Length = 0; + bTextParsed = false; +} +final function string GetText() +{ + return Text; +} + +final function ParseTextLines() +{ + local array SA; + local int i,j,z; + local string S; + local color C; + local ETextFieldStyles TextType; + + ParseStringIntoArray(Text,SA,LineSplitter,false); + Lines.Length = SA.Length; + C.A = 0; + TextType = TEXT_FIELD_NONE; + for( i=0; i0 ) + { + Lines[i].Text.Length = z+1; + Lines[i].Text[z].S = Left(S,j); + Lines[i].Text[z].C = C; + Lines[i].Text[z].TextType = TextType; + ++z; + } + else if( j==-1 ) + break; + + S = Mid(S,j+2); + if( Left(S,4)=="DEF}" ) + { + C.A = 0; + S = Mid(S,4); + TextType = TEXT_FIELD_NONE; + } + else if( Left(S,4)=="HSV}" ) + { + C.A = 0; + S = Mid(S,4); + TextType = TEXT_FIELD_HSV; + } + else if( Left(S,6)=="FLASH}" ) + { + C.A = 0; + S = Mid(S,6); + TextType = TEXT_FIELD_FLASH; + } + else if( Left(S,7)=="CFLASH=" ) + { + C.A = 0; + S = Mid(S,7); + TextType = TEXT_FIELD_FLASH; + + C.R = GrabHexValue(Mid(S,0,2)); + C.G = GrabHexValue(Mid(S,2,2)); + C.B = GrabHexValue(Mid(S,4,2)); + S = Mid(S,7); + C.A = 255; + } + else + { + C.R = GrabHexValue(Mid(S,0,2)); + C.G = GrabHexValue(Mid(S,2,2)); + C.B = GrabHexValue(Mid(S,4,2)); + S = Mid(S,7); + C.A = 255; + TextType = TEXT_FIELD_NONE; + } + } + Lines[i].Text.Length = z+1; + Lines[i].Text[z].S = S; + Lines[i].Text[z].C = C; + Lines[i].Text[z].TextType = TextType; + } + OrgLines = Lines; // Create a backup. +} +final function byte GrabHexValue( string S ) +{ + local byte n; + + n = (HexToInt(Asc(Left(S,1)))<<4) | HexToInt(Asc(Right(S,1))); + S = Mid(S,2); + return n; +} +final function byte HexToInt( byte n ) +{ + if( n>=48 && n<=57 ) // '0' - '9' + return n-48; + if( n>=65 && n<=70 ) // 'A' - 'F' + return n-55; // 'A' - 10 + if( n>=97 && n<=102 ) // 'a' - 'f' + return n-87; // 'a' - 10 + return 0; +} + +function InitSize() +{ + local byte i; + local float XS; + local int MaxScrollRange; + + if( Canvas == None ) + return; + + OldSize[0] = CompPos[2]; + OldSize[1] = CompPos[3]; + if( !bTextParsed ) + { + ParseTextLines(); + bTextParsed = true; + } + else Lines = OrgLines; + + InitFont = Owner.CurrentStyle.PickFont(InitFontScale); + InitFontScale *= FontScale; + + // Compute Y-offsets of each line. + Canvas.Font = InitFont; + Canvas.TextSize("ABC",XS,TextHeight,InitFontScale,InitFontScale); + + ParseLines(CompPos[2] / InitFontScale); + MaxHeight = (Lines.Length * TextHeight); + bShowScrollbar = (MaxHeight>=CompPos[3]); + bClickable = bShowScrollbar; + bCanFocus = bShowScrollbar; + + if( bShowScrollbar ) + { + if( ScrollBar==None ) + { + ScrollBar = new(Self) class'KFGUI_ScrollBarV'; + ScrollBar.SetPosition(0.9,0.0,0.1,1.0); + ScrollBar.Owner = Owner; + ScrollBar.ParentComponent = Self; + ScrollBar.InitMenu(); + ScrollBar.SetVisibility(bVisible); + } + + // Compute scrollbar size and X-position. + for( i=0; i<4; ++i ) + ScrollBar.InputPos[i] = CompPos[i]; + ScrollWidth = ScrollBar.GetWidth(); + ScrollBar.XPosition = 1.f - ScrollWidth; + ScrollWidth *= CompPos[2]; + + ScrollBar.ComputeCoords(); + + // Recompute line sizes because we now have a scrollbar. + Lines = OrgLines; + ParseLines((CompPos[2]-ScrollWidth) / InitFontScale); + + if( Components.Find(ScrollBar)==-1 ) + Components.AddItem(ScrollBar); + MaxHeight = (Lines.Length * TextHeight); + MaxScrollRange = Max(((MaxHeight-CompPos[3])/TextHeight),1); + ScrollBar.UpdateScrollSize(bNoReset ? MaxScrollRange : 0,MaxScrollRange,1,1); + } + else if( ScrollBar!=None ) + Components.RemoveItem(ScrollBar); +} + +// Parse textlines to see if they're too long. +final function ParseLines( float ClipX ) +{ + local float X,XS,YS; + local int i,j,z,n; + + for( i=0; iClipX ) + { + z = FindSplitPoint(Lines[i].Text[j].S,X,ClipX); + + // Add new line. + Lines.Insert(i+1,1); + + // Append the remaining lines there. + for( n=j; nClipX ) // Split here if possible. + { + if( PrevWord==0 ) + return (bStartedZero ? i : 0); // No wrap. + return PrevWord; + } + ++i; + } + return l; +} +final function string StripWhiteSpaces( string S ) +{ + if( Left(S,1)==" " ) + S = Mid(S,1); + return S; +} + +function byte GetCursorStyle() +{ + return `PEN_WHITE; +} + +function DrawMenu() +{ + local int i,j,Index; + local float Y; + + if( Text=="" || !bVisible ) + return; + + // Need to figure out best fitting font. + if( OldSize[0]!=CompPos[2] || OldSize[1]!=CompPos[3] ) + InitSize(); + + if( MaxHistory != 0 ) + { + if( Lines.Length >= MaxHistory ) + { + Index = InStr(Text, LineSplitter); + if( Index == INDEX_NONE ) + Lines.Remove(0, 1); + else SetText(Mid(Text, Index+Len(LineSplitter))); + } + } + + Canvas.Font = InitFont; + + if( bShowScrollbar ) + { + Canvas.SetClip(CompPos[0]+(CompPos[2]-ScrollWidth),CompPos[1]+CompPos[3]); + i = ScrollBar.GetValue(); + } + else i = 0; + + if( i=CompPos[3] ) + break; + + for( j=0; j MessageDisplayTime ) + { + return; + } + + if ( TempSize < MessageFadeInTime ) + { + FadeAlpha = int((TempSize / MessageFadeInTime) * 255.0); + } + else if ( TempSize > MessageDisplayTime - MessageFadeOutTime ) + { + FadeAlpha = int((1.0 - ((TempSize - (MessageDisplayTime - MessageFadeOutTime)) / MessageFadeOutTime)) * 255.0); + } + else + { + FadeAlpha = 255; + } + + Canvas.DrawColor.A = FadeAlpha; + } + + if( bUseOutlineText ) + { + Owner.CurrentStyle.DrawTextShadow(S,X,Y,OutlineSize,InitFontScale); + } + else + { + Canvas.SetPos(X,Y); + Canvas.DrawText(S,,InitFontScale,InitFontScale,TextFontInfo); + } +} + +function Color GetColorFromStyle(Color MainColor, ETextFieldStyles TextStyle) +{ + local float ColorHUE,Value; + local HSVColour HSV; + + if( TextStyle == TEXT_FIELD_HSV ) + { + ColorHUE = Abs(Sin(GetPlayer().WorldInfo.TimeSeconds * 0.9) * 335); + + HSV.H = ColorHUE; + HSV.S = 1.f; + HSV.V = 1.f; + HSV.A = MainColor.A / 255; + + return class'KFColorHelper'.static.LinearColorToColor(class'KFColorHelper'.static.HSVToRGB(HSV)); + } + else if( TextStyle == TEXT_FIELD_FLASH ) + { + Value = Abs(Sin(GetPlayer().WorldInfo.TimeSeconds * 0.9) * 1); + HSV = class'KFColorHelper'.static.RGBToHSV(ColorToLinearColor(MainColor)); + HSV.V = Value; + + return class'KFColorHelper'.static.LinearColorToColor(class'KFColorHelper'.static.HSVToRGB(HSV)); + } + + return MainColor; +} + +function bool CaptureMouse() +{ + return (bShowScrollbar ? Super.CaptureMouse() : false); // Nope. +} + +function ScrollMouseWheel( bool bUp ) +{ + if( bShowScrollbar ) + ScrollBar.ScrollMouseWheel(bUp); +} + +function SetVisibility(bool Visible) +{ + Super.SetVisibility(Visible); + + if( ScrollBar != None ) + { + ScrollBar.SetVisibility(Visible); + } +} + +defaultproperties +{ + bNoReset=false + LineSplitter="|" + FontScale=1 + MaxHistory=0 + OutlineSize=1 + Text="TextField" + TextColor=(R=255,G=255,B=255,A=255) + TextFontInfo=(bClipText=true,bEnableShadow=true) + bCanFocus=false + bClickable=false + bUseOutlineText=false +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_TextLable.uc b/Src/KFClassicHUD/Classes/KFGUI_TextLable.uc new file mode 100644 index 0000000..cce0948 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_TextLable.uc @@ -0,0 +1,120 @@ +Class KFGUI_TextLable extends KFGUI_Base; + +var() protected string Text; +var() color TextColor; +var() Canvas.FontRenderInfo TextFontInfo; +var() byte AlignX,AlignY; // Alignment, 0=Left/Up, 1=Center, 2=Right/Down +var() float FontScale; +var() bool bUseOutline; +var() int OutlineSize; + +var transient Font InitFont; +var transient float OldSize[2],InitOffset[2],InitFontScale; + +function InitSize() +{ + local float XL,YL,TS; + + OldSize[0] = CompPos[2]; + OldSize[1] = CompPos[3]; + + TS = Owner.CurrentStyle.GetFontScaler(); + TS *= FontScale; + + while( true ) + { + Canvas.Font = Owner.CurrentStyle.MainFont; + if( TextFontInfo.bClipText ) + Canvas.TextSize(Text,XL,YL,TS,TS); + else + { + Canvas.SetPos(0,0); + if( TS==1 ) + Canvas.StrLen(Text,XL,YL); + else + { + Canvas.SetClip(CompPos[2]/TS,CompPos[3]); // Hacky, since StrLen has no TextSize support. + Canvas.StrLen(Text,XL,YL); + XL*=TS; + YL*=TS; + } + } + if( (XL<(CompPos[2]*0.99) && YL<(CompPos[3]*0.99)) ) + break; + + TS -= 0.001; + } + Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]); + InitFont = Canvas.Font; + InitFontScale = TS; + + switch( AlignX ) + { + case 0: + InitOffset[0] = 0; + break; + case 1: + InitOffset[0] = FMax((CompPos[2]-XL)*0.5,0.f); + break; + default: + InitOffset[0] = CompPos[2]-(XL+1); + } + switch( AlignY ) + { + case 0: + InitOffset[1] = 0; + break; + case 1: + InitOffset[1] = FMax((CompPos[3]-YL)*0.5,0.f); + break; + default: + InitOffset[1] = CompPos[3]-YL; + } +} +function SetText( string S ) +{ + if( Text==S ) + return; + Text = S; + OldSize[0] = -1; // Force to refresh. +} +final function string GetText() +{ + return Text; +} + +function DrawMenu() +{ + if( Text=="" ) + return; + + // Need to figure out best fitting font. + if( OldSize[0]!=CompPos[2] || OldSize[1]!=CompPos[3] ) + InitSize(); + + Canvas.Font = InitFont; + Canvas.DrawColor = TextColor; + if( bUseOutline ) + { + Owner.CurrentStyle.DrawTextShadow(Text,InitOffset[0],InitOffset[1],OutlineSize,InitFontScale); + } + else + { + Canvas.SetPos(InitOffset[0],InitOffset[1]); + Canvas.DrawText(Text,,InitFontScale,InitFontScale,TextFontInfo); + } +} +function bool CaptureMouse() +{ + return false; +} + +defaultproperties +{ + Text="Label" + TextColor=(R=255,G=255,B=255,A=255) + TextFontInfo=(bClipText=false,bEnableShadow=true) + FontScale=1.f + OutlineSize=1 + bCanFocus=false +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_TextScroll.uc b/Src/KFClassicHUD/Classes/KFGUI_TextScroll.uc new file mode 100644 index 0000000..26735a2 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_TextScroll.uc @@ -0,0 +1,185 @@ +Class KFGUI_TextScroll extends KFGUI_TextField; + +var float ScrollSpeed; + +var transient float CharStartTime; +var transient bool bScrollCompleted, bTextDirty; +var transient array RowsCompleted; +var transient int MaxIndex, RowsDropped; + +function SetText( string S ) +{ + Super.SetText(S); + + MaxIndex = 0; + RowsCompleted.Length = 0; + RowsDropped = 0; + + bScrollCompleted = false; + bTextDirty = true; + CharStartTime = GetPlayer().WorldInfo.TimeSeconds; +} + +function DrawMenu() +{ + local int i,j,k,SLen,CurrentIndex; + local float Y, DTime, XL, YL, MainY, MainX, CharTime; + local string MainString; + local Color MainTextColor; + local Texture CurrentCursor; + local ETextFieldStyles TextStyle; + + if( bScrollCompleted ) + { + Super.DrawMenu(); + return; + } + + if( Text=="" ) + return; + + // Need to figure out best fitting font. + if( OldSize[0]!=CompPos[2] || OldSize[1]!=CompPos[3] ) + InitSize(); + + Canvas.Font = InitFont; + + if( bShowScrollbar ) + { + Canvas.SetClip(CompPos[0]+(CompPos[2]-ScrollWidth),CompPos[1]+CompPos[3]); + i = ScrollBar.GetValue(); + } + else i = 0; + + if( ScrollBar != None ) + { + if( bTextDirty ) + { + ScrollBar.bDisabled = true; + RowsCompleted.Length = Lines.Length; + bTextDirty = false; + } + + if( RowsCompleted[Lines.Length-1] ) + { + ScrollBar.AddValue(1); + ScrollBar.bDisabled = false; + bScrollCompleted = true; + + //Temp fix! The last line in the string seems to be skipped + AddText(LineSplitter); + + return; + } + else if( MaxIndex != 0 && RowsCompleted[MaxIndex] ) + { + MaxIndex = 0; + ScrollBar.AddValue(1); + + RowsDropped++; + + i = ScrollBar.GetValue(); + } + } + + if( RowsDropped > 0 ) + { + for( i=0; i<=RowsDropped; ++i ) + { + for( j=0; j=CompPos[3] ) + { + MaxIndex = i-1; + break; + } + + if( Lines[i].Text.Length!=0 ) + { + for( j=0; j DTime ) + { + if( CurrentIndex == k ) + { + Canvas.SetDrawColor(255,255,255,255); + Canvas.SetPos(MainX+XL,MainY); + Canvas.DrawTile(CurrentCursor, YL/2, YL, 0, 0, CurrentCursor.GetSurfaceWidth(), CurrentCursor.GetSurfaceHeight()); + } + + continue; + } + + Canvas.DrawColor = GetColorFromStyle(MainTextColor, TextStyle); + Canvas.SetPos(MainX+XL,MainY); + Canvas.DrawText(Mid(MainString, k, 1),,InitFontScale,InitFontScale,TextFontInfo); + + CurrentIndex = k+1; + + if( k >= SLen ) + { + RowsCompleted[i] = true; + } + } + } + } + } + } +} + +function bool CaptureMouse() +{ + return (!bScrollCompleted && Super(KFGUI_MultiComponent).CaptureMouse()) || Super.CaptureMouse(); +} + +function MouseClick( bool bRight ) +{ + if( bScrollCompleted ) + return; + + if( ScrollBar != None ) + ScrollBar.bDisabled = false; + + bScrollCompleted = true; + + //Temp fix! The last line in the string seems to be skipped + AddText(LineSplitter); +} + +defaultproperties +{ + ScrollSpeed=0.01 +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFGUI_Tooltip.uc b/Src/KFClassicHUD/Classes/KFGUI_Tooltip.uc new file mode 100644 index 0000000..178f9f9 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFGUI_Tooltip.uc @@ -0,0 +1,42 @@ +Class KFGUI_Tooltip extends KFGUI_Base; + +var() array Lines; +var() Canvas.FontRenderInfo TextFontInfo; +var byte CurrentAlpha; + +function InputMouseMoved() +{ + DropInputFocus(); +} +function MouseClick( bool bRight ) +{ + DropInputFocus(); +} +function MouseRelease( bool bRight ) +{ + DropInputFocus(); +} +function ShowMenu() +{ + CurrentAlpha = 1; +} + +final function SetText( string S ) +{ + ParseStringIntoArray(S,Lines,"",false); +} + +function PreDraw() +{ + if( !bVisible ) + return; + + Owner.CurrentStyle.RenderToolTip(Self); +} + +defaultproperties +{ + TextFontInfo=(bClipText=true,bEnableShadow=true) + bCanFocus=false + bFocusedPostDrawItem=true +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Classes/KFScoreBoard.uc b/Src/KFClassicHUD/Classes/KFScoreBoard.uc new file mode 100644 index 0000000..2950b89 --- /dev/null +++ b/Src/KFClassicHUD/Classes/KFScoreBoard.uc @@ -0,0 +1,491 @@ +class KFScoreBoard extends KFGUI_Page; + +var transient float PerkXPos, PlayerXPos, StateXPos, TimeXPos, HealXPos, KillsXPos, AssistXPos, CashXPos, DeathXPos, PingXPos; +var transient float NextScoreboardRefresh; + +var int PlayerIndex; +var KFGUI_List PlayersList; +var Texture2D DefaultAvatar; + +var KFGameReplicationInfo KFGRI; +var array KFPRIArray; + +var KFPlayerController OwnerPC; + +var Color PingColor; +var float PingBars,IdealPing,MaxPing; + +function InitMenu() +{ + Super.InitMenu(); + PlayersList = KFGUI_List(FindComponentID('PlayerList')); + OwnerPC = KFPlayerController(GetPlayer()); +} + +static function CheckAvatar(KFPlayerReplicationInfo KFPRI, KFPlayerController PC) +{ + local Texture2D Avatar; + + if( KFPRI.Avatar == None || KFPRI.Avatar == default.DefaultAvatar ) + { + Avatar = FindAvatar(PC, KFPRI.UniqueId); + if( Avatar == None ) + Avatar = default.DefaultAvatar; + + KFPRI.Avatar = Avatar; + } +} + +delegate bool InOrder( KFPlayerReplicationInfo P1, KFPlayerReplicationInfo P2 ) +{ + if( P1 == None || P2 == None ) + return true; + + if( P1.GetTeamNum() < P2.GetTeamNum() ) + return false; + + if( P1.Kills == P2.Kills ) + { + if( P1.Assists == P2.Assists ) + return true; + + return P1.Assists < P2.Assists; + } + + return P1.Kills < P2.Kills; +} + +function DrawMenu() +{ + local string S; + local PlayerController PC; + local KFPlayerReplicationInfo KFPRI; + local PlayerReplicationInfo PRI; + local float XPos, YPos, YL, XL, FontScalar, XPosCenter, DefFontHeight, BoxW, BoxX; + local int i, j, NumSpec, NumPlayer, NumAlivePlayer, Width; + + PC = GetPlayer(); + if( KFGRI==None ) + { + KFGRI = KFGameReplicationInfo(PC.WorldInfo.GRI); + if( KFGRI==None ) + return; + } + + // Sort player list. + if( NextScoreboardRefresh < PC.WorldInfo.TimeSeconds ) + { + NextScoreboardRefresh = PC.WorldInfo.TimeSeconds + 0.1; + + for( i=(KFGRI.PRIArray.Length-1); i>0; --i ) + { + for( j=i-1; j>=0; --j ) + { + if( !InOrder(KFPlayerReplicationInfo(KFGRI.PRIArray[i]),KFPlayerReplicationInfo(KFGRI.PRIArray[j])) ) + { + PRI = KFGRI.PRIArray[i]; + KFGRI.PRIArray[i] = KFGRI.PRIArray[j]; + KFGRI.PRIArray[j] = PRI; + } + } + } + } + + // Check players. + PlayerIndex = -1; + NumPlayer = 0; + for( i=(KFGRI.PRIArray.Length-1); i>=0; --i ) + { + KFPRI = KFPlayerReplicationInfo(KFGRI.PRIArray[i]); + if( KFPRI==None ) + continue; + if( KFPRI.bOnlySpectator ) + { + ++NumSpec; + continue; + } + if( KFPRI.PlayerHealth>0 && KFPRI.PlayerHealthPercent>0 && KFPRI.GetTeamNum()==0 ) + ++NumAlivePlayer; + ++NumPlayer; + } + + KFPRIArray.Length = NumPlayer; + j = KFPRIArray.Length; + for( i=(KFGRI.PRIArray.Length-1); i>=0; --i ) + { + KFPRI = KFPlayerReplicationInfo(KFGRI.PRIArray[i]); + if( KFPRI!=None && !KFPRI.bOnlySpectator ) + { + KFPRIArray[--j] = KFPRI; + if( KFPRI==PC.PlayerReplicationInfo ) + PlayerIndex = j; + } + } + + // Header font info. + Canvas.Font = Owner.CurrentStyle.PickFont(FontScalar); + YL = Owner.CurrentStyle.DefaultHeight; + DefFontHeight = YL; + + XPosCenter = (Canvas.ClipX * 0.5); + + // Server Name + + XPos = XPosCenter; + YPos += DefFontHeight; + + S = KFGRI.ServerName; + Canvas.TextSize(S, XL, YL, FontScalar, FontScalar); + + BoxW = XL + (Owner.HUDOwner.ScaledBorderSize*4); + BoxX = XPos - (BoxW * 0.5); + Canvas.SetDrawColor(10, 10, 10, 200); + Owner.CurrentStyle.DrawRectBox(BoxX, YPos, BoxW, DefFontHeight, 4); + Canvas.SetDrawColor(250, 0, 0, 255); + + Owner.CurrentStyle.DrawTextShadow(S, BoxX + ((BoxW-XL) / 2), YPos + ((DefFontHeight-YL) / 2), 1, FontScalar); + + // Deficulty | Wave | MapName + + XPos = XPosCenter; + YPos += DefFontHeight+Owner.HUDOwner.ScaledBorderSize; + + S = " " $Class'KFCommon_LocalizedStrings'.Static.GetDifficultyString (KFGRI.GameDifficulty) $" | "$class'KFGFxHUD_ScoreboardMapInfoContainer'.default.WaveString@KFGRI.WaveNum $" | " $class'KFCommon_LocalizedStrings'.static.GetFriendlyMapName(PC.WorldInfo.GetMapName(true)); + Canvas.TextSize(S, XL, YL, FontScalar, FontScalar); + + BoxW = XL + (Owner.HUDOwner.ScaledBorderSize*4); + BoxX = XPos - (BoxW * 0.5); + Canvas.SetDrawColor(10, 10, 10, 200); + Owner.CurrentStyle.DrawRectBox(BoxX, YPos, BoxW, DefFontHeight, 4); + Canvas.SetDrawColor(0, 250, 0, 255); + + Owner.CurrentStyle.DrawTextShadow(S, BoxX + ((BoxW-XL) / 2), YPos + ((DefFontHeight-YL) / 2), 1, FontScalar); + + // Players | Spectators | Alive | Time + + XPos = XPosCenter; + YPos += DefFontHeight+Owner.HUDOwner.ScaledBorderSize; + + S = " Players : " $ NumPlayer $ " | Spectators : " $ NumSpec $ " | Alive : " $ NumAlivePlayer $ " | Elapsed Time : " $ Owner.CurrentStyle.GetTimeString(KFGRI.ElapsedTime) $ " "; + Canvas.TextSize(S, XL, YL, FontScalar, FontScalar); + + BoxW = XL + (Owner.HUDOwner.ScaledBorderSize*4); + BoxX = XPos - (BoxW * 0.5); + Canvas.SetDrawColor(10, 10, 10, 200); + Owner.CurrentStyle.DrawRectBox(BoxX, YPos, BoxW, DefFontHeight, 4); + Canvas.SetDrawColor(250, 250, 0, 255); + + Owner.CurrentStyle.DrawTextShadow(S, BoxX + ((BoxW-XL) / 2), YPos + ((DefFontHeight-YL) / 2), 1, FontScalar); + + Width = Canvas.ClipX * 0.625; + + XPos = (Canvas.ClipX - Width) * 0.5; + YPos += DefFontHeight * 2.0; + + Canvas.SetDrawColor (10, 10, 10, 200); + Owner.CurrentStyle.DrawRectBox(XPos, YPos, Width, DefFontHeight, 4); + + Canvas.SetDrawColor(250, 250, 250, 255); + + // Calc X offsets + PerkXPos = Width * 0.01; + PlayerXPos = Width * 0.2; + KillsXPos = Width * 0.5; + AssistXPos = Width * 0.6; + CashXPos = Width * 0.7; + StateXPos = Width * 0.8; + PingXPos = Width * 0.92; + + // Header texts + Canvas.SetPos (XPos + PerkXPos, YPos); + Canvas.DrawText (class'KFGFxMenu_Inventory'.default.PerkFilterString, , FontScalar, FontScalar); + + Canvas.SetPos (XPos + KillsXPos, YPos); + Canvas.DrawText (class'KFGFxHUD_ScoreboardWidget'.default.KillsString, , FontScalar, FontScalar); + + Canvas.SetPos (XPos + AssistXPos, YPos); + Canvas.DrawText (class'KFGFxHUD_ScoreboardWidget'.default.AssistsString, , FontScalar, FontScalar); + + Canvas.SetPos (XPos + CashXPos, YPos); + Canvas.DrawText (class'KFGFxHUD_ScoreboardWidget'.default.DoshString, , FontScalar, FontScalar); + + Canvas.SetPos (XPos + StateXPos, YPos); + Canvas.DrawText ("STATE", , FontScalar, FontScalar); + + Canvas.SetPos (XPos + PlayerXPos, YPos); + Canvas.DrawText (class'KFGFxHUD_ScoreboardWidget'.default.PlayerString, , FontScalar, FontScalar); + + Canvas.SetPos (XPos + PingXPos, YPos); + Canvas.DrawText (class'KFGFxHUD_ScoreboardWidget'.default.PingString, , FontScalar, FontScalar); + + PlayersList.XPosition = ((Canvas.ClipX - Width) * 0.5) / InputPos[2]; + PlayersList.YPosition = (YPos + (YL + 4)) / InputPos[3]; + PlayersList.YSize = (1.f - PlayersList.YPosition) - 0.15; + + PlayersList.ChangeListSize(KFPRIArray.Length); +} + +function DrawPlayerEntry( Canvas C, int Index, float YOffset, float Height, float Width, bool bFocus ) +{ + local string S, StrValue; + local float FontScalar, TextYOffset, XL, YL, PerkIconPosX, PerkIconPosY, PerkIconSize, PrestigeIconScale; + local KFPlayerReplicationInfo KFPRI; + local byte Level, PrestigeLevel; + local bool bIsZED; + local int Ping; + + YOffset *= 1.05; + KFPRI = KFPRIArray[Index]; + + if( KFGRI.bVersusGame ) + bIsZED = KFTeamInfo_Zeds(KFPRI.Team) != None; + + C.Font = Owner.CurrentStyle.PickFont(FontScalar); + + TextYOffset = YOffset + (Height / 2) - (Owner.CurrentStyle.DefaultHeight / 2); + if (PlayerIndex == Index) + C.SetDrawColor (51, 30, 101, 150); + else C.SetDrawColor (30, 30, 30, 150); + + Owner.CurrentStyle.DrawRectBox(0.f, YOffset, Width, Height, 4); + + C.SetDrawColor(250,250,250,255); + + // Perk + if( bIsZED ) + { + C.SetDrawColor(255,0,0,255); + C.SetPos (PerkXPos, YOffset - ((Height-5) / 2)); + C.DrawRect (Height-5, Height-5, Texture2D'UI_Widgets.MenuBarWidget_SWF_IF'); + + S = "ZED"; + C.SetPos (PerkXPos + Height, TextYOffset); + C.DrawText (S, , FontScalar, FontScalar); + } + else + { + if( KFPRI.CurrentPerkClass!=None ) + { + PrestigeLevel = KFPRI.GetActivePerkPrestigeLevel(); + Level = KFPRI.GetActivePerkLevel(); + + PerkIconPosX = PerkXPos; + PerkIconPosY = YOffset + (Owner.HUDOwner.ScaledBorderSize * 2); + PerkIconSize = Height-(Owner.HUDOwner.ScaledBorderSize * 4); + PrestigeIconScale = 0.6625f; + + C.DrawColor = HUDOwner.WhiteColor; + if (PrestigeLevel > 0) + { + C.SetPos(PerkIconPosX, PerkIconPosY); + C.DrawTile(KFPRI.CurrentPerkClass.default.PrestigeIcons[PrestigeLevel - 1], PerkIconSize, PerkIconSize, 0, 0, 256, 256); + + C.SetPos(PerkIconPosX + ((PerkIconSize/2) - ((PerkIconSize*PrestigeIconScale)/2)), PerkIconPosY + ((PerkIconSize/2) - ((PerkIconSize*PrestigeIconScale)/1.75))); + C.DrawTile(KFPRI.CurrentPerkClass.default.PerkIcon, PerkIconSize * PrestigeIconScale, PerkIconSize * PrestigeIconScale, 0, 0, 256, 256); + } + else + { + C.SetPos(PerkIconPosX, PerkIconPosY); + C.DrawTile(KFPRI.CurrentPerkClass.default.PerkIcon, PerkIconSize, PerkIconSize, 0, 0, 256, 256); + } + + C.SetDrawColor(250,250,250,255); + C.SetPos(PerkIconPosX + PerkIconSize + (Owner.HUDOwner.ScaledBorderSize*2), TextYOffset); + C.DrawText(Level@KFPRI.CurrentPerkClass.default.PerkName, , FontScalar, FontScalar); + } + else + { + C.SetDrawColor(250,250,250,255); + S = "No Perk"; + C.SetPos (PerkXPos + Height, TextYOffset); + C.DrawText (S, , FontScalar, FontScalar); + } + } + + // Avatar + if( KFPRI.Avatar != None ) + { + if( KFPRI.Avatar == default.DefaultAvatar ) + CheckAvatar(KFPRI, OwnerPC); + + C.SetDrawColor(255,255,255,255); + C.SetPos(PlayerXPos - (Height * 1.075), YOffset + (Height / 2) - ((Height - 6) / 2)); + C.DrawTile(KFPRI.Avatar,Height - 6,Height - 6,0,0,KFPRI.Avatar.SizeX,KFPRI.Avatar.SizeY); + Owner.CurrentStyle.DrawBoxHollow(PlayerXPos - (Height * 1.075), YOffset + (Height / 2) - ((Height - 6) / 2), Height - 6, Height - 6, 1); + } + else if( !KFPRI.bBot ) + CheckAvatar(KFPRI, OwnerPC); + + // Player + C.SetPos (PlayerXPos, TextYOffset); + + if( Len(KFPRI.PlayerName) > 25 ) + S = Left(KFPRI.PlayerName, 25); + else S = KFPRI.PlayerName; + C.DrawText (S, , FontScalar, FontScalar); + + C.SetDrawColor(255,255,255,255); + + // Kill + C.SetPos (KillsXPos, TextYOffset); + C.DrawText (string (KFPRI.Kills), , FontScalar, FontScalar); + + // Assist + C.SetPos (AssistXPos, TextYOffset); + C.DrawText (string (KFPRI.Assists), , FontScalar, FontScalar); + + // Cash + C.SetPos (CashXPos, TextYOffset); + if( bIsZED ) + { + C.SetDrawColor(250, 0, 0, 255); + StrValue = "Brains!"; + } + else + { + C.SetDrawColor(250, 250, 100, 255); + StrValue = "£"$GetNiceSize(int(KFPRI.Score)); + } + C.DrawText (StrValue, , FontScalar, FontScalar); + + C.SetDrawColor(255,255,255,255); + + // State + if( !KFPRI.bReadyToPlay && KFGRI.bMatchHasBegun ) + { + C.SetDrawColor(250,0,0,255); + S = "LOBBY"; + } + else if( !KFGRI.bMatchHasBegun ) + { + C.SetDrawColor(250,0,0,255); + S = KFPRI.bReadyToPlay ? "Ready" : "Not Ready"; + } + else if( bIsZED && KFTeamInfo_Zeds(GetPlayer().PlayerReplicationInfo.Team) == None ) + { + C.SetDrawColor(250,0,0,255); + S = "Unknown"; + } + else if (KFPRI.PlayerHealth <= 0 || KFPRI.PlayerHealthPercent <= 0) + { + C.SetDrawColor(250,0,0,255); + S = (KFPRI.bOnlySpectator) ? "Spectator" : "DEAD"; + } + else + { + if (ByteToFloat(KFPRI.PlayerHealthPercent) >= 0.8) + C.SetDrawColor(0,250,0,255); + else if (ByteToFloat(KFPRI.PlayerHealthPercent) >= 0.4) + C.SetDrawColor(250,250,0,255); + else C.SetDrawColor(250,100,100,255); + + S = string (KFPRI.PlayerHealth) @"HP"; + } + + C.SetPos (StateXPos, TextYOffset); + C.DrawText (S, , FontScalar, FontScalar); + + C.SetDrawColor(250,250,250,255); + + // Ping + if (KFPRI.bBot) + S = "-"; + else + { + Ping = int(KFPRI.Ping * `PING_SCALE); + + if (Ping <= 100) + C.SetDrawColor(0,250,0,255); + else if (Ping <= 200) + C.SetDrawColor(250,250,0,255); + else C.SetDrawColor(250,100,100,255); + + S = string(Ping); + } + + C.TextSize(MaxPing, XL, YL, FontScalar, FontScalar); + + C.SetPos(PingXPos, TextYOffset); + C.DrawText(S,, FontScalar, FontScalar); + + DrawPingBars(C, YOffset + (Height/2) - ((Height*0.5)/2), Width - (Height*0.5) - (Owner.HUDOwner.ScaledBorderSize*2), Height*0.5, Height*0.5, float(Ping)); +} + +final function DrawPingBars( Canvas C, float YOffset, float XOffset, float W, float H, float Ping ) +{ + local float PingMul, BarW, BarH, BaseH, XPos, YPos; + local byte i; + + PingMul = 1.f - FClamp(FMax(Ping - IdealPing, 1.f) / MaxPing, 0.f, 1.f); + BarW = W / PingBars; + BaseH = H / PingBars; + + PingColor.R = (1.f - PingMul) * 255; + PingColor.G = PingMul * 255; + + for(i=1; i= (i / PingBars) ) + { + C.SetPos(XPos,YPos); + C.DrawColor = PingColor; + Owner.CurrentStyle.DrawWhiteBox(BarW,BarH); + } + + C.SetDrawColor(80, 80, 80, 255); + Owner.CurrentStyle.DrawBoxHollow(XPos,YPos,BarW,BarH,1); + } +} + +static final function Texture2D FindAvatar( KFPlayerController PC, UniqueNetId ClientID ) +{ + local string S; + + S = PC.GetSteamAvatar(ClientID); + if( S=="" ) + return None; + return Texture2D(PC.FindObject(S,class'Texture2D')); +} + +final static function string GetNiceSize(int Num) +{ + if( Num < 1000 ) return string(Num); + else if( Num < 1000000 ) return (Num / 1000) $ "K"; + else if( Num < 1000000000 ) return (Num / 1000000) $ "M"; + + return (Num / 1000000000) $ "B"; +} + +function ScrollMouseWheel( bool bUp ) +{ + PlayersList.ScrollMouseWheel(bUp); +} + +defaultproperties +{ + bEnableInputs=true + + PingColor=(R=255,G=255,B=60,A=255) + IdealPing=50.0 + MaxPing=200.0 + PingBars=5.0 + + Begin Object Class=KFGUI_List Name=PlayerList + XSize=0.625 + OnDrawItem=DrawPlayerEntry + ID="PlayerList" + bClickable=false + ListItemsPerPage=16 + End Object + Components.Add(PlayerList) + + DefaultAvatar=Texture2D'UI_HUD.ScoreBoard_Standard_SWF_I26' +} \ No newline at end of file diff --git a/Src/KFClassicHUD/Globals.uci b/Src/KFClassicHUD/Globals.uci new file mode 100644 index 0000000..9e37816 --- /dev/null +++ b/Src/KFClassicHUD/Globals.uci @@ -0,0 +1,81 @@ +`define WM_WAVEINBOUND 1 +`define WM_WAVESURVIVED 2 +`define WM_FINALWAVEINBOUND 3 +`define WM_BOSSINBOUND 4 +`define WM_DEFEATED 5 +`define WM_SURVIVED 6 + +`define TRADER_ALMOSTOPEN 0 +`define TRADER_MOVING 1 +`define TRADER_OPEN 2 +`define TRADER_CLOSED 3 +`define TRADER_THIRTYSECONDS 4 +`define TRADER_TENSECONDS 5 +`define TRADER_LASTWAVE 6 +`define TRADER_WELCOME 7 +`define TRADER_TOOEXPENSIVE 8 +`define TRADER_TOOHEAVY 9 +`define TRADER_WALKIEBEEP 10 + +`define BOX_INNERBORDER 0 +`define BOX_INNERBORDER_TRANSPARENT 1 +`define BOX_MEDIUM 2 +`define BOX_MEDIUM_SLIGHTTRANSPARENT 3 +`define BOX_MEDIUM_TRANSPARENT 4 +`define BOX_LARGE 5 +`define BOX_LARGE_SLIGHTTRANSPARENT 6 +`define BOX_LARGE_TRANSPARENT 7 +`define BOX_SMALL 8 +`define BOX_SMALL_SLIGHTTRANSPARENT 9 +`define BOX_SMALL_TRANSPARENT 10 +`define BOX_CORNER_8 11 +`define BOX_CORNER_16 12 +`define BOX_CORNER_32 13 +`define BOX_CORNER_64 14 +`define BOX_CORNER_512 15 + +`define ITEMBOX_NORMAL 0 +`define ITEMBOX_DISABLED 1 +`define ITEMBOX_HIGHLIGHTED 2 + +`define ITEMBOX_BAR_NORMAL 3 +`define ITEMBOX_BAR_DISABLED 4 +`define ITEMBOX_BAR_HIGHLIGHTED 5 + +`define PROGRESS_BAR_NORMAL 0 +`define PROGRESS_BAR_SELECTED 1 + +`define CHECKMARK_NORMAL 0 +`define CHECKMARK_DISABLED 1 +`define CHECKMARK_HIGHLIGHTED 2 + +`define PERK_BOX_SELECTED 0 +`define PERK_BOX_UNSELECTED 1 + +`define ARROW_DOWN 0 +`define ARROW_LEFT 1 +`define ARROW_RIGHT 2 +`define ARROW_UP 3 + +`define BUTTON_NORMAL 0 +`define BUTTON_DISABLED 1 +`define BUTTON_HIGHLIGHTED 2 +`define BUTTON_PRESSED 3 + +`define TAB_TOP 0 +`define TAB_BOTTOM 1 + +`define PEN_WHITE 0 +`define PEN_BLACK 1 +`define PEN_GRAY 2 + +`define SLIDER_NORMAL 0 +`define SLIDER_GRIP 1 +`define SLIDER_DISABLED 2 + +`define CURSOR_DEFAULT 0 +`define CURSOR_SELECTION 1 +`define CURSOR_RESIZEVERT 2 +`define CURSOR_RESIZEHORZ 3 + +`define Print(log) LocalPlayer(class'WorldInfo'.static.GetWorldInfo().GetALocalPlayerController().Player).ViewportClient.ViewportConsole.OutputText(`log) \ No newline at end of file