199 lines
6.1 KiB
Ucode
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
|
|
} |