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

479 lines
11 KiB
Ucode

//=============================================================================
// Pickup items.
//
// Pickup is the base class of actors that when touched by an appropriate pawn,
// will create and place an Inventory actor in that pawn's inventory chain. Each
// pickup class has an associated inventory class (its InventoryType). Pickups are
// placed by level designers. Pickups can only interact with pawns when in their
// default Pickup state. Pickups verify that they can give inventory to a pawn by
// calling the GameInfo's PickupQuery() function. After a pickup spawns an inventory
// item for a pawn, it then queries the GameInfo by calling the GameInfo's
// ShouldRespawn() function about whether it should remain active, enter its Sleep
// state and later become active again, or destroy itself.
//
// When navigation paths are built, each pickup has an InventorySpot (a subclass
// of NavigationPoint) placed on it and associated with it
// (the Pickup's MyMarker== the InventorySpot,
// and the InventorySpot's markedItem == the pickup).
//
//=============================================================================
class Pickup extends Actor
abstract
placeable
native
nativereplication;
//-----------------------------------------------------------------------------
// AI related info.
var float MaxDesireability; // Maximum desireability this item will ever have.
var InventorySpot MyMarker;
var NavigationPoint PickupCache; // used for dropped pickups
var() class<Inventory> InventoryType;
var() bool bInstantRespawn; // Can be tagged so this item respawns instantly.
var bool bOnlyReplicateHidden; // only replicate changes in bHidden (optimization for level pickups)
var(Display) bool bAmbientGlow; // Whether to glow or not.
var bool bDropped;
var bool bPredictRespawns; // high skill bots may predict respawns for this item
var() float RespawnTime; // Respawn after this time, 0 for instant.
var float RespawnEffectTime;
var() localized string PickupMessage; // Human readable description when picked up.
var() sound PickupSound;
var() string PickupForce; // jdf
var() xPickUpBase PickUpBase; // Pick-up base which spawned this pickup.
var Controller TeamOwner[4]; // AI controller currently going after this pickup (for team coordination)
// #ifdef _KF_
var() bool bExcludeFromNavigation; // If true, this pickup won't become part of the navigation network.
// #endif
native final function AddToNavigation(); // cache dropped inventory in navigation network
native final function RemoveFromNavigation();
static function StaticPrecache(LevelInfo L);
function Destroyed()
{
if (MyMarker != None )
MyMarker.markedItem = None;
if (Inventory != None )
Inventory.Destroy();
}
simulated function String GetHumanReadableName()
{
if ( InventoryType == None )
return GetItemName(string(class));
if ( InventoryType.Default.ItemName == "" )
return GetItemName(string(InventoryType));
return InventoryType.Default.ItemName;
}
function bool IsSuperItem()
{
return (PickupBase != None) && PickupBase.bDelayedSpawn;
}
simulated static function UpdateHUD(HUD H)
{
H.LastPickupTime = H.Level.TimeSeconds;
}
/* Reset()
reset actor to initial state - used when restarting level without reloading.
*/
function Reset()
{
if ( Inventory != None )
destroy();
else
{
if (myMarker != None && myMarker.bSuperPickup)
GotoState('Sleeping', 'DelayedSpawn');
else
GotoState('Pickup');
Super.Reset();
}
}
function RespawnEffect();
// Turns the pickup into a different type of pickup - specificly used by the WildcardCharger
function Pickup Transmogrify(class<Pickup> NewClass) // de
{
local Pickup NewPickup;
NewPickup = Spawn(NewClass);
NewPickup.PickupBase = PickupBase;
NewPickup.RespawnTime = RespawnTime;
if (MyMarker != None )
{
MyMarker.markedItem = NewPickup;
NewPickup.MyMarker = MyMarker;
MyMarker = None;
}
Destroy();
return NewPickup;
}
/* 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)
*/
function float DetourWeight(Pawn Other,float PathWeight)
{
return 0;
}
/* Pickups have an AI interface to allow AIControllers, such as bots, to assess the
desireability of acquiring that pickup. The BotDesireability() method returns a
float typically between 0 and 1 describing how valuable the pickup is to the
AIController. This method is called when an AIController uses the
FindPathToBestInventory() navigation intrinsic.
*/
function float BotDesireability( pawn Bot )
{
local Inventory AlreadyHas;
local float desire;
desire = MaxDesireability;
if ( RespawnTime < 10 )
{
AlreadyHas = Bot.FindInventoryType(InventoryType);
if ( AlreadyHas != None )
{
if ( Inventory != None )
{
if( Inventory.Charge <= AlreadyHas.Charge )
return -1;
}
else if ( InventoryType.Default.Charge <= AlreadyHas.Charge )
return -1;
}
}
return desire;
}
// Either give this inventory to player Other, or spawn a copy
// and give it to the player Other, setting up original to be respawned.
//
function inventory SpawnCopy( pawn Other )
{
local inventory Copy;
if ( Inventory != None )
{
Copy = Inventory;
Inventory = None;
}
else
Copy = spawn(InventoryType,Other,,,rot(0,0,0));
Copy.GiveTo( Other, self );
return Copy;
}
function StartSleeping()
{
if (bDropped)
Destroy();
else
GotoState('Sleeping');
}
function AnnouncePickup( Pawn Receiver )
{
Receiver.HandlePickup(self);
PlaySound( PickupSound,SLOT_Interact );
}
//
// Set up respawn waiting if desired.
//
function SetRespawn()
{
if( Level.Game.ShouldRespawn(self) )
StartSleeping();
else
Destroy();
}
// HUD Messages
static function string GetLocalString(
optional int Switch,
optional PlayerReplicationInfo RelatedPRI_1,
optional PlayerReplicationInfo RelatedPRI_2
)
{
return Default.PickupMessage;
}
function InitDroppedPickupFor(Inventory Inv)
{
SetPhysics(PHYS_Falling);
GotoState('FallingPickup');
Inventory = Inv;
bAlwaysRelevant = false;
bOnlyReplicateHidden = false;
bUpdateSimulatedPosition = true;
bDropped = true;
LifeSpan = 16;
bIgnoreEncroachers = false; // handles case of dropping stuff on lifts etc
NetUpdateFrequency = 8;
}
function bool ReadyToPickup(float MaxWait)
{
return false;
}
event Landed(Vector HitNormal)
{
GotoState('Pickup','Begin');
}
//=============================================================================
// Pickup state: this inventory item is sitting on the ground.
auto state Pickup
{
function bool ReadyToPickup(float MaxWait)
{
return true;
}
/* ValidTouch()
Validate touch (if valid return true to let other pick me up and trigger event).
*/
function bool ValidTouch( actor Other )
{
// make sure its a live player
if ( (Pawn(Other) == None) || !Pawn(Other).bCanPickupInventory || (Pawn(Other).DrivenVehicle == None && Pawn(Other).Controller == None) )
return false;
// make sure not touching through wall
if ( !FastTrace(Other.Location, Location) )
return false;
// make sure game will let player pick me up
if( Level.Game.PickupQuery(Pawn(Other), self) )
{
TriggerEvent(Event, self, Pawn(Other));
return true;
}
return false;
}
// When touched by an actor.
function Touch( actor Other )
{
local Inventory Copy;
// If touched by a player pawn, let him pick this up.
if( ValidTouch(Other) )
{
Copy = SpawnCopy(Pawn(Other));
AnnouncePickup(Pawn(Other));
SetRespawn();
if ( Copy != None )
Copy.PickupFunction(Pawn(Other));
}
}
// Make sure no pawn already touching (while touch was disabled in sleep).
function CheckTouching()
{
local Pawn P;
ForEach TouchingActors(class'Pawn', P)
Touch(P);
}
function Timer()
{
if ( bDropped )
GotoState('FadeOut');
}
function BeginState()
{
UntriggerEvent(Event, self, None);
if ( bDropped )
{
AddToNavigation();
SetTimer(8, false);
}
}
function EndState()
{
if ( bDropped )
RemoveFromNavigation();
}
Begin:
CheckTouching();
}
state FallingPickup extends Pickup
{
function CheckTouching()
{
}
function Timer()
{
GotoState('FadeOut');
}
function BeginState()
{
SetTimer(8, false);
}
}
State FadeOut extends Pickup
{
function Tick(float DeltaTime)
{
SetDrawScale(FMax(0.01, DrawScale - Default.DrawScale * DeltaTime));
}
function BeginState()
{
RotationRate.Yaw=60000;
SetPhysics(PHYS_Rotating);
LifeSpan = 1.0;
}
function EndState()
{
LifeSpan = 0.0;
SetDrawScale(Default.DrawScale);
if ( Physics == PHYS_Rotating )
SetPhysics(PHYS_None);
}
}
//=============================================================================
// Sleeping state: Sitting hidden waiting to respawn.
function float GetRespawnTime()
{
return RespawnTime;
}
State WaitingForMatch
{
ignores Touch;
function MatchStarting()
{
GotoState( 'Sleeping', 'DelayedSpawn' );
}
function BeginState()
{
NetUpdateTime = Level.TimeSeconds - 1;
bHidden = true;
}
}
State Sleeping
{
ignores Touch;
function bool ReadyToPickup(float MaxWait)
{
return ( bPredictRespawns && (LatentFloat < MaxWait) );
}
function StartSleeping() {}
function BeginState()
{
local int i;
NetUpdateTime = Level.TimeSeconds - 1;
bHidden = true;
SetCollision(false, false);
for ( i=0; i<4; i++ )
TeamOwner[i] = None;
}
function EndState()
{
NetUpdateTime = Level.TimeSeconds - 1;
bHidden = false;
SetCollision(default.bCollideActors, default.bBlockActors );
}
DelayedSpawn:
if ( Level.NetMode == NM_Standalone )
Sleep(FMin(30, Level.Game.GameDifficulty * 8));
else
Sleep(30);
Goto('Respawn');
Begin:
Sleep( GetReSpawnTime() - RespawnEffectTime );
Respawn:
RespawnEffect();
Sleep(RespawnEffectTime);
if (PickUpBase != None)
PickUpBase.TurnOn();
GotoState('Pickup');
}
State Disabled
{
function bool ReadyToPickup(float MaxWait)
{
return false;
}
function Reset() {}
function StartSleeping() {}
simulated function BeginState()
{
MaxDesireability = 0;
bHidden = true;
ResetStaticFilterState();
SetCollision(false,false,false);
}
}
defaultproperties
{
RespawnEffectTime=+0.5
bOnlyDirtyReplication=true
NetUpdateFrequency=0.1
PickupMessage="Snagged an item."
bAlwaysRelevant=true
RemoteRole=ROLE_DumbProxy
bHidden=false
NetPriority=+1.4
bCollideActors=true
bCollideWorld=true
bAmbientGlow=false
bFixedRotationDir=True
RotationRate=(Yaw=5000)
DesiredRotation=(Yaw=30000)
Texture=Texture'Engine.S_Inventory'
MaxDesireability=0.1000
DrawType=DT_Mesh
bOnlyReplicateHidden=true
bOrientOnSlope=true
bUseCylinderCollision=true
bShouldBaseAtStartup=true
bIgnoreEncroachers=true
bIgnoreVehicles=true
CullDistance=+8000.0
}