477 lines
10 KiB
Ucode
477 lines
10 KiB
Ucode
//=============================================================================
|
|
// PickupFactory.
|
|
// Produces pickups when active and touched by valid toucher
|
|
// Combines functionality of old Pickup and InventorySpot classes
|
|
// Pickup class now just used for dropped/individual items
|
|
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
|
|
//=============================================================================
|
|
class PickupFactory extends NavigationPoint
|
|
abstract
|
|
placeable
|
|
native
|
|
nativereplication
|
|
ClassGroup(Pickups);
|
|
|
|
var bool bOnlyReplicateHidden; // only replicate changes in bPickupHidden and bHidden
|
|
var RepNotify bool bPickupHidden; // Whether the pickup mesh should be hidden
|
|
var bool bPredictRespawns; // high skill bots may predict respawns for this item
|
|
var bool bIsSuperItem;
|
|
|
|
/** set when the respawn process has been paused because DelayRespawn() is returning true */
|
|
var bool bRespawnPaused;
|
|
|
|
var repnotify class<Inventory> InventoryType;
|
|
var float RespawnEffectTime;
|
|
var float MaxDesireability;
|
|
|
|
var PrimitiveComponent PickupMesh;
|
|
|
|
/** when replacing a pickup factory with another (e.g. mutators), set this property on the original to point to the replacement
|
|
* so that AI queries can be redirected to the right one
|
|
*/
|
|
var PickupFactory ReplacementFactory;
|
|
/** similarly, set this property on the replacement to point to the original so
|
|
* that it can optimally anchor itself on the path network
|
|
*/
|
|
var PickupFactory OriginalFactory;
|
|
|
|
cpptext
|
|
{
|
|
virtual APickupFactory* GetAPickupFactory() { return this; }
|
|
INT* GetOptimizedRepList( BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, UActorChannel* Channel );
|
|
virtual UBOOL ReachedBy(APawn* P, const FVector& TestPosition, const FVector& Dest);
|
|
virtual ANavigationPoint* SpecifyEndAnchor(APawn* RouteFinder);
|
|
}
|
|
|
|
replication
|
|
{
|
|
// Things the server should send to the client.
|
|
if ( bNetDirty && (Role == ROLE_Authority) )
|
|
bPickupHidden;
|
|
if (bNetInitial && Role == ROLE_Authority)
|
|
InventoryType;
|
|
}
|
|
|
|
simulated event ReplicatedEvent(name VarName)
|
|
{
|
|
if ( VarName == 'bPickupHidden' )
|
|
{
|
|
if ( bPickupHidden )
|
|
{
|
|
SetPickupHidden();
|
|
}
|
|
else
|
|
{
|
|
SetPickupVisible();
|
|
}
|
|
}
|
|
else if (VarName == 'InventoryType')
|
|
{
|
|
InitializePickup();
|
|
}
|
|
}
|
|
|
|
simulated event PreBeginPlay()
|
|
{
|
|
InitializePickup();
|
|
|
|
Super.PreBeginPlay();
|
|
}
|
|
|
|
simulated function InitializePickup()
|
|
{
|
|
if ( InventoryType == None )
|
|
{
|
|
`Warn("No inventory type for" @ self);
|
|
return;
|
|
}
|
|
|
|
bPredictRespawns = InventoryType.Default.bPredictRespawns;
|
|
MaxDesireability = InventoryType.Default.MaxDesireability;
|
|
SetPickupMesh();
|
|
bIsSuperItem = InventoryType.Default.bDelayedSpawn;
|
|
}
|
|
|
|
// Called after PostBeginPlay.
|
|
//
|
|
simulated event SetInitialState()
|
|
{
|
|
bScriptInitialized = true;
|
|
|
|
if (InventoryType == None)
|
|
{
|
|
`warn("Disabling as no inventory type for " $ self);
|
|
GotoState('Disabled');
|
|
}
|
|
else if (bIsSuperItem)
|
|
{
|
|
GotoState('WaitingForMatch');
|
|
}
|
|
else
|
|
{
|
|
Super.SetInitialState();
|
|
}
|
|
}
|
|
|
|
simulated function ShutDown()
|
|
{
|
|
GotoState('Disabled');
|
|
}
|
|
|
|
simulated function SetPickupMesh()
|
|
{
|
|
if ( InventoryType.Default.PickupFactoryMesh != None )
|
|
{
|
|
if (PickupMesh != None)
|
|
{
|
|
DetachComponent(PickupMesh);
|
|
PickupMesh = None;
|
|
}
|
|
PickupMesh = new(self) InventoryType.default.PickupFactoryMesh.Class(InventoryType.default.PickupFactoryMesh);
|
|
|
|
AttachComponent(PickupMesh);
|
|
|
|
if (bPickupHidden)
|
|
{
|
|
SetPickupHidden();
|
|
}
|
|
else
|
|
{
|
|
SetPickupVisible();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Reset()
|
|
reset actor to initial state - used when restarting level without reloading.
|
|
*/
|
|
function Reset()
|
|
{
|
|
if ( bIsSuperItem )
|
|
GotoState('Sleeping');
|
|
else
|
|
GotoState('Pickup');
|
|
Super.Reset();
|
|
}
|
|
|
|
function bool CheckForErrors()
|
|
{
|
|
local Actor HitActor;
|
|
local vector HitLocation, HitNormal;
|
|
|
|
HitActor = Trace(HitLocation, HitNormal,Location - Vect(0,0,10), Location,false);
|
|
if ( HitActor == None )
|
|
{
|
|
`log(self$" FLOATING");
|
|
return true;
|
|
}
|
|
return Super.CheckForErrors();
|
|
}
|
|
|
|
//
|
|
// Set up respawn waiting if desired.
|
|
//
|
|
function SetRespawn()
|
|
{
|
|
if( (InventoryType.Default.RespawnTime != 0) && WorldInfo.Game.ShouldRespawn(self) )
|
|
StartSleeping();
|
|
else
|
|
GotoState('Disabled');
|
|
}
|
|
|
|
function StartSleeping()
|
|
{
|
|
GotoState('Sleeping');
|
|
}
|
|
|
|
/* DetourWeight()
|
|
value of this path to take a quick detour (usually 0, used when on route to distant objective, but want to grab inventory for example)
|
|
*/
|
|
event float DetourWeight(Pawn Other, float PathWeight)
|
|
{
|
|
// not ready to pick up
|
|
return (ReplacementFactory != None ? ReplacementFactory.DetourWeight(Other, PathWeight) : 0.0);
|
|
}
|
|
|
|
function SpawnCopyFor( Pawn Recipient )
|
|
{
|
|
local Inventory Inv;
|
|
|
|
Inv = spawn(InventoryType);
|
|
if ( Inv != None )
|
|
{
|
|
Inv.GiveTo(Recipient);
|
|
Inv.AnnouncePickup(Recipient);
|
|
}
|
|
}
|
|
|
|
function bool ReadyToPickup(float MaxWait)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/** give pickup to player */
|
|
function GiveTo( Pawn P )
|
|
{
|
|
SpawnCopyFor(P);
|
|
PickedUpBy(P);
|
|
}
|
|
|
|
function PickedUpBy(Pawn P)
|
|
{
|
|
SetRespawn();
|
|
|
|
TriggerEventClass(class'SeqEvent_PickupStatusChange', P, 1);
|
|
|
|
if (P.Controller != None && P.Controller.MoveTarget == self)
|
|
{
|
|
P.SetAnchor(self);
|
|
P.Controller.MoveTimer = -1.0;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// Pickup state: this inventory item is sitting on the ground.
|
|
|
|
function RecheckValidTouch();
|
|
|
|
auto state Pickup
|
|
{
|
|
/* DetourWeight()
|
|
value of this path to take a quick detour (usually 0, used when on route to distant objective, but want to grab inventory for example)
|
|
*/
|
|
event float DetourWeight(Pawn Other,float PathWeight)
|
|
{
|
|
return InventoryType.static.DetourWeight(Other,PathWeight);
|
|
}
|
|
|
|
function bool ReadyToPickup(float MaxWait)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Validate touch (if valid return true to let other pick me up and trigger event).
|
|
*/
|
|
function bool ValidTouch( Pawn Other )
|
|
{
|
|
// make sure its a live player
|
|
if (Other == None || !Other.bCanPickupInventory)
|
|
{
|
|
return false;
|
|
}
|
|
else if (Other.Controller == None)
|
|
{
|
|
// re-check later in case this Pawn is in the middle of spawning, exiting a vehicle, etc
|
|
// and will have a Controller shortly
|
|
SetTimer( 0.2, false, nameof(RecheckValidTouch) );
|
|
return false;
|
|
}
|
|
// make sure not touching through wall
|
|
else if ( !FastTrace(Other.Location, Location) )
|
|
{
|
|
SetTimer( 0.5, false, nameof(RecheckValidTouch) );
|
|
return false;
|
|
}
|
|
|
|
// make sure game will let player pick me up
|
|
if (WorldInfo.Game.PickupQuery(Other, InventoryType, self))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
Pickup was touched through a wall. Check to see if touching pawn is no longer obstructed
|
|
*/
|
|
function RecheckValidTouch()
|
|
{
|
|
CheckTouching();
|
|
}
|
|
|
|
// When touched by an actor.
|
|
event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
|
|
{
|
|
local Pawn P;
|
|
|
|
// If touched by a player pawn, let him pick this up.
|
|
P = Pawn(Other);
|
|
|
|
if( P != None && ValidTouch(P) )
|
|
{
|
|
GiveTo(P);
|
|
}
|
|
}
|
|
|
|
// Make sure no pawn already touching (while touch was disabled in sleep).
|
|
function CheckTouching()
|
|
{
|
|
local Pawn P;
|
|
|
|
ForEach TouchingActors(class'Pawn', P)
|
|
Touch(P, None, Location, Normal(Location-P.Location) );
|
|
}
|
|
|
|
event BeginState(name PreviousStateName)
|
|
{
|
|
TriggerEventClass(class'SeqEvent_PickupStatusChange', None, 0);
|
|
}
|
|
|
|
Begin:
|
|
CheckTouching();
|
|
}
|
|
|
|
//=============================================================================
|
|
// Sleeping state: Sitting hidden waiting to respawn.
|
|
function float GetRespawnTime()
|
|
{
|
|
return InventoryType.Default.RespawnTime;
|
|
}
|
|
|
|
function RespawnEffect();
|
|
|
|
/**
|
|
* Make pickup mesh and associated effects hidden.
|
|
*/
|
|
simulated function SetPickupHidden()
|
|
{
|
|
bForceNetUpdate = TRUE;
|
|
bPickupHidden = true;
|
|
if ( PickupMesh != None )
|
|
PickupMesh.SetHidden(true);
|
|
}
|
|
|
|
/**
|
|
* Make pickup mesh and associated effects visible.
|
|
*/
|
|
simulated function SetPickupVisible()
|
|
{
|
|
bForceNetUpdate = TRUE;
|
|
bPickupHidden = false;
|
|
if ( PickupMesh != None )
|
|
PickupMesh.SetHidden(false);
|
|
}
|
|
|
|
event Destroyed()
|
|
{
|
|
// remove from any replacement chain
|
|
if (OriginalFactory != None)
|
|
{
|
|
OriginalFactory.ReplacementFactory = ReplacementFactory;
|
|
}
|
|
if (ReplacementFactory != None)
|
|
{
|
|
ReplacementFactory.OriginalFactory = OriginalFactory;
|
|
}
|
|
}
|
|
|
|
State WaitingForMatch
|
|
{
|
|
ignores Touch;
|
|
|
|
function MatchStarting()
|
|
{
|
|
GotoState('Sleeping');
|
|
}
|
|
|
|
event BeginState(Name PreviousStateName)
|
|
{
|
|
SetPickupHidden();
|
|
}
|
|
}
|
|
|
|
/** @return whether the respawning process for this pickup is currently halted */
|
|
function bool DelayRespawn()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
State Sleeping
|
|
{
|
|
ignores Touch;
|
|
|
|
function bool ReadyToPickup(float MaxWait)
|
|
{
|
|
return (bPredictRespawns && !bRespawnPaused && LatentFloat <= MaxWait && LatentFloat > 0.0);
|
|
}
|
|
|
|
function StartSleeping() {}
|
|
|
|
event BeginState(Name PreviousStateName)
|
|
{
|
|
SetPickupHidden();
|
|
}
|
|
|
|
event EndState(Name NextStateName)
|
|
{
|
|
SetPickupVisible();
|
|
}
|
|
|
|
Begin:
|
|
bRespawnPaused = true;
|
|
while (DelayRespawn())
|
|
{
|
|
Sleep(1.0);
|
|
}
|
|
bRespawnPaused = false;
|
|
Sleep( GetReSpawnTime() - RespawnEffectTime );
|
|
Respawn:
|
|
RespawnEffect();
|
|
Sleep(RespawnEffectTime);
|
|
GotoState('Pickup');
|
|
}
|
|
|
|
State Disabled
|
|
{
|
|
function bool ReadyToPickup(float MaxWait)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
function Reset() {}
|
|
function StartSleeping() {}
|
|
|
|
simulated event SetInitialState()
|
|
{
|
|
bScriptInitialized = true;
|
|
}
|
|
|
|
simulated event BeginState(Name PreviousStateName)
|
|
{
|
|
SetPickupHidden();
|
|
SetCollision(false,false);
|
|
}
|
|
|
|
simulated event EndState(Name NextStateName)
|
|
{
|
|
SetPickupVisible();
|
|
}
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
TickGroup=TG_DuringAsyncWork
|
|
|
|
Begin Object NAME=CollisionCylinder
|
|
CollisionRadius=+00040.000000
|
|
CollisionHeight=+00080.000000
|
|
CollideActors=true
|
|
End Object
|
|
|
|
bCollideWhenPlacing=False
|
|
bHiddenEd=false
|
|
bOnlyReplicateHidden=true
|
|
bStatic=false
|
|
bNoDelete=true
|
|
RemoteRole=ROLE_SimulatedProxy
|
|
bAlwaysRelevant=true
|
|
bCollideActors=true
|
|
bCollideWorld=false
|
|
bBlockActors=false
|
|
bIgnoreEncroachers=true
|
|
bHidden=false
|
|
NetUpdateFrequency=1.0
|
|
SupportedEvents.Add(class'SeqEvent_PickupStatusChange')
|
|
}
|