1
0
KF2-Dev-Scripts/Engine/Classes/CoverLink.uc

1418 lines
39 KiB
Ucode
Raw Normal View History

2020-12-13 15:01:13 +00:00
/**
* Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
*/
class CoverLink extends NavigationPoint
native
DependsOn(Pylon)
placeable
ClassGroup(Cover)
config(Game);
/**
* Global flag: Whether coverlinks should create slot markers for navigation
* Should be FALSE if using navigation mesh, where cover navigation info will be built into the mesh
*/
var globalconfig bool GLOBAL_bUseSlotMarkers;
// Initial flanking dot prod value
const COVERLINK_ExposureDot = 0.4f;
// Considered vulnerable at edge slot if past this dot prod
const COVERLINK_EdgeCheckDot = 0.25f;
const COVERLINK_EdgeExposureDot = 0.85f;
// Navigation points within this range are considered dangerous to travel through
const COVERLINK_DangerDist = 1536.f;
struct immutablewhencooked native CoverReference extends ActorReference
{
/** Slot referenced in the link */
var() int SlotIdx;
structcpptext
{
friend FArchive& operator<<( FArchive& Ar, FCoverReference& T );
}
};
cpptext
{
struct FFireLinkInfo
{
class ACoverLink* Link;
INT SlotIdx;
FCoverSlot* Slot;
FVector SlotLocation;
FRotator SlotRotation;
FVector X, Y, Z;
TArray<BYTE> Types;
TArray<BYTE> Actions;
INT* out_FireLinkIdx;
FFireLinkInfo( ACoverLink* InLink, INT InSlotIdx, INT* InIdx = NULL )
{
Link = InLink;
SlotIdx = InSlotIdx;
Slot = &Link->Slots(SlotIdx);
out_FireLinkIdx = InIdx;
if( Slot->bLeanLeft )
{
Actions.AddItem( CA_LeanLeft );
}
if( Slot->bLeanRight )
{
Actions.AddItem( CA_LeanRight );
}
if( Slot->bCanPopUp && Slot->CoverType == CT_MidLevel )
{
Actions.AddItem( CA_PopUp );
}
Types.AddItem( Slot->CoverType );
if( Slot->CoverType == CT_Standing )
{
Types.AddItem( CT_MidLevel );
}
SlotLocation = Link->GetSlotLocation(SlotIdx);
SlotRotation = Link->GetSlotRotation(SlotIdx);
FRotationMatrix(SlotRotation).GetAxes(X,Y,Z);
}
};
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent);
virtual void BuildSlotInfo( INT SlotIdx, UBOOL bSeedPylon = FALSE, AScout* Scout = NULL);
virtual void BuildSlotInfoInternal( AScout* Scout, INT SlotIdx, UBOOL bSeedPylon = FALSE );
/**Sorts the CoverSlots
* @param LastSelectedSlot - the last coverslot the user has selected, the sort will update this value if passed in*/
void SortSlots(FCoverSlot** LastSelectedSlot = NULL);
void BuildFireLinks( AScout* Scout );
void BuildOtherLinks( AScout* Scout );
UBOOL GetFireActions( FFireLinkInfo& SrcInfo, ACoverLink* TestLink, INT TestSlotIdx, UBOOL bFill = TRUE );
UBOOL CanFireLinkHit( const FVector &ViewPt, const FVector &TargetLoc, UBOOL bDebugLines = FALSE );
UBOOL GetExposedInfo( ACoverLink* SrcLink, INT SrcSlotIdx, ACoverLink* DestLink, INT DestSlotIdx, FLOAT& out_ExposedScale );
virtual UBOOL GetFireLinkTo( INT SlotIdx, const FCoverInfo& ChkCover, BYTE ChkActin, BYTE ChkType, INT& out_FireLinkIdx, TArray<INT>& Items );
virtual UBOOL HasFireLinkTo( INT SlotIdx, const FCoverInfo& ChkCover, UBOOL bAllowFallbackLinks = FALSE );
FLOAT GetSlotHeight(INT SlotIdx);
#if WITH_EDITOR
/** Properly handles the mirroring of cover slots associated with this link */
virtual void EditorApplyMirror(const FVector& MirrorScale, const FVector& PivotLocation);
virtual void CheckForErrors();
virtual INT AddMyMarker(AActor *S);
#endif
virtual UBOOL IsFireLinkValid( INT SlotIdx, INT FireLinkIdx, BYTE ArrayID = 0 );
virtual void GetActorReferences(TArray<FActorReference*> &ActorRefs, UBOOL bIsRemovingLevel);
UBOOL IsOverlapSlotClaimed( APawn *ChkClaim, INT SlotIdx, UBOOL bSkipTeamCheck );
static FCoverSlot* CoverInfoToSlotPtr( FCoverInfo& InSlot );
static FCoverSlot* CoverRefToSlotPtr( FCoverReference& InRef );
UBOOL FindCoverEdges(const FVector& StartLoc, FVector AxisX, FVector AxisY, FVector AxisZ);
INT AddCoverSlot(FVector& SlotLocation, FRotator& SlotRotation, FCoverSlot Slot, INT SlotIdx = -1);
void EditorAutoSetup(FVector Direction,FVector *HitL = NULL, FVector *HitN = NULL);
void ClearExposedFireLinks();
// called during navmesh generation to link this coverlink into the mesh
virtual UBOOL LinkCoverSlotToNavigationMesh(INT SlotIdx, class UNavigationMeshBase* Mesh=NULL);
virtual INT FindCoverReference( ACoverLink* TestLink, INT TestSlotIdx, UBOOL bAddIfNotFound = TRUE );
virtual UBOOL GetCachedCoverInfo( INT RefIdx, FCoverInfo& out_Info );
void FixupLevelCoverReferences();
static FORCEINLINE void FireLinkInteraction_PackSrcType( BYTE SrcType, BYTE& PackedByte )
{
if( SrcType == CT_MidLevel ) { PackedByte |= (1<<0); }
}
static FORCEINLINE void FireLinkInteraction_PackSrcAction( BYTE SrcAction, BYTE& PackedByte )
{
PackedByte |= (SrcAction == CA_LeanLeft ? (1<<1) :
SrcAction == CA_LeanRight ? (1<<2) :
SrcAction == CA_PopUp ? (1<<3) :
0);
}
static FORCEINLINE void FireLinkInteraction_PackDestType( BYTE DestType, BYTE& PackedByte )
{
if( DestType == CT_MidLevel ) { PackedByte |= (1<<4); }
}
static FORCEINLINE void FireLinkInteraction_PackDestAction( BYTE DestAction, BYTE& PackedByte )
{
PackedByte |= (DestAction == CA_LeanLeft ? (1<<5) :
DestAction == CA_LeanRight ? (1<<6) :
DestAction == CA_PopUp ? (1<<7) :
0);
}
static FORCEINLINE BYTE FireLinkInteraction_UnpackSrcType( const BYTE PackedByte )
{
return (PackedByte & (1<<0)) ? CT_MidLevel : CT_Standing;
}
static FORCEINLINE BYTE FireLinkInteraction_UnpackSrcAction( const BYTE PackedByte )
{
return (PackedByte & (1<<1)) ? CA_LeanLeft :
(PackedByte & (1<<2)) ? CA_LeanRight :
(PackedByte & (1<<3)) ? CA_PopUp :
CA_Default;
}
static FORCEINLINE BYTE FireLinkInteraction_UnpackDestType( const BYTE PackedByte )
{
return (PackedByte & (1<<4)) ? CT_MidLevel : CT_Standing;
}
static FORCEINLINE BYTE FireLinkInteraction_UnpackDestAction( const BYTE PackedByte )
{
return (PackedByte & (1<<5)) ? CA_LeanLeft :
(PackedByte & (1<<6)) ? CA_LeanRight :
(PackedByte & (1<<7)) ? CA_PopUp :
CA_Default;
}
};
/** Utility struct for referencing cover link slots. */
struct immutablewhencooked native CoverInfo
{
var() editconst CoverLink Link;
var() editconst int SlotIdx;
structcpptext
{
FCoverInfo()
{
Link = NULL;
SlotIdx = 0;
}
FCoverInfo(EEventParm)
{
appMemzero(this, sizeof(FCoverInfo));
}
FCoverInfo(class ACoverLink* inLink, INT inSlotIdx)
{
Link = inLink;
SlotIdx = inSlotIdx;
}
UBOOL operator==(const FCoverInfo &Other) const
{
return (this->Link == Other.Link && this->SlotIdx == Other.SlotIdx);
}
FString ToString() const;
}
};
/** Utility struct to reference a position in cover */
struct immutablewhencooked native CovPosInfo
{
/** CoverLink holding cover position */
var CoverLink Link;
/** Index of left bounding slot */
var int LtSlotIdx;
/** Index of right bounding slot */
var int RtSlotIdx;
/** Pct of distance Location is, between left and right slots */
var float LtToRtPct;
/** Location in cover */
var vector Location;
/** Normal vector, used to define direction. Pointing from Location away from Wall. */
var vector Normal;
/** Tangent vector, gives alignement of cover. With multiple slots cover, this gives the direction from Left to Right slots. */
var vector Tangent;
structdefaultproperties
{
LtSlotIdx=-1
RtSlotIdx=-1
LtToRtPct=+0.f
}
};
/**
* Represents the current action this pawn is performing at the
* current cover node.
*/
enum ECoverAction
{
/** Default no action */
CA_Default,
/** Blindfiring to the left */
CA_BlindLeft,
/** Blindfiring to the right */
CA_BlindRight,
/** Leaning to the left */
CA_LeanLeft,
/** Leaning to the right */
CA_LeanRight,
/** Pop up, out of cover */
CA_PopUp,
/** Blind fire up */
CA_BlindUp,
/** AI Peek from cover options */
CA_PeekLeft,
CA_PeekRight,
CA_PeekUp,
};
/**
* Represents a direction associated with cover, for use with movement/camera/etc.
*/
enum ECoverDirection
{
CD_Default,
CD_Left,
CD_Right,
CD_Up,
};
/**
* Represents what type of cover this node provides.
*/
enum ECoverType
{
/** Default, no cover */
CT_None,
/** Full standing cover */
CT_Standing,
/** Mid-level crouch cover, stand to fire */
CT_MidLevel,
};
/** Descriptive tags for a particular cover location. Could be used for custom dialogue, for instance. */
enum ECoverLocationDescription
{
CoverDesc_None,
CoverDesc_InWindow,
CoverDesc_InDoorway,
CoverDesc_BehindCar,
CoverDesc_BehindTruck,
CoverDesc_OnTruck,
CoverDesc_BehindBarrier,
CoverDesc_BehindColumn,
CoverDesc_BehindCrate,
CoverDesc_BehindWall,
CoverDesc_BehindStatue,
CoverDesc_BehindSandbags,
// new entries go here at the end
};
enum EFireLinkID
{
FLI_FireLink,
FLI_RejectedFireLink,
// new entries go here at the end
};
/** Contains specific links between SOURCE actions/postures to DEST actions/postures */
struct immutablewhencooked native FireLinkItem
{
/** CT_Standing/CT_MidLevel for source */
var ECoverType SrcType;
/** Action for source */
var ECoverAction SrcAction;
/** CT_Standing/CT_MidLevel for source */
var ECoverType DestType;
/** Action for source */
var ECoverAction DestAction;
};
/**
* Contains information about what other cover nodes this node is
* capable of firing on.
*/
struct immutablewhencooked native FireLink
{
// var deprecated editconst const CoverReference TargetActor;
// var deprecated array<FireLinkItem> Items;
/** List of fire link interactions */
var array<byte> Interactions;
/**
* Packed properties
* CoverRefIdx (Bits 0 - 15) - Index into Levels CoverIndexPairs array
* DynamicLinkInfoIndex (Bits 16 - 31) - Index into this CoverLinks DynamicLinkInfos array
*/
var private const int PackedProperties_CoverPairRefAndDynamicInfo;
/** Is this link considered a fallback link? (Shouldn't be desired, but is acceptable) */
var private bool bFallbackLink;
/** Whether DynamicLinkInfoIndex has been initialized */
var private bool bDynamicIndexInited;
structcpptext
{
/**
* Updated DynamicLinkInfos array if source or destination is dynamic
*/
void UpdateDynamicLinkInfoFor(ACoverLink* MyLink, ACoverLink* TestLink, INT InSlotIdx, const FVector& LastSrcLocation);
FVector GetLastTargetLocation(ACoverLink *MyLink);
FVector GetLastSrcLocation(ACoverLink *MyLink);
FORCEINLINE void SetFallbackLink( UBOOL bSet )
{
bFallbackLink = bSet;
}
FORCEINLINE UBOOL IsFallbackLink()
{
return bFallbackLink;
}
FORCEINLINE void SetDynamicIndexInited( UBOOL bSet )
{
bDynamicIndexInited = bSet;
}
FORCEINLINE UBOOL IsDynamicIndexInited()
{
return bDynamicIndexInited;
}
FORCEINLINE void SetCoverRefIdx( INT Val )
{
Val &= 0x0000FFFF;
PackedProperties_CoverPairRefAndDynamicInfo &= ~(0x0000FFFF);
PackedProperties_CoverPairRefAndDynamicInfo |= Val;
}
FORCEINLINE DWORD GetCoverRefIdx()
{
return (PackedProperties_CoverPairRefAndDynamicInfo & (0x0000FFFF));
}
FORCEINLINE void SetDynamicLinkInfoIndex( INT Val )
{
Val &= 0xFFFF0000;
PackedProperties_CoverPairRefAndDynamicInfo &= ~(0xFFFF0000);
PackedProperties_CoverPairRefAndDynamicInfo |= (Val << 16);
}
FORCEINLINE DWORD GetDynamicLinkInfoIndex()
{
return ((PackedProperties_CoverPairRefAndDynamicInfo & (0xFFFF0000)) >> 16);
}
}
};
struct immutablewhencooked native DynamicLinkInfo
{
/** Location of the target when this FireLink was created/updated (Used for tracking CoverLink_Dynamic) */
var Vector LastTargetLocation;
/** Location of the src when this FireLink was created/updated (Used for tracking CoverLink_Dynamic) */
var Vector LastSrcLocation;
};
/**
* Contains information about other cover nodes this node is exposed to
* (ie flanked by)
*/
struct immutablewhencooked native ExposedLink
{
/** Slot that is dangerous to this link */
var() editconst const CoverReference TargetActor;
/** Scale of how dangerous this exposure is
(0,255] -- ~0 = not very dangerous, 255 = extremely dangerous */
var() byte ExposedScale;
};
struct immutablewhencooked native SlotMoveRef
{
var() PolyReference Poly;
var() BasedPosition Dest;
var() int Direction;
structcpptext
{
void Clear()
{
Poly.Clear();
Dest.Clear();
Direction = 0;
}
}
};
/** Contains information for a cover slot that a player can occupy */
struct immutablewhencooked native CoverSlot
{
/** Slot marker to allow the slot to exist on the navigation network */
// var deprecated editconst Actor SlotMarker;
// var deprecated array<FireLink> ForcedFireLinks;
// var deprecated array<ExposedLink> ExposedFireLinks;
// var deprecated editconst array<CoverInfo> OverlapClaims;
// var deprecated array<CoverReference> TurnTarget;
/** Current owner of this slot */
var Pawn SlotOwner;
/** Slot is invalid until world.timeseconds is >= this value (allows temporary disabling of slots) */
var transient float SlotValidAfterTime;
/** Gives LDs ability to force the type - CT_None == auto find*/
var() ECoverType ForceCoverType;
/** Type of cover this slot provides */
var(Auto) editconst ECoverType CoverType;
/** Per-slot description tag. If _None, fall back to the description in the CoverLink. */
var() ECoverLocationDescription LocationDescription;
/** Offset from node location for this slot */
var vector LocationOffset;
/** Offset from node rotation for this slot */
var rotator RotationOffset;
/** List of actions possible from this slot */
var array<ECoverAction> Actions;
/** List of all attackable nodes */
var() editconst array<FireLink> FireLinks;
/** List of coverlinks/slots that couldn't be shot at - used by COVERLINK_DYNAMIC */
var() editconst transient array<FireLink> RejectedFireLinks;
/**
* ExposedCover Packed Properties
* CoverRefIdx (Bits 0 - 15) - Index into Levels CoverIndexPairs array
* ExposedScale (Bits 16 - 23) - Scale of how dangerous this exposure is
* (0,255] -- ~0 = not very dangerous, 255 = extremely dangerous
*/
var private array<int> ExposedCoverPackedProperties;
/**
* Link/slot info about where swat turn evade can move to
* Packs left/right index into Level CoverIndexPair
* left turn target into bits 0-15, right turn target into 16-31
*/
var private int TurnTargetPackedProperties;
/** Info about where cover slip can move to */
var array<SlotMoveRef> SlipRefs;
/** List of cover slots that should be claimed when this slot is claimed
because they are overlapping */
var(Auto) editconst array<CoverInfo> OverlapClaimsList;
/** Can we lean left/right to shoot from this slot? */
var(Auto) bool bLeanLeft, bLeanRight;
/** Can we popup? */
var(Auto) bool bForceCanPopUp;
var(Auto) editconst bool bCanPopUp;
/** Can we mantle over this cover? */
var(Auto) editconst bool bCanMantle;
/** Can we mantle up? */
var(Auto) editconst bool bCanClimbUp;
/** Can cover slip at this slot? */
var(Auto) bool bForceCanCoverSlip_Left, bForceCanCoverSlip_Right;
var(Auto) editconst bool bCanCoverSlip_Left, bCanCoverSlip_Right;
/** Can swat turn at this slot? */
var(Auto) editconst bool bCanSwatTurn_Left, bCanSwatTurn_Right;
/** Is this slot currently enabled? */
var() bool bEnabled;
/** Is popping up allowed for midlevel/crouching cover? */
var() bool bAllowPopup;
/** Is mantling allowed here? */
var() bool bAllowMantle;
/** Is cover slip allowed? */
var() bool bAllowCoverSlip;
/** Is climbing up allowed here? */
var() bool bAllowClimbUp;
/** Is swat turn allowed? */
var() bool bAllowSwatTurn;
/** if this is on ground adjustments will be skipped */
var() bool bForceNoGroundAdjust;
/** Slot can only be used by players, not AI */
var() bool bPlayerOnly;
/** Override the default behavior of popup on target preffered over lean out */
var() bool bPreferLeanOverPopup;
/** runtime only - whether this slot is on destructible cover (so AI can shoot it to get the enemy out) */
var transient bool bDestructible;
/** === Editor specific === */
/** Is this slot currently selected for editing? */
var transient bool bSelected;
/** Map Error: Cover slot failed to find surface to align to */
var() transient editconst bool bFailedToFindSurface;
structdefaultproperties
{
bEnabled=TRUE
bCanMantle=TRUE
bCanCoverSlip_Left=TRUE
bCanCoverSlip_Right=TRUE
bCanSwatTurn_Left=TRUE
bCanSwatTurn_Right=TRUE
bCanClimbUp=FALSE
bAllowMantle=TRUE
bAllowCoverSlip=TRUE
bAllowPopup=TRUE
bAllowSwatTurn=TRUE
bAllowClimbUp=FALSE
TurnTargetPackedProperties=4294967296
}
structcpptext
{
FORCEINLINE void SetExposedCoverRefIdx( INT Index, INT Val )
{
Val &= 0x0000FFFF;
ExposedCoverPackedProperties(Index) &= ~(0x0000FFFF);
ExposedCoverPackedProperties(Index) |= Val;
}
FORCEINLINE DWORD GetExposedCoverRefIdx( INT Index )
{
return (ExposedCoverPackedProperties(Index) & (0x0000FFFF));
}
FORCEINLINE void SetExposedScale( INT Index, INT Val )
{
Val &= 0x000000FF;
ExposedCoverPackedProperties(Index) &= ~(0x00FF0000);
ExposedCoverPackedProperties(Index) |= (Val << 16);
}
FORCEINLINE BYTE GetExposedScale( INT Index )
{
return ((ExposedCoverPackedProperties(Index) & (0x00FF0000)) >> 16);
}
FORCEINLINE void SetLeftTurnTargetCoverRefIdx( INT Val )
{
Val &= 0x0000FFFF;
TurnTargetPackedProperties &= ~(0x0000FFFF);
TurnTargetPackedProperties |= Val;
}
FORCEINLINE DWORD GetLeftTurnTargetCoverRefIdx()
{
return (TurnTargetPackedProperties & (0x0000FFFF));
}
FORCEINLINE void SetRightTurnTargetCoverRefIdx( INT Val )
{
Val &= 0x0000FFFF;
TurnTargetPackedProperties &= ~(0xFFFF0000);
TurnTargetPackedProperties |= (Val << 16);
}
FORCEINLINE DWORD GetRightTurnTargetCoverRefIdx()
{
return ((TurnTargetPackedProperties & (0xFFFF0000)) >> 16);
}
FORCEINLINE FFireLink& GetFireLinkRef( INT FireLinkIdx, BYTE ArrayID = 0 )
{
if( ArrayID == FLI_RejectedFireLink )
{
return RejectedFireLinks(FireLinkIdx);
}
else
{
return FireLinks(FireLinkIdx);
}
}
}
};
/** How far auto adjust code traces forward from lean fire point
to determine if the lean has a valid fire line */
var float LeanTraceDist;
/** All slots linked to this node */
var() editinline array<CoverSlot> Slots;
/** Array of src and target location for dynamic links */
var array<DynamicLinkInfo> DynamicLinkInfos;
/** List of all players using this cover */
var array<Pawn> Claims;
/** Whether cover link is disabled */
var() bool bDisabled;
/** Claim all slots when someone claims one - used for cover that needs more than one slot, but slots overlap */
var() bool bClaimAllSlots;
/** Allow auto-sorting of the Slots array */
var() bool bAutoSort;
/** Allow auto-adjusting of the Slots orientation/position and covertype? */
var() bool bAutoAdjust;
/** Is this circular cover? */
var() bool bCircular;
/** Cover is looped, first slot and last slot should be reachable direclty */
var() bool bLooped;
/** Is this cover restricted to player use? */
var() bool bPlayerOnly;
/** This cover is dynamic */
var bool bDynamicCover;
/** This cover fractures when it is interacted with */
var() bool bFractureOnTouch;
/** Distance link must move to invalidate it's info */
var() float InvalidateDistance;
/** Max trace dist for fire links to check */
var() float MaxFireLinkDist;
/** Origin for circular cover */
var const vector CircularOrigin;
/** Radius for circular cover */
var const float CircularRadius;
/** Distance used when aligning to nearby surfaces */
var const float AlignDist;
/** Minimum distance to place between non-essential cover slots when auto-generating a cover link */
var const float AutoCoverSlotInterval;
/** Min height for nearby geometry to categorize as standing cover */
var const float StandHeight;
/** Min height for nearby geometry to categorize as mid-level cover */
var const float MidHeight;
var const Vector StandingLeanOffset;
var const Vector CrouchLeanOffset;
var const Vector PopupOffset;
/** Forward distance for checking cover slip links */
var const float SlipDist;
/** Lateral distance for checking swat turn links */
var const float TurnDist;
/** Scale applied to danger cost during path finding for slots of this link */
var() float DangerScale;
/** Used for the WorldInfo.CoverList linked list */
var const CoverLink NextCoverLink;
var(Debug) bool bDebug_FireLinks;
var(Debug) bool bDebug_ExposedLinks;
/** when enabled, extra info will be drawn and printed to the log related to generation of cover information for this link */
var(Debug) bool bDebug_CoverGen;
/** Description for the entire CoverLink. Can be overridden per-slot. */
var() const ECoverLocationDescription LocationDescription;
/** Should we automatically insert slots when there is too big of a gap? */
var() bool bDoAutoSlotDensityFixup;
simulated native function bool GetFireLinkTargetCoverInfo( int SlotIdx, int FireLinkIdx, out CoverInfo out_Info, optional EFireLinkID ArrayID );
/**
* Packs fire link item info into a single byte
* SrcType/DestType - only allow CT_Standing/CT_MidLevel
* SrcAction/DestAction - only allow CA_LeanLeft/CA_LeanRight/CA_PopUp/CA_Default(destonly)
*/
simulated static native function BYTE PackFireLinkInteractionInfo( ECoverType SrcType, ECoverAction SrcAction, ECoverType DestType, ECoverAction DestAction );
simulated static native function UnPackFireLinkInteractionInfo( const BYTE PackedByte, out ECoverType SrcType, out ECoverAction SrcAction, out ECoverType DestType, out ECoverAction DestAction );
/** Returns the world location of the requested slot. */
simulated native final function vector GetSlotLocation(int SlotIdx, optional bool bForceUseOffset);
/** Returns the world rotation of the requested slot. */
simulated native final function rotator GetSlotRotation(int SlotIdx, optional bool bForceUseOffset);
/** Returns the world location of the default viewpoint for the specified slot. */
simulated native final function vector GetSlotViewPoint( int SlotIdx, optional ECoverType Type, optional ECoverAction Action );
simulated native final function bool IsExposedTo( int SlotIdx, CoverInfo ChkSlot, out float out_ExposedScale );
simulated final event SetInvalidUntil(int SlotIdx, float TimeToBecomeValid)
{
Slots[SlotIdx].SlotValidAfterTime = TimeToBecomeValid;
NotifySlotOwnerCoverDisabled( SlotIdx );
}
/** Asserts a claim on this link by the specified controller. */
simulated final event bool Claim( Pawn NewClaim, int SlotIdx )
{
local int Idx;
local bool bResult, bDoClaim;
local PlayerController PC;
local Pawn PreviousOwner;
`if (`notdefined(FINAL_RELEASE))
local int NumClaims;
local array<int> SlotList;
local String Str;
//debug
if( bDebug )
{
`log( self@"Claim Slot"@SlotIdx@"For"@NewClaim@"(All?)"@bClaimAllSlots );
}
`endif
// Make sure SlotIdx is valid
if( SlotIdx < 0 )
{
return FALSE;
}
bDoClaim = TRUE;
// If slot already claimed
if( Slots[SlotIdx].SlotOwner != None )
{
// If we have already claimed it, nothing to do
// If we don't, fail claim
bResult = Slots[SlotIdx].SlotOwner == NewClaim;
bDoClaim = FALSE;
// If claimer is different
if( !bResult )
{
// If claimer is a player controller
PC = PlayerController( NewClaim.Controller );
if( PC != None )
{
PreviousOwner = Slots[SlotIdx].SlotOwner;
// Tell the previous owner that we are taking over
bDoClaim = TRUE;
}
}
}
if( bDoClaim )
{
// If all slots must be claimed
if( bClaimAllSlots )
{
// Loop through each slot and set new claim as owner of all
for( Idx = 0; Idx < Slots.Length; Idx++ )
{
if( Slots[Idx].SlotOwner == None )
{
// Add entry to general claims list (will contain multiple entries if has multiple slots claimed)
Claims[Claims.Length] = NewClaim;
// Mark slot claim
Slots[Idx].SlotOwner = NewClaim;
bResult = TRUE;
}
}
}
else
{
// Add entry to general claims list (will contain multiple entries if has multiple slots claimed)
Claims[Claims.Length] = NewClaim;
// Mark slot claim
Slots[SlotIdx].SlotOwner = NewClaim;
bResult = TRUE;
}
if (PreviousOwner != None && PreviousOwner.Controller != None)
{
PreviousOwner.Controller.NotifyCoverClaimViolation( NewClaim.Controller, self, SlotIdx );
}
}
//debug
`if (`notdefined(FINAL_RELEASE))
if( bDebug )
{
for( Idx = 0; Idx < Claims.Length; Idx++ )
{
if( Claims[Idx] == NewClaim )
{
NumClaims++;
}
}
for( Idx = 0; Idx < Slots.Length; Idx++ )
{
if( Slots[Idx].SlotOwner == NewClaim )
{
SlotList[SlotList.Length] = Idx;
}
}
if( SlotList.Length == 0 )
{
Str = "None";
}
else
{
for( Idx = 0; Idx < SlotList.Length; Idx++ )
{
Str = Str@SlotList[Idx];
}
}
`log( self@"Claims from"@NewClaim@NumClaims@"Slots:"@Str );
ScriptTrace();
}
`endif
return bResult;
}
/** Removes any claims the specified controller has on this link. */
simulated final event bool UnClaim( Pawn OldClaim, int SlotIdx, bool bUnclaimAll )
{
local int Idx, NumReleased;
local bool bResult;
`if (`notdefined(FINAL_RELEASE))
//debug
local int NumClaims;
local array<int> SlotList;
local String Str;
//debug
if( bDebug )
{
`log( self@"UnClaim"@`showvar(OldClaim)@`showvar(SlotIdx)@`showvar(bUnclaimAll)@`showvar(bClaimAllSlots) );
}
`endif
if( !bUnclaimAll && SlotIdx < 0)
{
return false;
}
// If letting go of link completely
if( bUnclaimAll )
{
// Clear the slot owner from all slots
for( Idx = 0; Idx < Slots.Length; Idx++ )
{
if( Slots[Idx].SlotOwner == OldClaim )
{
Slots[Idx].SlotOwner = None;
NumReleased++;
bResult = TRUE;
}
}
}
// Otherwise, if we want to let go of only one slot (and shouldn't always hold all of them)
else if( !bClaimAllSlots && Slots[SlotIdx].SlotOwner == OldClaim )
{
// Release this slot
Slots[SlotIdx].SlotOwner = None;
NumReleased++;
bResult = TRUE;
}
// For each slot released
while( NumReleased > 0 )
{
// Find a claim in the list
Idx = Claims.Find(OldClaim);
if( Idx < 0 )
{
break;
}
// Clear on claim from the general claims list
Claims.Remove( Idx, 1 );
NumReleased--;
}
//debug
`if (`notdefined(FINAL_RELEASE))
if( bDebug )
{
for( Idx = 0; Idx < Claims.Length; Idx++ )
{
if( Claims[Idx] == OldClaim )
{
NumClaims++;
}
}
for( Idx = 0; Idx < Slots.Length; Idx++ )
{
if( Slots[Idx].SlotOwner == OldClaim )
{
SlotList[SlotList.Length] = Idx;
}
}
if( SlotList.Length == 0 )
{
Str = "None";
}
else
{
for( Idx = 0; Idx < SlotList.Length; Idx++ )
{
Str = Str@SlotList[Idx];
}
}
`log( self@"Claims from"@`showvar(OldClaim)@`showvar(NumClaims)@"Slots:"@Str );
ScriptTrace();
}
`endif
return bResult;
}
/** Returns true if the specified controller is able to claim the slot. */
final native function bool IsValidClaim( Pawn ChkClaim, int SlotIdx, optional bool bSkipTeamCheck, optional bool bSkipOverlapCheck );
final native function bool IsValidClaimBetween( Pawn ChkClaim, int StartSlotIdx, int EndSlotIdx, optional bool bSkipTeamCheck, optional bool bSkipOverlapCheck );
/**
* Checks to see if the specified slot support stationary cover actions.
*/
simulated final function bool IsStationarySlot(int SlotIdx)
{
return (!bCircular && IsEdgeSlot(SlotIdx,FALSE));
}
/**
* Finds the current set of slots the specified point is between. Returns true
* if a valid slot set was found.
*/
simulated native final function bool FindSlots(vector CheckLocation, float MaxDistance, out int LeftSlotIdx, out int RightSlotIdx);
/**
* Return true if the specified slot is an edge, signifying "End Of Cover".
*/
simulated native final function bool IsEdgeSlot( int SlotIdx, optional bool bIgnoreLeans );
simulated native final function bool IsLeftEdgeSlot( int SlotIdx, bool bIgnoreLeans );
simulated native final function bool IsRightEdgeSlot( int SlotIdx, bool bIgnoreLeans );
simulated native final function int GetSlotIdxToLeft( int SlotIdx, optional int Cnt = 1 );
simulated native final function int GetSlotIdxToRight( int SlotIdx, optional int Cnt = 1 );
simulated final function bool AllowRightTransition(int SlotIdx)
{
local int NextSlotIdx;
NextSlotIdx = GetSlotIdxToRight( SlotIdx );
if( NextSlotIdx >= 0 )
{
return Slots[NextSlotIdx].bEnabled;
}
return FALSE;
}
simulated final function bool AllowLeftTransition(int SlotIdx)
{
local int NextSlotIdx;
NextSlotIdx = GetSlotIdxToLeft( SlotIdx );
if( NextSlotIdx >= 0 )
{
return Slots[NextSlotIdx].bEnabled;
}
return FALSE;
}
/**
* Searches for a fire link to the specified cover/slot and returns the cover actions.
*/
native noexport function bool GetFireLinkTo( int SlotIdx, CoverInfo ChkCover, ECoverAction ChkAction, ECoverType ChkType, out int out_FireLinkIdx, out array<int> out_Items );
/**
* Searches for a valid fire link to the specified cover/slot.
* NOTE: marked noexport until 'optional out int' is fixed in the exporter
*/
native noexport function bool HasFireLinkTo( int SlotIdx, CoverInfo ChkCover, optional bool bAllowFallbackLinks );
/**
* Returns a list of AI actions possible from this slot
*/
native final function GetSlotActions( int SlotIdx, out array<ECoverAction> Actions );
/**
* Enable/disable the entire CoverLink.
*/
simulated event SetDisabled(bool bNewDisabled)
{
local int SlotIdx;
local CoverReplicator CoverReplicator;
bDisabled = bNewDisabled;
if( bDisabled )
{
for( SlotIdx = 0; SlotIdx < Slots.Length; SlotIdx++ )
{
NotifySlotOwnerCoverDisabled( SlotIdx );
}
}
// if on server, notify clients slot was disabled
if( Role == ROLE_Authority )
{
CoverReplicator = WorldInfo.Game.GetCoverReplicator();
if (CoverReplicator != None)
{
CoverReplicator.NotifyLinkDisabledStateChange(self);
}
}
}
/**
* Enable/disable a particular cover slot.
*/
simulated event SetSlotEnabled(int SlotIdx, bool bEnable)
{
Slots[SlotIdx].bEnabled = bEnable;
if( !bEnable )
{
NotifySlotOwnerCoverDisabled( SlotIdx );
}
}
simulated function NotifySlotOwnerCoverDisabled( int SlotIdx, optional bool bAIOnly )
{
local int LeftIdx, RightIdx;
if( Slots[SlotIdx].SlotOwner != None &&
Slots[SlotIdx].SlotOwner.Controller != None &&
(!bAIOnly || PlayerController(Slots[SlotIdx].SlotOwner.Controller) == None) )
{
// notify any owner that the slot is disabled
Slots[SlotIdx].SlotOwner.Controller.NotifyCoverDisabled( self, SlotIdx, FALSE );
}
// Notify any adjacent owners
LeftIdx = GetSlotIdxToLeft( SlotIdx );
if( LeftIdx >= 0 &&
Slots[LeftIdx].SlotOwner != None &&
Slots[LeftIdx].SlotOwner.Controller != None &&
(!bAIOnly || PlayerController(Slots[LeftIdx].SlotOwner.Controller) == None) )
{
Slots[LeftIdx].SlotOwner.Controller.NotifyCoverDisabled( self, SlotIdx, TRUE );
}
RightIdx = GetSlotIdxToRight( SlotIdx );
if( RightIdx >= 0 &&
Slots[RightIdx].SlotOwner != None &&
Slots[RightIdx].SlotOwner.Controller != None &&
(!bAIOnly || PlayerController(Slots[RightIdx].SlotOwner.Controller) == None) )
{
Slots[RightIdx].SlotOwner.Controller.NotifyCoverDisabled( self, SlotIdx, TRUE );
}
}
/**
* Enable/disable playersonly on a particular cover slot.
*/
simulated event SetSlotPlayerOnly(int SlotIdx, bool bInPlayerOnly )
{
Slots[SlotIdx].bPlayerOnly = bInPlayerOnly;
if( Slots[SlotIdx].bPlayerOnly )
{
NotifySlotOwnerCoverDisabled( SlotIdx, TRUE );
}
}
/**
* Handle modify action by enabling/disabling the list of slots, or auto adjusting.
*/
function OnModifyCover(SeqAct_ModifyCover Action)
{
local array<int> SlotIndices;
local int Idx, SlotIdx;
local CoverReplicator CoverReplicator;
// if the action has slots specified
if (Action.Slots.Length > 0)
{
// use only those indicies
SlotIndices = Action.Slots;
}
else
{
// otherwise use all the slots
for (Idx = 0; Idx < Slots.Length; Idx++)
{
SlotIndices[SlotIndices.Length] = Idx;
}
}
for (Idx = 0; Idx < SlotIndices.Length; Idx++)
{
SlotIdx = SlotIndices[Idx];
if (SlotIdx >= 0 && SlotIdx < Slots.Length)
{
if (Action.InputLinks[0].bHasImpulse)
{
SetSlotEnabled(SlotIdx, TRUE);
}
else
if (Action.InputLinks[1].bHasImpulse)
{
SetSlotEnabled(SlotIdx, FALSE);
}
else
if (Action.InputLinks[2].bHasImpulse)
{
// update the slot
if (AutoAdjustSlot(SlotIdx,FALSE) &&
Slots[SlotIdx].SlotOwner != None && Slots[SlotIdx].SlotOwner.Controller != None)
{
// and notify if it changed
Slots[SlotIdx].SlotOwner.Controller.NotifyCoverAdjusted();
}
}
else
if (Action.InputLinks[3].bHasImpulse)
{
if( Action.ManualCoverType != CT_None )
{
Slots[SlotIdx].CoverType = Action.ManualCoverType;
if (Slots[SlotIdx].SlotOwner != None && Slots[SlotIdx].SlotOwner.Controller != None)
{
// notify the owner of the change
Slots[SlotIdx].SlotOwner.Controller.NotifyCoverAdjusted();
}
}
Slots[SlotIdx].bPlayerOnly = Action.bManualAdjustPlayersOnly;
}
}
}
CoverReplicator = WorldInfo.Game.GetCoverReplicator();
if (CoverReplicator != None)
{
if (Action.InputLinks[0].bHasImpulse)
{
CoverReplicator.NotifyEnabledSlots(self, SlotIndices);
}
else if (Action.InputLinks[1].bHasImpulse)
{
CoverReplicator.NotifyDisabledSlots(self, SlotIndices);
}
else if (Action.InputLinks[2].bHasImpulse)
{
CoverReplicator.NotifyAutoAdjustSlots(self, SlotIndices);
}
else if (Action.InputLinks[3].bHasImpulse)
{
CoverReplicator.NotifySetManualCoverTypeForSlots(self, SlotIndices, Action.ManualCoverType);
}
}
}
/**
* Auto-adjusts the slot orientation/location to the nearest geometry, as well
* as determine leans and cover type. Returns TRUE if the cover type changed.
*/
native final function bool AutoAdjustSlot(int SlotIdx, bool bOnlyCheckLeans);
native final function bool IsEnabled();
/**
* Overridden to disable all slots when toggled off.
*/
function OnToggle(SeqAct_Toggle inAction)
{
local CoverReplicator CoverReplicator;
local int SlotIdx;
Super.OnToggle( inAction );
if (inAction.InputLinks[0].bHasImpulse)
{
bDisabled = FALSE;
}
else if (inAction.InputLinks[1].bHasImpulse)
{
bDisabled = TRUE;
}
else
{
bDisabled = !bDisabled;
}
// Call SetSlotEnabled() which notifies any Pawns using this cover
for (SlotIdx = 0; SlotIdx < Slots.Length; ++SlotIdx)
{
SetSlotEnabled(SlotIdx, !bDisabled);
}
CoverReplicator = WorldInfo.Game.GetCoverReplicator();
if (CoverReplicator != None)
{
CoverReplicator.NotifyLinkDisabledStateChange(self);
}
}
function CreateCheckpointRecord(out CheckpointRecord Record)
{
Super.CreateCheckpointRecord(Record);
Record.bDisabled = bDisabled;
}
function ApplyCheckpointRecord(const out CheckpointRecord Record)
{
local CoverReplicator CoverReplicator;
Super.ApplyCheckpointRecord(Record);
bDisabled = Record.bDisabled;
CoverReplicator = WorldInfo.Game.GetCoverReplicator();
if (CoverReplicator != None)
{
CoverReplicator.NotifyLinkDisabledStateChange(self);
}
}
simulated event ShutDown()
{
Super.ShutDown();
bDisabled = TRUE;
}
simulated native function bool GetSwatTurnTarget( int SlotIdx, int Direction, out CoverInfo out_Info );
/** Applies an impulse to all nearby fractureable objects, if this coverlink is set to fracture on touch
*
* @param Origin - Origin of fracture pulse
* @param Radius - Radius around origin to apply the fracturable pulse. All parts in radius will fracture
* @param RBStrength - strength to apply to fractureable parts
* @param DamageType - DamageType to use as the fracturable pulse, potentially ignored by certain fractureable objects
*/
simulated function BreakFracturedMeshes(vector Origin, float Radius, float RBStrength, class<DamageType> DamageType)
{
local FracturedStaticMeshActor FracActor;
local byte bWantPhysChunksAndParticles;
if (!bFractureOnTouch)
{
return;
}
foreach CollidingActors(class'FracturedStaticMeshActor', FracActor, Radius, Origin, TRUE)
{
if((FracActor.Physics == PHYS_None) && FracActor.IsFracturedByDamageType(DamageType))
{
// Make sure the impacted fractured mesh is visually relevant
if( FracActor.FractureEffectIsRelevant( FALSE, Instigator, bWantPhysChunksAndParticles ) )
{
FracActor.BreakOffPartsInRadius(Origin, Radius, RBStrength, bWantPhysChunksAndParticles == 1 ? TRUE : FALSE);
}
}
}
}
//debug
`if (`notdefined(FINAL_RELEASE))
simulated event Tick( float DeltaTime )
{
local int SlotIdx;
local CoverSlot Slot;
local Vector OwnerLoc;
local byte R, G, B;
// no super tick implemented
//super.Tick( DeltaTime );
if( bDebug )
{
for( SlotIdx = 0; SlotIdx < Slots.Length; SlotIdx++ )
{
Slot = Slots[SlotIdx];
if( Slot.SlotOwner != None )
{
if( Slot.SlotOwner != None )
{
OwnerLoc = Slot.SlotOwner.Location;
R = 166;
G = 236;
B = 17;
}
else
{
OwnerLoc = vect(0,0,0);
R = 170;
G = 0;
B = 0;
}
DrawDebugLine( GetSlotLocation(SlotIdx), OwnerLoc, R, G, B );
}
}
}
}
`endif
native final function int AddCoverSlot(vector SlotLocation, rotator SlotRotation, optional int SlotIdx = -1, optional bool bForceSlotUpdate, optional Scout Scout);
simulated final event string GetDebugString(int SlotIdx)
{
return "L:"$GetRightMost(self)@"S:"$SlotIdx;
}
simulated native final function ECoverLocationDescription GetLocationDescription(int SlotIdx);
simulated event string GetDebugAbbrev()
{
return "CL";
}
defaultproperties
{
Components.Remove(PathRenderer)
Begin Object Name=CollisionCylinder
CollisionRadius=48.f
CollisionHeight=58.f
End Object
Begin Object NAME=Sprite
Sprite=Texture2D'EditorMaterials.CoverIcons.CoverNodeNoneLocked'
SpriteCategoryName="Cover"
End Object
Begin Object Class=CoverMeshComponent Name=CoverMesh
AlwaysLoadOnClient=False
AlwaysLoadOnServer=False
bUsePrecomputedShadows=False
End Object
Components.Add(CoverMesh)
// Don't show the navigation point arrow on cover links.
Components.Remove(Arrow)
Slots(0)=(LocationOffset=(X=64.f))
AlignDist=36.f
StandHeight=160.f
MidHeight=70.f
AutoCoverSlotInterval=175.f
StandingLeanOffset=(X=0,Y=78,Z=69)
CrouchLeanOffset=(X=0,Y=70,Z=19)
PopupOffset=(X=0,Y=0,Z=70)
SlipDist=60.f
TurnDist=512.f
bAutoSort=TRUE
bAutoAdjust=TRUE
bSpecialMove=TRUE
bBuildLongPaths=FALSE
MaxFireLinkDist=2048.f
InvalidateDistance=64.f
DangerScale=2.f
//debug
// bDebug=TRUE
// bStatic=FALSE
bDebug_FireLinks=FALSE
bDebug_ExposedLinks=FALSE
bDestinationOnly=TRUE
LeanTraceDist=64.f
bDoAutoSlotDensityFixup=FALSE
}