rott/kf_sources/KFStoryGame/Classes/HUD_StoryMode.uc
2026-07-14 20:27:09 +07:00

2059 lines
68 KiB
Ucode

/*
--------------------------------------------------------------
HUD_StoryMode
--------------------------------------------------------------
Custom HUD type for use in KF 'Story' maps.
Author : Alex Quick
--------------------------------------------------------------
*/
class HUD_StoryMode extends HUDKillingFloorSP
dependson(KFStoryGameInfo) ;
/* Same sort of icon as the Trader arrow - shows you roughly where your next objective is located */
var KFShopDirectionPointer ObjectiveArrow;
var KF_StoryGRI SGRI;
/* The amount of time that has passed since the last HUD Tick. Used for controlling interpolation */
var float RenderDelta;
var float LastHUDRenderTime;
var float LastIconUpdateTime;
/* Current game objective according to the game replication info */
var KF_StoryObjective CurrentObj;
/* The HUD's currently rendered objective. Tends to lag behind the 'CurrentObj' var because it fades in/ out*/
var KF_StoryObjective RenderObj;
var int ObjRenderIdx;
/* Objectives which haven't yet been displayed on the player's HUD but are qued & awaiting fade in/ out effects*/
var array <KF_StoryObjective> HUDObjs;
/* Cached list of all the objectives in the map */
var array <KF_StoryObjective> AllObjs;
/* Opacity of the currently rendered objective on the HUD */
var float RenderObjOpacity;
var bool bFadingIn;
var bool bFadingOut;
var float PendingFadeOutStartTime;
var bool bPendingFadeOut;
var bool bSkipTransitions;
var float ObjFadeOutTime,ObjFadeInTime;
/* The amount of delay after an objective completes before it actually fades out */
var float ObjFadeOutDelay;
/* Skip the usual fading between objectives and just display the current one */
var bool bInstantObjTransitions;
var float LastNewRenderObjTime;
var bool bFadingOutObj;
var bool bShowObjectives;
var bool bCollapseConditions;
struct SConditionHint
{
var name ConditionName;
var string DataString,WorldHint;
var int bComplete;
var float ProgressPct;
var color ProgressBar_Clr;
var color World_Clr;
var byte ConditionType,HintStyle,DisplayStyle; // 1 == success , 0 == failure
var Actor ConditionLoc;
var Material WorldTex;
var Material Material_ProgressBarFill,Material_ProgressBarBG;
var int FontScale;
var bool bHideWorld;
var bool bIgnoreWorldHidden;
var float LastProgressUpdateTime ;
var float LastProgressVal;
var float WidestDataX;
var float ProgBarheight;
var float HintWidth;
var float HintHeight;
var name ObjOwner;
var bool bShowCheckBox;
var bool bShowStrikeThrough;
var float World_Texture_Scale;
var name PendingLocActorTag ; // we want to cache an actor, but have no reference to it yet .
};
var array<SConditionHint> ConditionHints;
var float lastConditionupdateTime;
/* === Dialogue Rendering =================================================================================*/
struct SDialogueRenderInfo
{
var string Speaker;
var string Message;
var float Duration;
var Material Portrait;
var float FirstDisplayedTime;
var float Opacity;
var bool bWrapped;
var bool bFirstDisplay;
var KFStoryGameInfo.SVect2D ScreenPos;
var KFStoryGameInfo.EDialogueAlignment ScreenAlignment;
var LobbyMenuAd BinkPortrait;
var Material BackGroundMat;
var KFStoryGameInfo.EDialogueScaleStyle ScreenScaleStyle;
};
var array<SDialogueRenderInfo> Dialogues;
var array<KF_DialogueSpot> DialogueSpots;
var int CurrentDlgIndex;
var SpriteWidget DialogueBackground;
var TextWidget DialogueTitleWidget;
var TextWidget DialogueTextWidget;
var RelativeCoordsInfo DialogueCoords;
var array<string> WrappedDialogue;
var LobbyMenuAd Intro_BinkMovie;
var bool bPlayingIntroMovie;
var bool bPlayedIntroMovie;
var KF_HUDStyleManager HUDStyleManager;
var int StoryIconOffsetX;
var int StoryIconOffsetY;
/* @todo - there's a bug in this code where bNoKFColorCorrection is ignored, needs fixing
for now just gonna empty out this func
simulated function DrawModOverlay( Canvas C ){} */
/* toggles displaying properties of player's current viewtarget
Cut out the StandAlone only condition so I can see what up in net-play
*/
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
CacheDialogueActors();
CacheObjectives();
}
simulated function CacheObjectives()
{
local KF_StoryObjective Obj;
foreach AllActors(class 'KF_StoryObjective', Obj)
{
AllObjs[AllObjs.length] = Obj;
}
}
simulated function CacheDialogueActors()
{
local KF_DialogueSpot NewDlgSpot;
foreach AllActors(class 'KF_DialogueSpot', NewDlgSpot)
{
DialogueSpots[DialogueSpots.length] = NewDlgSpot;
}
}
simulated function KF_DialogueSpot FindDialogueActor(name DlgName)
{
local int i;
for(i = 0 ; i < DialogueSpots.length ; i ++)
{
if(DialogueSpots[i].name == DlgName)
{
return DialogueSpots[i];
}
}
}
exec function ShowDebug()
{
bShowDebugInfo = !bShowDebugInfo;
}
exec simulated function ToggleObjectiveHUD()
{
bShowObjectives = !bShowObjectives ;
}
simulated function DrawSpectatingHud(Canvas C)
{
Super.DrawSpectatingHUD(C);
DrawStoryHUDInfo(C);
}
simulated function DrawHudPassA (Canvas C)
{
DrawStoryHUDInfo(C);
Super.DrawHUDPassA(C);
}
simulated function DrawStoryHUDInfo(Canvas C)
{
if(bHideHUD ||
PlayerOwner != none &&
PlayerOwner.Player != none &&
GUIController(PlayerOwner.Player.GUIController) != none &&
GUIController(PlayerOwner.Player.GUIController).ActivePage != none) // we've got another menu open, dont show this stuff...
{
return;
}
RenderStoryItems(C);
DrawObjectiveInfo(C);
if(!bShowScoreBoard)
{
DrawDialogue(C);
}
}
/* Specific function to use Canvas.DrawActor()
Clear Z-Buffer once, prior to rendering all actors */
function CanvasDrawActors( Canvas C, bool bClearedZBuffer )
{
PostRenderStoryInventory(C);
Super.CanvasDrawActors(C,bClearedZBuffer);
}
function PostRenderStoryInventory(Canvas C)
{
local Inventory CurInv;
local KF_StoryInventoryItem StoryInv;
if(PawnOwner == none)
{
return;
}
for ( CurInv = PawnOwner.Inventory; CurInv != none; CurInv = CurInv.Inventory )
{
StoryInv = KF_StoryInventoryItem(CurInv);
if(StoryInv != none )
{
StoryInv.RenderOverlays(C);
}
}
}
/* Draws overlays for Pickup-able or currently carried items in story missions */
simulated function RenderStoryItems(Canvas C)
{
local Inventory CurInv;
local KF_StoryInventoryItem StoryInv;
local float PosX,PosY;
local float IconSizeX,IconSizeY;
local Material InvIcon;
local float ScaleX,ScaleY;
local int i;
local KF_StoryPRI PRI;
local float Opacity;
local float IconSize;
local float XCentre,YCentre;
local vector ScreenPos;
local Material RenderMat;
local vector CameraLocation;
local rotator CameraRotation;
local float Dist;
local vector RenderLocation;
local vector CurrentPawnPos,NextPawnPos;
local float AbsoluteDist;
local vector MovementDir;
local float DistMax;
local float InterpSpeed,InterpDist;
local KF_StoryInventoryPickup Pickup;
/* Render icons over players heads while they are carrying Story Items*/
if(PlayerOwner != none && PlayerOwner.GameReplicationinfo != none)
{
for(i = 0 ; i < PlayerOwner.GameReplicationInfo.PRIArray.length ; i ++)
{
PRI = KF_StoryPRI(PlayerOwner.GameReplicationInfo.PRIArray[i]);
if(PRI == none ||
PRI == PlayerOwner.PlayerReplicationInfo ||
PRI.GetFloatingIconMat() == none)
{
continue;
}
else
{
/* Looks like we've got a relevant pawn. That makes things nice and easy.. */
if(PRI.GetOwnerPawn() != none &&
!PRI.GetOwnerPawn().bDeleteMe &&
!PRI.GetOwnerPawn().bPendingDelete)
{
RenderLocation = PRI.GetOwnerPawn().GetHoverIconPosition() ;
}
else // he's not relevant - do some interpolation mumbo jumbo and pray it doesn't look horrible ..
{
CurrentPawnPos = PRI.GetCurrentPawnLoc();
if(CurrentPawnPos == vect(0,0,0) ||
PRI.GetLastPawnLoc() == vect(0,0,0))
{
continue;
}
/* Client prediction - Attempt to figure out where the next update will place the Icon*/
MovementDir = Normal(CurrentPawnPos - PRI.GetLastPawnLoc());
AbsoluteDist = VSize(CurrentPawnPos - PRI.GetLastPawnLoc());
NextPawnPos = CurrentPawnPos + (MovementDir * AbsoluteDist);
DistMax = 500.f;
InterpDist = VSize(NextPawnPos - PRI.GetInterpolatedPawnLoc());
InterpSpeed = InterpDist;
// log("InterpDist : "@InterpDist@" === InterpSpeed : "@InterpSpeed);
/* Huge move - re-position immediately */
if(InterpDist > DistMax)
{
PRI.SetInterpolatedPawnLoc(NextPawnPos);
}
PRI.SetInterpolatedPawnLoc(VInterpTo(PRI.GetInterpolatedPawnLoc(),NextPawnPos,RenderDelta,InterpSpeed));
RenderLocation = PRI.GetInterpolatedPawnLoc();
}
if(RenderLocation == Vect(0,0,0))
{
continue;
}
C.GetCameraLocation(CameraLocation, CameraRotation);
/* fading jazz from PlayerBeacon code */
Dist = vsize(CameraLocation-RenderLocation);
Dist -= class 'HUDKillingFloor'.default.HealthBarFullVisDist;
Dist = FClamp(Dist, 0, class 'HUDKillingFloor'.default.HealthBarCutoffDist-class 'HUDKillingFloor'.default.HealthBarFullVisDist);
Dist = Dist / (class 'HUDKillingFloor'.default.HealthBarCutoffDist- class 'HUDKillingFloor'.default.HealthBarFullVisDist);
Opacity = Max(byte((1.f - Dist) * 255.f),100.f);
RenderMat = PRI.GetFloatingIconMat();
IconSize = 48.f;
ScreenPos = C.WorldToScreen(RenderLocation);
XCentre = ScreenPos.X;
YCentre = ScreenPos.Y;
/* Dont render stuff behind the camera */
if ( (Normal(RenderLocation - CameraLocation) dot vector(CameraRotation)) < 0 )
{
continue;
}
C.DrawColor.R = 255;
C.DrawColor.G = 255;
C.DrawColor.B = 255;
C.DrawColor.A = Opacity;
C.SetPos(XCentre - (0.5 * IconSize) - StoryIconOffsetX, YCentre - (0.5 * IconSize) - StoryIconOffsetY);
C.DrawTileScaled(RenderMat, IconSize/ RenderMat.MaterialVSize() ,IconSize/ RenderMat.MaterialVSize() );
}
}
}
if( PawnOwner == none )
{
return;
}
/* Draw Projected World Icons */
foreach DynamicActors(class 'KF_StoryInventoryPickup', Pickup)
{
Pickup.RenderOverlays(C);
}
PosX = C.ClipX * 0.3 ;
PosY = C.ClipY * 0.9 ;
IconSizeX = C.ClipX / 32.f;
IconSizeY = IconSizeX;
/* Draw little HUD Icons on the owning player's HUD */
for ( CurInv = PawnOwner.Inventory; CurInv != none; CurInv = CurInv.Inventory )
{
StoryInv = KF_StoryInventoryItem(CurInv);
if(StoryInv != none )
{
if(StoryInv.CarriedMaterial != none)
{
InvIcon = StoryInv.CarriedMaterial ;
ScaleX = IconSizeX/ InvIcon.MaterialVSize() ;
ScaleY = IconSizeY / InvIcon.MaterialVSize() ;
C.SetPos(PosX- IconSizeX/2,PosY+ IconSizeY/2);
C.DrawColor = WhiteColor;
C.DrawColor.A = KFHUDAlpha;
C.DrawTileScaled(InvIcon,ScaleX,ScaleY);
PosX += (IconSizeX*ScaleX) * 1.1;
}
}
}
}
/** Interpolate vector from Current to Target with constant step */
simulated function Vector VInterpTo(Vector Current, Vector Target, FLOAT DeltaTime, FLOAT InterpSpeed)
{
local Vector Delta;
local FLOAT DeltaM;
local FLOAT MaxStep ;
local Vector DeltaN;
Delta = Target - Current;
DeltaM = VSize(Delta);
MaxStep = InterpSpeed * DeltaTime;
if( DeltaM > MaxStep )
{
if( MaxStep > 0.f )
{
DeltaN = Delta / DeltaM;
return Current + DeltaN * MaxStep;
}
else
{
return Current;
}
}
return Target;
}
simulated function DrawHUD(Canvas Canvas)
{
RenderDelta = Level.TimeSeconds - LastHUDRenderTime;
LastHUDRenderTime = Level.TimeSeconds;
if(PlayerOwner != none)
{
if(!bHideHUD)
{
Super.DrawHUD(Canvas);
DrawStoryDebugInfo(Canvas);
}
}
}
simulated function RenderIntroMovie(Canvas C)
{
if(PlayerOwner.GameReplicationInfo.bMatchHasBegun)
{
if ( Intro_BinkMovie == none)
{
Intro_BinkMovie = new class'LobbyMenuAd';
if (Intro_BinkMovie.MenuMovie == None)
{
Intro_BinkMovie.MenuMovie = new class'Movie';
Intro_BinkMovie.MenuMovie.Callbacks = Intro_BinkMovie;
}
}
else
{
if(Intro_BinkMovie.MenuMovie != none)
{
if(!bPlayedIntroMovie)
{
bPlayedIntroMovie = true;
Intro_BinkMovie.MenuMovie.Open("../Movies/Dummy_UI_Vid"$".bik");
Intro_BinkMovie.MenuMovie.Play(true);
}
bPlayingIntroMovie = Intro_BinkMovie.MenuMovie.IsPlaying() ;
if(bPlayingIntroMovie)
{
C.SetPos(0,0);
C.DrawColor = WhiteColor;
C.DrawTileScaled(Intro_BinkMovie.MenuMovie, C.SizeX/Intro_BinkMovie.MenuMovie.GetWidth(),C.SizeY/Intro_BinkMovie.MenuMovie.GetHeight());
}
}
}
}
}
simulated function DrawStoryDebugInfo(Canvas Canvas)
{
local float XPos,YPos;
local float XL,YL;
local int i;
local KFStoryGameInfo StoryGI;
local string NewObjName;
local KF_StoryObjective Obj;
local string ObjName;
if(KFPlayerController_Story(PlayerOwner) != none &&
KFPlayerController_Story(PlayerOwner).bShowObjectiveDebug)
{
Canvas.Font = GetConsoleFont(Canvas);
Canvas.Style = ERenderStyle.STY_Alpha;
Canvas.DrawColor = ConsoleColor;
Canvas.SetPos(XPos,YPos);
Canvas.DrawText("==================== OBJECTIVES ===========================");
StoryGI = KFStoryGameInfo(Level.Game);
if(StoryGI == none)
{
return;
}
YPos = Canvas.ClipY * 0.5;
for(i = 0 ; i < StoryGi.Allobjectives.length ; i ++)
{
Obj = StoryGI.AllObjectives[i];
if(Obj.bCompleted)
{
Canvas.DrawColor = GreenColor;
}
else if (Obj.bFailed)
{
Canvas.DrawColor = RedColor;
}
else
{
Canvas.DrawColor = WhiteColor;
}
Canvas.Font = GetConsoleFont(Canvas);
ObjName = ""$Obj.ObjectiveName ;
if(Obj == StoryGI.CurrentObjective)
{
ObjName = "((("$Obj.ObjectiveName$")))" ;
}
NewObjName = "["$i+1$"]"@ObjName@"-->";
Canvas.StrLen(NewObjName,XL,YL);
XPos += XL ;
Canvas.SetPos(XPos,YPos);
Canvas.DrawText(NewObjName);
}
}
}
simulated function Tick(float DeltaTime)
{
Super.Tick(DeltaTime);
if(PlayerOwner != none && !bHideHUD)
{
UpdateObjFadeVals(deltaTime);
}
/*
copied from parent class ..
This seems like an unnnecessarily redundant way to cache the GRI ...
*/
if ( SGRI == None &&
PlayerOwner.GameReplicationInfo != none)
{
SGRI = KF_StoryGRI(PlayerOwner.GameReplicationInfo);
if(SGRI != none)
{
HUDStyleManager = SGRI.GetHUDStyleManager();
}
}
}
simulated function UpdateObjFadeVals(float DeltaTime)
{
if(RenderObj == none)
{
return;
}
/* Switch to the next Objective .. fade the current one out, first */
if(RenderObj != CurrentObj &&
RenderObjOpacity == 1.f &&
!bFadingIn && !bPendingFadeout)
{
PendingFadeOutStartTime = Level.TimeSeconds;
bPendingFadeOut = true;
}
if(bPendingFadeOut && Level.TimeSeconds - PendingFadeOutStartTime >= ObjFadeOutDelay)
{
bPendingFadeOut = false;
bFadingOut = true;
}
/* We're rendering the right objective, it just needs to fade in */
if(RenderObjOpacity < 1.f &&
!bFadingOut && CurrentObj != none)
{
bFadingIn = true;
}
if(bFadingIn)
{
RenderObjOpacity = FClamp(RenderObjOpacity + (DeltaTime / ObjFadeInTime),0.f,1.f) ;
if(RenderObjOpacity == 1.f || bSkipTransitions)
{
ObjFadeInComplete();
}
}
if(bFadingOut)
{
RenderObjOpacity = FClamp(RenderObjOpacity - (DeltaTime / ObjFadeOutTime),0.f,1.f) ;
if(RenderObjOpacity < 0.1 || bSkipTransitions)
{
ObjFadeOutComplete();
}
}
}
simulated function ObjFadeOutComplete()
{
local int CurrentObjIdx,LastRenderidx;
LastRenderidx = ObjRenderIdx;
bFadingOut = false;
RenderObjOpacity = 0.f;
RemoveHUDObjective(HUDObjs[LastRenderidx]);
if(CurrentObj != none &&
FindHUDObjective(CurrentObj.name,CurrentObjIdx) != none)
{
ObjRenderIdx = CurrentObjIdx;
}
}
simulated function ObjFadeInComplete()
{
// log("+++++++++++++++++++ Fade In complete for : "@RenderObj.ObjectiveName);
bFadingIn = false;
RenderObjOpacity = 1.f;
LastNewRenderObjTime = Level.TimeSeconds;
}
/* Returns 0 if it's a failure condition, or 1 if it's a success condition */
simulated function bool FindConditionTypeFor(SConditionHint TestCondition, out byte ConditionType)
{
local KF_StoryObjective OwningObj;
OwningObj = FindObjectiveByName(TestCondition.ObjOwner);
if(OwningObj != none)
{
ConditionType = OwningObj.GetNamedConditionType(TestCondition.ConditionName);
}
return ConditionType < 2;
}
simulated function ResolveObjectiveInfo()
{
local KF_StoryObjective NewObj;
local int NewIndex;
if(SGRI == none)
{
return;
}
NewObj = SGRI.GetCurrentObjective() ;
if(CurrentObj != NewObj)
{
if(NewObj != none &&
FindHUDObjective(NewObj.name,NewIndex) == none &&
(SGRI.GetDebugTargetObjective() == none || SGRI.GetDebugTargetObjective() ==
NewObj))
{
AddHUDObjective(NewObj);
log("Add Hud Objective : "@NewObj, 'Story_Debug');
}
CurrentObj = NewObj;
}
if(HUDObjs.length > 0)
{
RenderObj = HUDObjs[Min(ObjRenderIdx,HUDObjs.length-1)] ;
// log("======== Current RenderObj :::: "@RenderObj.ObjectiveName@" ========== "@RenderObjOpacity@"======== Target RenderObj :::: "@CurrentObj.ObjectiveName);
}
}
simulated function KF_StoryObjective FindObjectiveByName(name TestObj, optional out int i)
{
for(i = 0 ; i < AllObjs.length ; i ++)
{
if(AllObjs[i].name == TestObj)
{
return AllObjs[i];
}
}
}
simulated function KF_StoryObjective FindHUDObjective(name TestObj, optional out int i)
{
for(i = 0 ; i < HUDObjs.length ; i ++)
{
if(HUDObjs[i].name == TestObj)
{
return HUDObjs[i];
}
}
}
simulated function AddHUDObjective(KF_StoryObjective NewObj)
{
if(NewObj != none && NewObj.bShowOnHUD)
{
// log("** ADD HUD OBJ :: "@NewObj.ObjectiveName);
/* Apply any pending style preset before adding it to the HUD */
ApplyObjectiveStylePresets(NewObj);
HUDObjs.insert(HUDObjs.length,1);
HUDObjs[HUDObjs.length - 1] = NewObj;
}
}
simulated function ApplyObjectiveStylePresets(KF_StoryObjective NewObj)
{
if(HUDStylemanager != none && HUDStylemanager.StylePreset.Objectives.bOverride)
{
NewObj.HUD_Background = HUDStylemanager.StylePreset.Objectives.BackGround;
NewObj.HUD_Header.Header_Color = HUDStylemanager.StylePreset.Objectives.Header.Header_Color;
NewObj.HUD_Header.Header_Scale = HUDStylemanager.StylePreset.Objectives.Header.Header_Scale;
NewObj.HUD_ScreenPosition = HUDStyleManager.StylePreset.Objectives.Position;
}
}
simulated function RemoveHUDObjective(KF_StoryObjective RemoveObj)
{
local int RemovalIndex;
local KF_StoryObjective ObjToRemove;
local int i;
log("Remove HUD Obj : "@RemoveObj, 'Story_Debug');
if(RemoveObj !=none)
{
// log("** REMOVE HUD OBJ :: "@RemoveObj.ObjectiveName);
ObjToRemove = FindHUDObjective(RemoveObj.name,RemovalIndex);
HUDObjs.Remove(RemovalIndex,1);
/* Remove any associated condition info as well */
for(i = 0 ; i < ConditionHints.length ; i ++)
{
if(ConditionHints[i].ObjOwner == RemoveObj.Name)
{
RemoveConditionHint(ConditionHints[i].ConditionName);
}
}
}
}
simulated function DrawObjWorldIcons(Canvas C)
{
local vector CameraLocation, CamDir, TargetLocation, HBScreenPos;
local rotator CameraRotation;
local float Dist;
local color OldDrawColor;
local string HintString;
local float XL,YL;
local int i;
local float IconX,IconY;
local float LargestX,LargestY;
local float OpacityModifier;
local float DistX,DistY;
local string DistString;
local float FarthestDistSq,DistSq;
local float FarthestDist;
local float DistanceScale;
local int FontScale;
local float IconSize;
// rjp -- don't draw the health bar if menus are open
// exception being, the Veterancy menu
if ( PlayerOwner.Player.GUIController.bActive && GUIController(PlayerOwner.Player.GUIController).ActivePage.Name != 'GUIVeterancyBinder' )
{
return;
}
OldDrawColor = C.DrawColor;
C.Style = ERenderStyle.STY_Alpha;
C.GetCameraLocation(CameraLocation, CameraRotation);
CamDir = vector(CameraRotation);
/* Establish distance scaling values for the icons before drawing */
for(i = 0 ; i < ConditionHints.length ; i ++)
{
if(!ShouldRenderCondition(ConditionHints[i],"World"))
{
continue;
}
DistSq = VSizeSquared(ConditionHints[i].ConditionLoc.Location - PlayerOwner.CalcViewLocation) ;
if(DistSq > FarthestDistSq)
{
FarthestDistSq = DistSq;
}
}
i=0;
FarthestDist = Sqrt(FarthestDistSq) ;
for(i = 0 ; i < ConditionHints.length ; i ++)
{
if(!ShouldRenderCondition(ConditionHints[i],"World"))
{
continue;
}
TargetLocation = Conditionhints[i].ConditionLoc.Location;
Dist = VSize(TargetLocation - CameraLocation);
/* Check Distance Threshold / behind camera cut off */
if ( (Normal(TargetLocation - CameraLocation) dot CamDir) < 0 )
{
continue;
}
/* Target is located behind camera
HBScreenPos = C.WorldToScreen(TargetLocation);
if ( HBScreenPos.X <= 0 || HBScreenPos.X >= C.SizeX || HBScreenPos.Y <= 0 || HBScreenPos.Y >= C.SizeY)
{
HBScreenPos = C.WorldToScreen(TargetLocation);
if ( HBScreenPos.X <= 0 || HBScreenPos.X >= C.ClipX || HBScreenPos.Y <= 0 || HBScreenPos.Y >= C.ClipY)
{
return;
}
} */
C.DrawColor = WhiteColor;
HBScreenPos = C.WorldToScreen(TargetLocation);
DistanceScale = 1.f;//FClamp(1.f - (Square(Dist) / FarthestDistSq) , 0.4f,1.f);
if(DistanceScale <= 0.9)
{
FontScale = 1;
}
else if(DistanceScale <= 0.75)
{
FontScale = 0;
}
else if(DistanceScale <= 0.5)
{
FontScale = -1;
}
C.Font = LoadFont(ResolveFontResolution(C,FontScale));
HintString = ConditionHints[i].WorldHint;
if ( HintString != "" )
{
// HintString = HintString @ "(" @ (Round(VSize(TargetLocation - C.ViewPort.Actor.Pawn.Location)/50.0)) @ "m )";
C.StrLen(HintString, XL, YL);
}
OpacityModifier = FClamp(1.f - ((VSize(ConditionHints[i].ConditionLoc.Location - PlayerOwner.CalcViewLocation) - 1500.f) / 1500.f),0.6f,1.f) ;
C.DrawColor = ConditionHints[i].World_Clr;
C.DrawColor.A = KFHUDAlpha * OpacityModifier;
if(ConditionHints[i].WorldTex != none)
{
IconX = ConditionHints[i].WorldTex.MaterialUSize() * DistanceScale * ConditionHints[i].World_Texture_Scale * (C.SizeX/1920.f);
IconY = IconX ;
IconSize = (IconX / ConditionHints[i].WorldTex.MaterialUSize()) ;
}
LargestX = FMax(XL,IconX);
LargestY = FMax(YL,IconY);
/* Clamp icons to the edges of the screeen */
// HBScreenPos.X = FClamp(HBScreenPos.X,LargestX,C.ClipX - LargestX);
// HBScreenPos.Y = FClamp(HBScreenPos.Y,LargestY,C.ClipY - LargestY);
if(ConditionHints[i].WorldTex != none)
{
C.SetPos(HBScreenPos.X - (0.5*IconX), HBScreenPos.Y - (IconY) - 16.f);
C.DrawTileScaled(ConditionHints[i].WorldTex, IconSize ,(IconY/ ConditionHints[i].WorldTex.MaterialVSize()));
}
if ( HintString != "" )
{
if ( XL > 0.125 * C.ClipY )
{
// C.Font = GetFontSizeIndex(C, -2 );
C.StrLen(HintString, XL, YL);
}
C.SetPos(HBScreenPos.X - 0.5*XL , HBScreenPos.Y - YL/2 );
C.DrawTextClipped(HintString);
}
DistString = int(Dist / 50)$"m" ;
C.StrLen(DistString,DistX,DistY);
C.SetPos(HBScreenPos.X - (0.5* IconSize) - DistX/2 , HBScreenPos.Y + YL/2);
C.DrawTextClipped(DistString);
}
}
simulated function DrawObjectiveInfo(Canvas C)
{
if(!bShowObjectives )
{
return;
}
ResolveObjectiveInfo();
if(RenderObj != none)
{
DrawObjWorldIcons(C);
DrawObjectiveHints(C, RenderObj,RenderObjOpacity);
}
}
simulated function bool FindExistingCondition(name ConditionName, out Int Index)
{
local int i;
for(i = 0 ; i < ConditionHints.length ; i ++)
{
if(ConditionHints[i].ConditionName == ConditionName)
{
Index = i;
return true;
}
}
return false;
}
function KF_ObjectiveCondition FindConditionByName(name ConditionName)
{
local KF_ObjectiveCondition Condition;
foreach AllObjects(class 'KF_ObjectiveCondition' , Condition)
{
if(Condition.name == ConditionName)
{
return Condition;
}
}
}
simulated function UpdateConditionHint(
name UpdatedCondition,
name NewOwner,
float NewProgressPct,
Actor NewLocActor,
string NewDataString,
bool NewComplete,
name PendingLocActorTag)
{
local int Index;
local KF_ObjectiveCondition ConditionObject;
ConditionObject = FindConditionByName(UpdatedCondition);
if(ConditionObject == none)
{
log("Warning - Could not find Object Reference for condition of name : "@UpdatedCondition,'Story_Debug');
return;
}
if(FindExistingCondition(UpdatedCondition,Index))
{
if(NewProgressPct != ConditionHints[Index].ProgressPct)
{
ConditionHints[Index].LastProgressUpdateTime = Level.TimeSeconds;
ConditionHints[Index].LastProgressVal = ConditionHints[Index].ProgressPct;
}
ConditionHints[index].ObjOwner = NewOwner;
ConditionHints[Index].DataString = NewDataString;
ConditionHints[Index].ProgressPct = NewProgressPct;
ConditionHints[Index].bComplete = int (NewComplete);
ConditionHints[Index].ConditionLoc = NewLocActor ;
ConditionHints[Index].PendingLocActorTag = PendingLocActorTag;
}
else
{
AddNewConditionHint(ConditionObject,
NewOwner,
NewProgressPct,
NewLocActor,
NewDataString,
NewComplete,
PendingLocActorTag);
}
}
simulated function AddNewConditionHint(
KF_ObjectiveCondition NewCondition,
name NewOwner,
float NewProgressPct,
Actor NewLocActor,
string NewDataString,
bool bComplete,
name PendingLocActorTag)
{
ConditionHints.length = ConditionHints.length + 1;
ConditionHints[ConditionHints.length - 1].ConditionName = NewCondition.name;
ConditionHints[ConditionHints.length - 1].ObjOwner = NewOwner;
ConditionHints[ConditionHints.length - 1].ConditionLoc = NewLocActor;
ConditionHints[ConditionHints.length - 1].World_Texture_Scale = NewCondition.HUD_World.World_Texture_Scale;
ConditionHints[ConditionHints.length - 1].DataString = NewDataString;
ConditionHints[ConditionHints.length - 1].WorldHint = NewCondition.HUD_World.World_Hint;
ConditionHints[ConditionHints.length - 1].bHideWorld = NewCondition.HUD_World.bHide;
ConditionHints[ConditionHints.length - 1].HintStyle = NewCondition.HUD_Screen.Screen_ProgressStyle;
ConditionHints[ConditionHints.length - 1].DisplayStyle = NewCondition.HUD_Screen.Screen_CountStyle;
ConditionHints[ConditionHints.length - 1].bShowCheckBox = NewCondition.HUD_Screen.bShowCheckBox;
ConditionHints[ConditionHints.length - 1].bShowStrikeThrough = NewCondition.HUD_Screen.bShowStrikethrough;
ConditionHints[ConditionHints.length - 1].bIgnoreWorldHidden = NewCondition.HUD_World.bIgnoreWorldLocHidden;
ConditionHints[ConditionHints.length - 1].bComplete = int(bComplete);
ConditionHints[ConditionHints.length - 1].PendingLocActorTag = PendingLocActorTag;
FindConditionTypeFor(ConditionHints[ConditionHints.length -1],ConditionHints[ConditionHints.length -1].ConditionType);
/* Style Settings */
if(!ApplyConditionStylePresets(Conditionhints.length - 1))
{
Conditionhints[Conditionhints.length - 1].World_Clr = NewCondition.HUD_World.World_Clr;
Conditionhints[Conditionhints.length - 1].ProgressBar_Clr = NewCondition.HUD_Screen.Screen_Clr;
ConditionHints[ConditionHints.length - 1].WorldTex = NewCondition.HUD_World.World_Texture;
ConditionHints[ConditionHints.length - 1].Material_ProgressBarBG = NewCondition.HUD_Screen.Screen_ProgressBarBG;
ConditionHints[ConditionHints.length - 1].Material_ProgressBarFill = NewCondition.HUD_Screen.Screen_ProgressBarFill;
ConditionHints[ConditionHints.length - 1].FontScale = NewCondition.HUD_Screen.FontScale;
}
}
simulated function bool ApplyConditionStylePresets(int Index)
{
if(HUDStylemanager == none ||
!HUDStylemanager.StylePreset.Objectives.bOverride)
{
return false;
}
ConditionHints[Index].World_Clr = HUDStyleManager.StylePreset.Objectives.Conditions.Style_ObjCondition_World.World_Clr;
Conditionhints[Index].ProgressBar_Clr = HUDStyleManager.StylePreset.Objectives.Conditions.Style_ObjCondition_Screen.Screen_Clr;
ConditionHints[Index].WorldTex = HUDStyleManager.StylePreset.Objectives.Conditions.Style_ObjCondition_World.World_Texture;
ConditionHints[Index].Material_ProgressBarBG = HUDStyleManager.StylePreset.Objectives.Conditions.Style_ObjCondition_Screen.Screen_ProgressBarBG;
ConditionHints[Index].Material_ProgressBarFill = HUDStyleManager.StylePreset.Objectives.Conditions.Style_ObjCondition_Screen.Screen_ProgressBarFill;
ConditionHints[Index].FontScale = HUDStyleManager.StylePreset.Objectives.Conditions.Style_ObjCondition_Screen.FontScale;
return true;
}
simulated function RemoveConditionHint(name HintToRemove)
{
local int Index;
if(FindExistingCondition(HintToRemove,Index))
{
ConditionHints.Remove(Index,1);
}
}
simulated function float ResolveFontResolution(Canvas C, optional int FontScale)
{
local float FontSize;
local float SizeModifier;
Sizemodifier = 1.f;
if(FontScale != 1)
{
switch(FontScale)
{
case -1: SizeModifier = 3.f; break; // tiny
case 0 : SizeModifier = 2.f; break; // small
case 2 : SizeModifier = -1.f; break; // large
case 3 : SizeModifier = -2.f; break; // very large.
}
}
if ( C.ClipX <= 640 )
FontSize = 7;
else if ( C.ClipX <= 800 )
FontSize = 6;
else if ( C.ClipX <= 1024 )
FontSize = 5;
else if ( C.ClipX <= 1280 )
FontSize = 4;
else
FontSize = 3;
FontSize += SizeModifier;
return FontSize;
}
exec simulated function SetObjX(float X)
{
if(CurrentObj != none)
{
CurrentObj.HUD_ScreenPosition.Horizontal = X ;
}
}
exec simulated function SetObjY(float Y)
{
if(CurrentObj != none)
{
CurrentObj.HUD_ScreenPosition.Vertical = Y ;
}
}
/* Determines which elements of the ConditionHints array should be rendered at any given time
primarily used to ensure that hidden conditions, or those belonging to an objective other than the
one on the HUD are not drawn. */
simulated function bool ShouldRenderCondition(SConditionHint TestCondition, string Type)
{
switch(Type)
{
case "World" :
if(TestCondition.bHideWorld ||
TestCondition.bComplete == 1 ||
(TestCondition.WorldHint == "" && TestCondition.WorldTex == none) ||
TestCondition.Conditionloc == none ||
TestCondition.ConditionLoc.Location == Vect(0,0,0) ||
(TestCondition.ConditionLoc.bHidden && !TestCondition.bIgnoreWorldHidden) ||
(KF_BreakerBoxNPC(TestCondition.ConditionLoc) != none &&
!KF_BreakerBoxNPC(TestCondition.ConditionLoc).bActive) )
{
return false;
}
break;
case "Screen" :
if(TestCondition.HintStyle == 0)
{
return false;
}
break;
}
return TestCondition.ObjOwner == RenderObj.name;
}
/* Renders Objective Hints on the Players HUD telling him what his objective is and where to find it */
simulated final function DrawObjectiveHints(Canvas C, KF_StoryObjective CurrentObj, float FadeValue)
{
local float SuccessWidth, SuccessHeight;
local string ObjectiveHint;
local float PosX,PosY;
local float BGWidth,BGHeight;
local float ScalingValue;
local int i;
local float WidestX;
local float HeaderX,HeaderY;
local float DataX,DataY;
local int FontSize;
local int DataFontSize;
local float BarWidth;
local float WidestDataX;
local int NumScreenConditions;
local float HighlightWidth;
local float HighlightFadeVal;
local float SecondaryBarWidth;
local float HighlightFadeTime;
local float OpacityModifier;
local float WidestStringX;
local float BarHeightMultiplier;
local string HintString;
local Material BGTex;
local float HeaderScale;
local Material CheckboxMat;
local float CheckboxScale;
local float CheckBoxSize;
local float OldXPos;
local float BarBGWidth,StrikeThroughWidth;
BarHeightMultiplier = 1.25f;
HeaderScale = 0.5;
CheckBoxScale = 1.5;
if ( PlayerOwner != none && KFGRI != none && FadeValue > 0 && !bShowScoreboard)
{
if ( CurrentObj != none && ConditionHints.length > 0 )
{
/* Coordinates to start drawing at */
PosX = C.SizeX * CurrentObj.HUD_ScreenPosition.Horizontal; //(C.SizeX / 64.f) ;
PosY = C.SizeY * CurrentObj.HUD_ScreenPosition.Vertical; //0 ;
/*================ SIZING PASS ====================================================================
==================================================================================================*/
ScalingValue = CurrentObj.HUD_Background.Background_Scale ;
FontSize = ResolveFontResolution(C,CurrentObj.HUD_Header.Header_Scale);
DataFontSize = FontSize;
/* Size up the Objective Header text */
/* Header uses a massive font, gotta scale things */
C.FontScaleX = HeaderScale;
C.FontScaleY = HeaderScale;
C.Font = GetWaitingFontSizeIndex(C,CurrentObj.HUD_Header.Header_Scale);//LoadFont(FontSize);
C.TextSize(CurrentObj.HUD_Header.Header_Text,HeaderX,HeaderY);
WidestX = FMax(WidestX,HeaderX);
WidestStringX = WidestX;
HeaderY *= BarHeightMultiplier;
C.FontScaleX = 1.f;
C.FontScaleY = 1.f;
/* Now Size up the conditions */
for(i = 0 ; i < ConditionHints.Length ; i ++)
{
if(!ShouldRenderCondition(ConditionHints[i],"Screen"))
{
ConditionHints[i].ProgBarheight = 0 ;
continue;
}
/* Check that there's actually something to display */
if(ConditionHints[i].HintStyle > 0 && ConditionHints[i].DataString != "")
{
NumScreenConditions ++ ;
}
FontSize = ResolveFontResolution(C,ConditionHints[i].FontScale);
DataFontSize = FontSize;
C.Font = LoadFont(FontSize);
ObjectiveHint = ConditionHints[i].DataString ;
C.StrLen(ObjectiveHint, SuccessWidth, SuccessHeight);
SuccessWidth *= ScalingValue;
SuccessHeight *= ScalingValue;
CheckBoxSize = (FMax(SuccessHeight,DataY)* BarHeightMultiplier) * CheckboxScale;
if(Conditionhints[i].bShowCheckBox)
{
SuccessWidth += CheckBoxSize;
}
ConditionHints[i].HintWidth = SuccessWidth;
ConditionHints[i].HintHeight = SuccessHeight;
WidestX = FMax(WidestX,SuccessWidth);
WidestStringX = WidestX;
// retrieve scaling for data string
C.StrLen(ConditionHints[i].DataString,DataX,DataY);
DataX *= ScalingValue;
DataY *= ScalingValue;
/* Since the Data string size affects the background scale we never want it to shrink */
if(DataX > ConditionHints[i].WidestDataX)
{
ConditionHints[i].WidestDataX = DataX;
}
WidestDataX = FMax(DataX,WidestDataX);
ConditionHints[i].ProgBarHeight = FMax(SuccessHeight,DataY)* BarHeightMultiplier ;
}
WidestX += C.ClipX / 64.f;
if(NumScreenConditions == 0 && CurrentObj.HUD_Header.Header_Text == "")
{
return;
}
if(CurrentObj.HUD_Background.Background_AspectRatio < 2)
{
BGHeight += HeaderY;
}
for(i = 0 ; i < ConditionHints.length ; i ++)
{
if(CurrentObj.HUD_Background.Background_AspectRatio < 2)
{
BGHeight += ConditionHints[i].ProgBarheight ;
}
}
BGHeight += CurrentObj.HUD_Background.Background_Padding ;
if(CurrentObj.HUD_Background.Background_AspectRatio < 2)
{
BGWidth = WidestX + (CurrentObj.HUD_Background.Background_Padding );
}
else
{
BGWidth += CurrentObj.HUD_Background.Background_Padding ;
}
if(CurrentObj.HUD_BackGround.Background_Texture != none)
{
if(CurrentObj.HUD_Background.Background_AspectRatio == Aspect_FromTexture)
{
BGWidth = CurrentObj.HUD_Background.Background_Texture.MaterialUSize() ;
BGHeight = CurrentObj.HUD_Background.Background_Texture.MaterialVSize() ;
}
}
BGHeight *= ScalingValue ;
BGWidth *= ScalingValue ;
// clamp - make sure it's not travelling off screen
PosX = FClamp(PosX-BGWidth/2,0,C.SizeX - BGWidth);
PosY = FClamp(PosY,0,C.SizeY - BGHeight);
/*================ DRAWING PASS ====================================================================
==================================================================================================*/
/* Draw Background first */
OpacityModifier = 1.f;
C.Style = ERenderStyle.STY_Alpha;
C.DrawColor = WhiteColor;
C.DrawColor.A = (KFHUDAlpha * FadeValue) * OpacityModifier ;
if(!bCollapseConditions)
{
BGTex = CurrentObj.HUD_Background.Background_Texture;
}
else
{
BGTex = CurrentObj.HUD_Background.Background_Texture_Collapsed ;
}
if(BGTex != none)
{
C.SetPos(PosX ,PosY);
if(CurrentObj.HUD_Background.Background_AspectRatio > 0)
{
C.DrawTileScaled(BGTex, BGWidth/BGTex.MaterialUSize() ,BGHeight / BGTex.MaterialVSize());
}
else
{
C.DrawTileStretched(BGTex, BGWidth ,BGHeight);
}
}
if(bCollapseConditions)
{
return;
}
/* Try to center justify everything */
PosX = FClamp(PosX+CurrentObj.HUD_Background.BackGround_Offset.Horizontal,0,C.SizeX - BGWidth);
PosY += CurrentObj.HUD_BackGround.BackGround_Offset.Vertical ;
/* Now draw objective header title */
C.FontScaleX = HeaderScale;
C.FontScaleY = HeaderScale;
C.Font = GetWaitingFontSizeIndex(C,CurrentObj.HUD_Header.Header_Scale);//
C.DrawColor = CurrentObj.HUD_Header.Header_Color;
C.DrawColor.A = (KFHUDAlpha * FadeValue) * OpacityModifier ;
C.SetPos(PosX - (HeaderX * 0.5) + (0.5*BGWidth),PosY );
C.DrawText(CurrentObj.HUD_Header.Header_Text,true);
C.FontScaleX = 1.f;
C.FontScaleY = 1.f;
/* Shift everything down so it fits under the header */
PosY += HeaderY * 1.1;
/* Next draw the conditions - starting with the backplates and ending with the strings */
for(i = 0 ; i < ConditionHints.length ; i ++)
{
if(!ShouldRenderCondition(ConditionHints[i],"Screen"))
{
continue;
}
OpacityModifier = 1.f ;
/* Shift it to the right abit if we're rendering a Checkbox */
OldXPos = PosX;
if(Conditionhints[i].bShowCheckBox)
{
PosX += Conditionhints[i].ProgBarheight * CheckboxScale;
}
FontSize = ResolveFontResolution(C,ConditionHints[i].FontScale);
C.Font = LoadFont(FontSize);
/* Draw progreess bar & backdrop */
C.StrLen(ConditionHints[i].DataString,SuccessWidth,SuccessHeight);
SuccessWidth *= ScalingValue;
SuccessHeight *= ScalingValue;
C.DrawColor = ConditionHints[i].ProgressBar_Clr ;
StrikeThroughWidth = WidestX;
BarBGWidth = WidestX;
if(Conditionhints[i].bShowCheckBox)
{
CheckBoxSize = ConditionHints[i].ProgBarheight * CheckboxScale;
BarBGWidth -= CheckboxSize;
StrikeThroughWidth -= CheckBoxSize;
}
// Render a strike-through if requested. (defaults to on)
if(ConditionHints[i].bShowStrikeThrough &&
GetCheckBoxMaterialFor(ConditionHints[i]) != none )
{
OpacityModifier = 0.5f ;
C.DrawColor.A = (KFHUDAlpha * FadeValue) * OpacityModifier ;
C.SetPos(PosX + (BGWidth-WidestX)/2 , PosY);
C.DrawTileStretched(Texture'KFStoryGame_Tex.HUD.Objective_Strikethrough', StrikeThroughWidth,ConditionHints[i].ProgbarHeight );
}
/* Progess Bar Background Material */
if((ConditionHints[i].HintStyle == 1 ||
ConditionHints[i].HintStyle >= 3) &&
ConditionHints[i].Material_ProgressBarBG != none)
{
C.DrawColor.A = ((ConditionHints[i].ProgressBar_Clr.A * FadeValue) * (KFHUDAlpha/255.f)) * OpacityModifier ;
C.SetPos(PosX + (BGWidth-WidestX)/2, PosY );
C.DrawTileStretched(ConditionHints[i].Material_ProgressBarBG, BarBGWidth,ConditionHints[i].ProgBarheight );
}
/* Progess Bar Fill Material */
if((ConditionHints[i].HintStyle == 1 ||
ConditionHints[i].HintStyle >= 3) &&
ConditionHints[i].Material_ProgressBarFill != none)
{
if(ConditionHints[i].DisplayStyle == 0)
{
BarWidth = WidestX * ConditionHints[i].ProgressPct ;
}
else
{
BarWidth = WidestX * (1.f-ConditionHints[i].ProgressPct) ;
}
if(Conditionhints[i].bShowCheckBox)
{
CheckBoxSize = ConditionHints[i].ProgBarheight * CheckboxScale;
BarWidth = FMax(BarWidth - CheckBoxSize,0.f);
}
C.DrawColor.A = ((ConditionHints[i].ProgressBar_Clr.A * FadeValue) * (KFHUDAlpha/255.f)) * OpacityModifier ;
C.SetPos(PosX + (BGWidth-WidestX)/2, PosY );
C.DrawTileStretched(ConditionHints[i].Material_ProgressBarFill, BarWidth,ConditionHints[i].ProgBarheight);
/* Fill Highlight */
if(ConditionHints[i].DisplayStyle == 1)
{
SecondaryBarWidth = FMax(1.f-(WidestX * (ConditionHints[i].ProgressPct - ConditionHints[i].LastProgressVal)),0.f) ;
HighlightFadeTime = FClamp((ConditionHints[i].ProgressPct - ConditionHints[i].LastProgressVal) * 3.f,0.5f,2.f);
HighlightFadeVal = FClamp( 1.f - ((Level.TimeSeconds - ConditionHints[i].LastProgressUpdateTime ) / HighlightFadeTime), 0.f,1.f);
C.DrawColor.A = (255 * (KFHudAlpha/255.f) * FadeValue * HighlightFadeVal) * OpacityModifier ;
C.SetPos(PosX + BarWidth - (SecondaryBarWidth), PosY);
C.DrawTileStretched(ConditionHints[i].Material_ProgressBarFill, SecondaryBarWidth,ConditionHints[i].ProgBarHeight);
C.DrawColor = WhiteColor;
C.DrawColor.A = (255 * (KFHudAlpha/255.f) * FadeValue * HighlightFadeVal) * OpacityModifier ;
HighlightWidth = BarWidth * 0.1;
C.SetPos(PosX - (HighlightWidth) + (BGWidth-WidestX)/2 + BarWidth , PosY);
C.DrawTileStretched(Texture 'KFStoryGame_Tex.HUD.ProgressBar_Higlight', HighlightWidth,ConditionHints[i].ProgBarheight);
C.DrawColor = ConditionHints[i].ProgressBar_Clr ;
C.DrawColor.A = ((ConditionHints[i].ProgressBar_Clr.A * FadeValue) * (KFHUDAlpha/255.f)) * OpacityModifier ;
}
}
/* Finally, Draw the condition Hint strings & DataStrings.. */
if(ConditionHints[i].HintStyle > 1 )
{
/* Make sure the hint string isn't so large it overlaps the data string
while( ConditionHints[i].DataString != "" &&
PosX + (WidestX * 0.05) + ConditionHints[i].HintWidth >= (ClampedX-(DataX/2)) &&
FontSize < arraycount(FontArrayFonts)-1)
{
FontSize ++ ;
C.Font = LoadFont(FontSize);
C.StrLen(ConditionHints[i].DataString,SuccessWidth,SuccessHeight);
SuccessWidth *= ScalingValue;
SuccessHeight *= ScalingValue;
ConditionHints[i].HintWidth = SuccessWidth;
} */
if(ConditionHints[i].DataString != "")
{
C.Font = LoadFont(FontSize);
HintString = ConditionHints[i].DataString;
C.DrawColor = ConditionHints[i].ProgressBar_Clr;
C.DrawColor.A = ((ConditionHints[i].ProgressBar_Clr.A * FadeValue) * (KFHUDAlpha/255.f)) * OpacityModifier ;
C.SetPos(PosX + BGWidth/2 - (ConditionHints[i].HintWidth/2), PosY + ConditionHints[i].HintHeight/4 );
C.DrawText(HintString,true);
}
if(ConditionHints[i].bShowCheckBox)
{
C.SetPos(PosX + (BGWidth-WidestX)/2 - (ConditionHints[i].ProgBarheight * 1.1) , PosY );
C.DrawColor.A = ((ConditionHints[i].ProgressBar_Clr.A * FadeValue) * (KFHUDAlpha/255.f)) ;
/* Show a Tick next to success conditions that were completed , or failure conditions that were *not* completed
at the time the objective was successfully finished */
C.DrawTileScaled( Texture 'KFStoryGame_Tex.HUD.ObjInComplete_Ico', ConditionHints[i].ProgBarheight/64.f,ConditionHints[i].ProgBarHeight/64.f);
CheckBoxMat = GetCheckBoxMaterialFor(ConditionHints[i]);
if(CheckBoxMat != none)
{
C.SetPos(PosX + (BGWidth-WidestX)/2 - (ConditionHints[i].ProgBarheight * 1.1) , PosY - ((ConditionHints[i].ProgBarHeight*CheckBoxScale)/4) );
C.DrawTileScaled(CheckBoxMat, (ConditionHints[i].ProgBarheight*1.5)/64.f,(ConditionHints[i].ProgBarHeight*CheckboxScale)/64.f);
}
}
}
if(ConditionHints[i].HintStyle <= 3)
{
PosY += ConditionHints[i].ProgBarheight * 1.25;
}
PosX = OldXPos;
}
}
}
}
simulated function Material GetCheckBoxMaterialFor(SConditionHint Testcondition)
{
/* Failure conditions */
if(TestCondition.ConditionType == 0)
{
if(Testcondition.bComplete == 1)
{
return Texture 'KFStoryGame_Tex.HUD.ObjFailed' ;
}
else
{
if(RenderObj.bCompleted)
{
return Texture 'KFStoryGame_Tex.HUD.ObjComplete_Ico';
}
}
}
else // Success , optional
{
if(Testcondition.bComplete == 1)
{
return Texture 'KFStoryGame_Tex.HUD.ObjComplete_Ico' ;
}
else
{
if(RenderObj.bCompleted)
{
return Texture 'KFStoryGame_Tex.HUD.ObjFailed' ;
}
}
}
return none;
}
/* Dialogue rendering ====================================================================================
=========================================================================================================*/
simulated function ApplyDialogueStylePresets(KF_DialogueSpot NewDlg, int DlgIndex)
{
if(HUDStylemanager != none && HUDStylemanager.StylePreset.Dialogue.bOverride)
{
NewDlg.Dialogues[DlgIndex].Display.Screen_BGMaterial = HUDStyleManager.StylePreset.Dialogue.Dialogue_Box.Screen_BGMaterial;
NewDlg.Dialogues[DlgIndex].Display.Screen_Position = HUDStyleManager.StylePreset.Dialogue.Dialogue_Box.Screen_Position;
NewDlg.Dialogues[DlgIndex].Display.Screen_Scaling = HUDStyleManager.StylePreset.Dialogue.Dialogue_Box.Screen_Scaling;
}
}
/* adds a new dialogue entry to the cue - Dialogue is rendered in order of addition */
simulated function AddDialogue(name DialogueActorName, int DlgIndex, float DisplayDuration)
{
local int Index,ExistingIndex;
local KF_DialogueSpot NewDlg;
NewDlg = FindDialogueActor(DialogueActorName);
if(NewDlg == none)
{
log("Warning - could not find Dialogue Actor of name : "@DialogueActorName@" Aborting HUD Render. ");
return;
}
if(!FindExistingDialogue(NewDlg.Dialogues[DlgIndex].Display.Dialogue_text,ExistingIndex))
{
Index = Dialogues.length ;
Dialogues.length = Index + 1;
CurrentDlgIndex = Index;
ApplyDialogueStylePresets(NewDlg,DlgIndex);
Dialogues[Index].Message = NewDlg.Dialogues[DlgIndex].Display.Dialogue_Text;
Dialogues[Index].Speaker = NewDlg.Dialogues[DlgIndex].Display.Dialogue_Header;
Dialogues[Index].Portrait = NewDlg.Dialogues[DlgIndex].Display.Portrait_Material;
Dialogues[Index].Opacity = KFHUDAlpha;
Dialogues[Index].Duration = DisplayDuration;
Dialogues[Index].ScreenPos = NewDlg.Dialogues[DlgIndex].Display.Screen_Position;
Dialogues[Index].ScreenAlignment = NewDlg.Dialogues[DlgIndex].Display.ScreenAlignment;
Dialogues[Index].ScreenScaleStyle = NewDlg.Dialogues[DlgIndex].Display.Screen_Scaling;
Dialogues[Index].BackGroundMat = NewDlg.Dialogues[DlgIndex].Display.Screen_BGMaterial;
Dialogues[Index].BinkPortrait = new class'LobbyMenuAd';
Dialogues[Index].BinkPortrait.MenuMovie = new class'Movie';
Dialogues[Index].BinkPortrait.MenuMovie.Callbacks = Dialogues[Index].BinkPortrait;
Dialogues[Index].BinkPortrait.MenuMovie.Open("../Movies/"$NewDlg.Dialogues[DlgIndex].Display.Portrait_BinkMovie$".bik");
Dialogues[Index].BinkPortrait.MenuMovie.Play(true);
}
else
{
CurrentDlgIndex = ExistingIndex;
Dialogues[ExistingIndex].Duration = DisplayDuration;
}
}
/* Main drawing pump for Story mode Dialogue system */
simulated function DrawDialogue(Canvas C)
{
local float HeaderX,HeaderY;
local float BackgroundOffset;
local int i;
local AbsoluteCoordsInfo coords;
local float DisplayTimeRemaining;
local float XL,YL;
local float OpacityVal;
local float BGSizeX,BGSizeY;
local float PortraitSizeX,PortraitSizeY;
local float PortraitAspect;
local Material DlgPortrait;
local Material DlgBackGroundMaterial;
if(CurrentDlgIndex >= Dialogues.length)
{
return;
}
DisplayTimeRemaining = Dialogues[CurrentDlgIndex].Duration - (Level.TimeSeconds - Dialogues[CurrentDlgIndex].FirstDisplayedTime) ;
if(DisplayTimeRemaining <= 0)
{
Dialogues[CurrentDlgIndex].Opacity = Max(Dialogues[CurrentDlgIndex].Opacity - 2,0);
if(Dialogues[CurrentDlgIndex].Opacity == 0)
{
// remove me from the cue and move on to the next!
Dialogues.Remove(CurrentDlgIndex,1);
}
}
if(CurrentDlgIndex >= Dialogues.length)
{
return;
}
OpacityVal = Dialogues[CurrentDlgIndex].Opacity ;
if(OpacityVal > 0)
{
if(!Dialogues[CurrentDlgIndex].bFirstDisplay)
{
Dialogues[CurrentDlgIndex].bFirstDisplay = true;
Dialogues[CurrentDlgIndex].FirstDisplayedTime = Level.TimeSeconds;
}
if(!Dialogues[CurrentDlgIndex].bWrapped)
{
CalculateDialogueWrappingData(C);
}
C.Font = GetFontSizeIndex(C,-2);
C.StrLen(Dialogues[CurrentDlgIndex].Speaker,HeaderX,HeaderY);
C.SetPos(0, 0);
// Set proper rendering style
C.Style = ERenderStyle.STY_Alpha;
// Calculate background offset in relation to text
backgroundOffset = DialogueBackground.PosY * C.ClipY;
// Calculate absolute drawing coordinates (mostly for text widget)
DialogueCoords.X = Dialogues[CurrentDlgIndex].ScreenPos.Horizontal;
DialogueCoords.Y = Dialogues[CurrentDlgIndex].ScreenPos.Vertical;
coords.PosX = DialogueCoords.X * C.ClipX;
coords.PosY = DialogueCoords.Y * C.ClipY;
coords.height = DialogueCoords.YL * C.ClipY;
BGSizeY = coords.height + backgroundOffset * 2;
DlgPortrait = Dialogues[CurrentDlgIndex].Portrait;
if(DlgPortrait != none)
{
PortraitAspect = float(DlgPortrait.MaterialUSize()) / float(DlgPortrait.MaterialVsize()) ;
// make sure the protrait is scaled to the background widget
PortraitSizeY = FMin(DlgPortrait.MaterialVsize(),BGSizeY);
PortraitSizeX = PortraitSizeY * PortraitAspect;
}
coords.width = (DialogueCoords.XL * C.ClipX) ;
// Draw the background
C.DrawColor = WhiteColor;
C.DrawColor.A = OpacityVal * (255.f/KFHUDAlpha) ;
BGSizeX = (coords.width + backgroundOffset * 2) ;
coords.PosX -= PortraitSizeX/2;
coords.PosY -= BGSizeY/2;
/* Clamp drawing positions so the dialogue never goes offscreen */
coords.PosX = FClamp(coords.PosX,FMax(coords.PosX,PortraitSizeX),C.ClipX - BGSizeX);
coords.PosY = FClamp(coords.PosY,0,C.ClipY - BGSizeY);
C.SetPos(coords.PosX , coords.PosY );
DlgBackGroundMaterial = Dialogues[CurrentDlgIndex].BackGroundMat;
if(DlgBackGroundMaterial == none)
{
DlgBackGroundMaterial = Texture'KillingFloorHUD.HUD.Hud_Box_128x64';
}
if(Dialogues[CurrentDlgIndex].ScreenScaleStyle == Stretched)
{
C.DrawTileStretched(DlgBackGroundMaterial, BGSizeX,BGSizeY);
}
else
{
C.DrawTileScaled(DlgBackGroundMaterial, BGSizeX/DlgBackGroundMaterial.MaterialUSize(),BGSizeY/DlgBackGroundMaterial.MaterialVSize());
}
// Draw title
C.Font = GetFontSizeIndex(C,-2);
DialogueTitleWidget.text = Dialogues[CurrentDlgIndex].Speaker ;
DialogueTitleWidget.Tints[0].A = OpacityVal;
DialogueTitleWidget.Tints[1].A = OpacityVal;
DrawTextWidgetClipped(C, DialogueTitleWidget, coords, XL, YL);
// Draw each line individually
DialogueTextWidget.OffsetY = (YL * 1.5) + DialogueTitleWidget.OffsetY ;
// C.Font = getSmallMenuFont(C);
YL = 0;
for (i = 0; i < WrappedDialogue.Length; i++)
{
DialogueTextWidget.text = WrappedDialogue[i];
DialogueTextWidget.Tints[0].A = OpacityVal;
DialogueTextWidget.Tints[1].A = OpacityVal;
if (WrappedDialogue[i] != "")
DrawTextWidgetClipped(C, DialogueTextWidget, coords, XL, YL);
else
YL /= 2;
DialogueTextWidget.OffsetY += YL;
}
//Draw Portraits . (Bink if available, or else just regular material)
if(Dialogues[CurrentDlgIndex].BinkPortrait != none &&
Dialogues[CurrentDlgIndex].BinkPortrait.MenuMovie != none &&
Dialogues[CurrentDlgIndex].BinkPortrait.MenuMovie.IsPlaying())
{
C.Style = ERenderStyle.STY_Normal;
C.DrawColor = WhiteColor;
C.DrawColor.A = OpacityVal * (255.f/KFHUDAlpha) ;
C.SetPos(coords.PosX - PortraitSizeX, coords.PosY );
C.DrawTileScaled(Dialogues[CurrentDlgIndex].BinkPortrait.MenuMovie, PortraitSizeX/Dialogues[CurrentDlgIndex].BinkPortrait.MenuMovie.GetWidth(),PortraitSizeY/Dialogues[CurrentDlgIndex].BinkPortrait.MenuMovie.GetHeight());
}
else
{
DlgPortrait = Dialogues[CurrentDlgIndex].Portrait;
if(DlgPortrait != none)
{
C.Style = ERenderStyle.STY_Alpha;
C.DrawColor = WhiteColor;
C.DrawColor.A = OpacityVal * (255.f/KFHUDAlpha) ;
C.SetPos(coords.PosX - PortraitSizeX, coords.PosY );
C.DrawTileScaled(DlgPortrait,PortraitSizeX / DlgPortrait.MaterialUSize(), PortraitSizeY / DlgPortrait.MaterialVSize());
}
}
}
}
simulated function bool FindExistingDialogue(string text, optional out int Index)
{
local int i;
for(i = 0 ; i < Dialogues.length ; i ++)
{
if(Dialogues[i].Message == text)
{
Index = i;
return true;
}
}
return false;
}
// This function is used to calculate how the Dialogue data should
// be wrapped.
function CalculateDialogueWrappingData(Canvas Canvas)
{
local float XL, YL, XL2, YL2;
local float minWidth, wrapWidth, totalYL;
local int i, count;
// First calculate minimum message width (e.g. the width of the
// title string)
Canvas.Font = GetFontSizeIndex(Canvas,-2);
Canvas.SetPos(0, 0);
Canvas.TextSize(Dialogues[CurrentDlgIndex].Speaker, minWidth, totalYL);
if (minWidth < 10.0)
minWidth = 10.0;
totalYL += totalYL / 2;
// Calculate max width of text string (or perhaps we should just use full screen width?)
Canvas.Font = getSmallMenuFont(Canvas);
Canvas.TextSize(Dialogues[CurrentDlgIndex].Message, XL, YL);
// Starting with full string width, progressively reduce width until the ratio of the height
// to the width is smaller than HintDesiredAspectRatio
wrapWidth = XL;
for (count = 0; count < 25; count++) // max 25 iterations
{
// Wrap text
WrappedDialogue.Length = 0;
Canvas.WrapStringToArray(Dialogues[CurrentDlgIndex].Message, WrappedDialogue, wrapWidth, "|");
// Calculate current width & height
XL = 0; YL = 0;
XL2 = 0; YL2 = 0;
for (i = 0; i < WrappedDialogue.Length; i++)
{
if (WrappedDialogue[i] != "")
Canvas.TextSize(WrappedDialogue[i], XL, YL);
else
YL /= 2;
if (XL > XL2)
XL2 = XL;
YL2 += YL;
}
// Check if current width is too small
if (XL2 < minWidth)
{
wrapWidth = minWidth;
break;
}
// Calculate ratio
if (YL2 < 1)
YL = 1;
else
YL = XL2 / YL2;
// Check if we should accept this wrap width
if (YL < HintDesiredAspectRatio)
{
wrapWidth = XL2;
break;
}
// Else, reduce currentWidth and try again.
wrapWidth *= 0.80;
}
// Wrap text to array
WrappedDialogue.Length = 0;
Canvas.SetPos(0, 0);
Canvas.WrapStringToArray(Dialogues[CurrentDlgIndex].Message, WrappedDialogue, wrapWidth, "|");
// Calculate total width and height
wrapWidth = minWidth;
XL = 0; YL = 0;
for (i = 0; i < WrappedDialogue.Length; i++)
{
Canvas.SetPos(0, 0);
if (WrappedDialogue[i] != "")
Canvas.TextSize(WrappedDialogue[i], XL, YL);
else
YL /= 2;
if (XL > wrapWidth)
wrapWidth = XL;
totalYL += YL;
//log("Wrapped line #" $ i $ ": '" $ WrappedDialogue[i] $"'");
}
// for safety
if (wrapWidth < 10)
wrapWidth = 10;
if (totalYL < 10)
totalYL = 10;
// Calculate target relative coordinates
DialogueCoords.XL = wrapWidth / Canvas.ClipX;
DialogueCoords.YL = totalYL / Canvas.ClipY;
DialogueCoords.X = default.DialogueCoords.X + DialogueCoords.XL * default.DialogueCoords.XL;
DialogueCoords.Y = default.DialogueCoords.Y + DialogueCoords.YL * default.DialogueCoords.YL;
Dialogues[CurrentDlgIndex].bWrapped = true;
}
/* Modified to allow story HUDs to render different end game screens */
simulated function DrawEndGameHUD(Canvas C, bool bVictory)
{
local float Scalar;
local Material VictoryMaterial,DefeatMaterial;
C.DrawColor.A = 255;
C.DrawColor.R = 255;
C.DrawColor.G = 255;
C.DrawColor.B = 255;
Scalar = FClamp(C.ClipY, 320, 1024);
C.CurX = C.ClipX / 2 - Scalar / 2;
C.CurY = C.ClipY / 2 - Scalar / 2;
C.Style = ERenderStyle.STY_Alpha;
Victorymaterial = SGRI.GetVictorySplashMaterial();
DefeatMaterial = SGRI.GetDefeatSplashMaterial();
if ( bVictory )
{
MyColorMod.Material = VictoryMaterial;
}
else
{
MyColorMod.Material = DefeatMaterial;
}
if ( EndGameHUDTime >= 1 )
{
MyColorMod.Color.A = 255;
}
else
{
MyColorMod.Color.A = EndGameHUDTime * 255.f;
}
C.DrawTile(MyColorMod, Scalar, Scalar, 0, 0, 1024, 1024);
if ( bShowScoreBoard && ScoreBoard != None )
{
ScoreBoard.DrawScoreboard(C);
}
}
simulated function Message(PlayerReplicationInfo PRI, coerce string Msg, name MsgType)
{
local Class<LocalMessage> LocalMessageClass;
if(MsgType == 'Msg_CashReward')
{
LocalMessageClass = class'Msg_CashReward';
AddTextMessage(Msg, LocalMessageClass, PRI);
}
else
{
Super.Message(PRI,Msg,MsgType);
}
}
defaultproperties
{
DialogueCoords=(X=0.5,Y=0.6,XL=-1.0,YL=0)
DialogueBackground=(WidgetTexture=Texture'KF_InterfaceArt_tex.Menu.Med_border_SlightTransparent',PosX=0,PosY=0.02,TextureCoords=(X1=0,Y1=0,X2=0,Y2=0),TextureScale=0.0,DrawPivot=DP_MiddleMiddle,OffsetX=0,OffsetY=0,ScaleMode=SM_Left,Scale=1.0,RenderStyle=STY_Alpha,Tints[0]=(R=255,G=255,B=255,A=192),Tints[1]=(R=255,G=255,B=255,A=192))
DialogueTitleWidget=(Text="",PosX=0,PosY=0,WrapWidth=0,WrapHeight=1,OffsetX=15,OffsetY=15,DrawPivot=DP_UpperLeft,RenderStyle=STY_Alpha,Tints[0]=(R=255,G=255,B=255,A=255),Tints[1]=(R=255,G=255,B=255,A=255),bDrawShadow=true)
DialogueTextWidget=(Text="",PosX=0,PosY=0,WrapWidth=0,WrapHeight=1,OffsetX=15,OffsetY=45,DrawPivot=DP_UpperLeft,RenderStyle=STY_Alpha,Tints[0]=(R=255,G=255,B=255,A=255),Tints[1]=(R=255,G=255,B=255,A=255),bDrawShadow=false)
ObjFadeOutTime = 0.5f
ObjFadeInTime = 0.5f
ObjFadeOutDelay = 1.f
StoryIconOffsetX=20;
StoryIconOffsetY=50;
bShowObjectives = true
}