1
0
KF2-Dev-Scripts/KFGame/Classes/KFDoorMarker.uc
2020-12-13 18:01:13 +03:00

199 lines
6.1 KiB
Ucode

//=============================================================================
// KFDoorMarker
//=============================================================================
// Base KF2 NavigationPoint used to mark door locations
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class KFDoorMarker extends DoorMarker
native(Waypoint)
hidecategories(DoorMarker);
var(KF2) KFDoorActor MyKFDoor;
/** Optionally override the distance at which my door will be considered reached by NPCs */
var(KF2) float AdjustedReachThreshold;
/** The computed cost when this door is welded */
var transient int ExtraCostWhenWelded;
cpptext
{
virtual UClass* GetReachSpecClass( ANavigationPoint* Nav, UClass* DefaultReachSpecClass );
// Overriding because DoorMarker returns MyKFDoor which is an InterpActor
virtual AActor* AssociatedLevelGeometry();
virtual UBOOL HasAssociatedLevelGeometry(AActor *Other);
#if WITH_EDITOR
virtual UBOOL IsNecessaryForPath()
{
return true;
}
virtual UBOOL CanConnectTo(ANavigationPoint* Nav, UBOOL bCheckDistance);
#endif
virtual void PrePath();
virtual void PostPath();
virtual void FindBase();
#if WITH_EDITOR
virtual void CheckForErrors();
#endif
}
event bool SuggestMovePreparation( Pawn Other )
{
local KFPawn_Monster KFPM;
local int count;
`AILog_Ext( GetFuncName()$"() "$self$" called for "$Other$" Dist: "$VSize(Location - Other.Location), 'Doors', KFPawn(Other).MyKFAIC );
if( MyKFDoor != none && !MyKFDoor.IsCompletelyOpen() && MyKFDoor.WeldIntegrity > 0 )
{
// @Todo We might want to make this check from the position of the marker without the visible check
foreach VisibleCollidingActors( class'KFPawn_Monster', KFPM, 220.f, Other.Location,,, true )
{
// Stop trying to attack the door if another zed's attacking it, as this event call was probably from adjust around code caused by bumping into the door
if( KFPM != Other && KFPM.IsAliveAndWell() && VSizeSq2D(KFPM.Location - Location) < VSizeSq2D(Other.Location - Location) &&
KFPM.MyKFAIC.DoorEnemy != none && KFPM.MyKFAIC.DoorEnemy == MyKFDoor )
{
Count++;
}
}
// Only allow up to 5 attackers
if( Count > 5 )
{
`AILog_Ext( GetFuncName()$"() "$self$" - telling "$Other$" to wait for "$MyKFDoor$" to open", 'Doors', KFPawn(Other).MyKFAIC );
Other.ZeroMovementVariables();
//DrawDebugSphere( Other.Location, 32, 8, 255, 0, 0, true );
KFPawn_Monster(Other).MyKFAIC.WaitForDoor( MyKFDoor );
return true;
}
}
return false;
}
function MoverOpened()
{
bBlocked = (!bInitiallyClosed && bBlockedWhenClosed);
bDoorOpen = bInitiallyClosed;
WorldInfo.Game.NotifyNavigationChanged(self);
}
function MoverClosed()
{
bBlocked = (bInitiallyClosed && bBlockedWhenClosed);
bDoorOpen = !bInitiallyClosed;
WorldInfo.Game.NotifyNavigationChanged(self);
}
/** Updates the pathing cost based on weld integrity, number of attackers and number queued */
function UpdatePathingCost( int AttackerCount, int QueuedCount )
{
local float IntegrityPct;
if( MyKFDoor.WeldIntegrity > 0 )
{
IntegrityPct = float(MyKFDoor.WeldIntegrity) / float(MyKFDoor.MaxWeldIntegrity);
// If there are simply too many AI waiting on this door, and it's heavily welded, just skip it
if( IntegrityPct > 0.75f && AttackerCount + QueuedCount > 10 )
{
ExtraCostWhenWelded = 100000;
return;
}
// Initialize at 1000
ExtraCostWhenWelded = 1000;
// Add cost based on the strength of the weld (10-1000)
ExtraCostWhenWelded += int( IntegrityPct * 100.f ) * 10;
// Add cost based on the number of attackers (0-500)
ExtraCostWhenWelded += Min( AttackerCount * 100, 500 );
// Add cost based on the number of queued AI (0-1000)
ExtraCostWhenWelded += Min( QueuedCount * 100, 1000 );
}
else
{
// Reset to base cost
ExtraCostWhenWelded = 1000;
}
//`log("updating door pathing cost:"@extracostwhenwelded);
}
function bool ProceedWithMove(Pawn Other)
{
local KFAIController KFAIC;
`if(`__TW_PATHFINDING_)
if( KFPawn(Other) != none && !KFPawn(Other).IsHumanControlled() )
{
`AILog_Ext( GetFuncName()$" "$self$" for "$Other, 'Doors', KFPawn(Other).MyKFAIC );
}
`endif
KFAIC = KFAIController( Other.Controller );
if( KFAIC != none && KFAIC.PendingDoor != none && (bWaitUntilCompletelyOpened && KFAIC.PendingDoor.IsCompletelyOpen()) ||
(!bWaitUntilCompletelyOpened && (KFAIC.PendingDoor.bIsDoorOpen || KFAIC.PendingDoor.bIsDestroyed)) )
{
return true;
}
if( MyKFDoor != none && (bWaitUntilCompletelyOpened && MyKFDoor.IsCompletelyOpen()) ||
(!bWaitUntilCompletelyOpened && (MyKFDoor.bIsDoorOpen || MyKFDoor.bIsDestroyed)) )
{
return true;
}
if( Other.Controller != none && KFAIController( Other.Controller ) != none &&
bWaitUntilCompletelyOpened && MyKFDoor != none )
{
KFAIController( Other.Controller ).WaitForDoor( MyKFDoor );
}
return false;
}
event Actor SpecialHandling( Pawn Other )
{
`AILog_Ext( GetFuncName()$"() "$self$" SpecialHandling event called for "$Other, 'Doors', KFPawn(Other).MyKFAIC );
if ( MyKFDoor == None || MyKFDoor.IsCompletelyOpen() /*|| VSize( Location - Other.Location ) > 200.f*/ )
{
return self;
}
if( KFPawn(Other) != none && !KFPawn(Other).IsHumanControlled() )
{
`AILog_Ext( GetFuncName()$" "$self$" calling for "$Other, 'Doors', KFPawn(Other).MyKFAIC );
}
return self; // Added 1.24.14
// Disabled 1.24.14, replaced with MoveToGoal command door handling (see ReachedIntermediateGoal)
// Door is welded shut
// if( MyKFDoor.WeldIntegrity > 0 )
// {
// KFAIController( Other.Controller ).WaitForDoor( MyKFDoor );
// KFAIController( Other.Controller ).NotifyAttackDoor( MyKFDoor );
// return self;
// }
// else
// {
// KFAIController( Other.Controller ).WaitForDoor( MyKFDoor );
// MyKFDoor.UseDoor( Other );
// return self;
// }
}
DefaultProperties
{
AdjustedReachThreshold=72.f
bBuildLongPaths=false
}