Player/Inventory/PlayerInventory.cs
using Opium;
public partial class PlayerInventory : Component
{
/// <summary>
/// How many weapons can we fit in our inventory?
/// </summary>
[Property] public int Capacity { get; set; } = 2;
/// <summary>
/// A list of weapons.
/// </summary>
[Property] public List<BaseWeapon> Weapons { get; protected set; } = new();
/// <summary>
/// A list of prefabs to instantiate.
/// </summary>
[Property] public List<GameObject> Loadout { get; set; } = new();
/// <summary>
/// The current weapon we're using
/// </summary>
[Property, ReadOnly] public BaseWeapon Current { get; private set; }
[Property] public BaseWeapon Fists { get; set; }
[Property] public GameObject FistsPrefab { get; set; }
/// <summary>
/// Our previous weapon
/// </summary>
public BaseWeapon Previous { get; private set; }
public Actor Owner => Components.Get<Actor>( FindMode.EverythingInSelfAndAncestors );
public bool CanInsertWeapon()
{
return Weapons.Count < Capacity;
}
public BaseWeapon AddWeaponPrefab( GameObject prefab, bool setActive = false )
{
if ( !CanInsertWeapon() ) return null;
var wpn = CreateWeaponFromPrefab( prefab );
if ( wpn.IsValid() )
{
Weapons.Add( wpn );
}
else
{
return null;
}
// Hide the fists
if ( Fists.IsValid() )
Fists.SetAsActive( false );
if ( ( setActive || Weapons.Count == 1 ) && Current is not SingleUseWeapon )
{
SetCurrent( Weapons.Count );
}
return wpn;
}
public BaseWeapon CreateWeaponFromPrefab( GameObject prefab )
{
var obj = prefab.Clone( new CloneConfig()
{
Parent = GameObject,
StartEnabled = false
} );
obj.BreakFromPrefab();
obj.Enabled = false;
var weapon = obj.Components.Get<BaseWeapon>( true );
if ( !weapon.IsValid() )
{
obj.Destroy();
}
return weapon;
}
protected override void OnStart()
{
// already got weapons? nope.
if ( Weapons.Count > 0 )
{
return;
}
foreach ( var prefab in Loadout )
{
AddWeaponPrefab( prefab );
}
// Set weapon as the first one.
var firstWeapon = Weapons.FirstOrDefault();
if ( firstWeapon.IsValid() )
{
SetCurrent( 1 );
}
if ( Weapons.Count < 1 )
{
if ( !Fists.IsValid() )
{
TryCreateFists();
SetCurrent( Fists, false );
}
}
}
/// <summary>
/// Is this weapon index in bounds? Used in input.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
private bool InBounds( int index )
{
if ( index > Weapons.Count )
{
return false;
}
return true;
}
public void TryCreateFists()
{
if ( !Fists.IsValid() )
{
Fists = CreateWeaponFromPrefab( FistsPrefab );
}
}
public void SetCurrent( BaseWeapon weapon, bool queue = false )
{
// Kinda poopy, but it works.
if ( queue )
{
if ( Current.IsValid() )
{
QueuedWeapon = weapon;
Holster();
}
else
{
SetCurrent( weapon );
if ( !Current.IsValid() )
{
TryCreateFists();
SetCurrent( Fists, false );
return;
}
}
return;
}
if ( Current.IsValid() )
{
Current.SetAsActive( false );
}
Previous = Current;
if ( Previous is SingleUseWeapon single && single.IsValid() )
{
single.Discard();
}
Current = weapon;
if ( !Current.IsValid() )
{
TryCreateFists();
SetCurrent( Fists, false );
return;
}
Current.Actor = Owner;
Current.SetAsActive( true );
Deploy();
}
public void SetCurrent( int index )
{
if ( !InBounds( index ) ) return;
var weapon = Weapons[index - 1];
// can't change to same wpn
if ( Current == weapon ) return;
SetCurrent( weapon, true );
}
private bool CanSwitchWeapon()
{
if ( Current.IsValid() && Current is SingleUseWeapon )
{
return false;
}
return true;
}
void CheckSlotForInput( int slot )
{
if ( Input.Pressed( $"Slot{slot}" ) )
{
if ( CanSwitchWeapon() )
{
SetCurrent( slot );
}
}
}
/// <summary>
/// Tries to drop a weapon on the floor.
/// </summary>
/// <param name="weapon"></param>
public WeaponPickup Drop( BaseWeapon weapon )
{
if ( !weapon.IsValid() ) return null;
if ( !weapon.Droppable ) return null;
var player = Components.Get<Opium.PlayerController>( FindMode.EverythingInSelfAndParent );
if ( Current == weapon ) Current = null;
if ( Weapons.Remove( weapon ) )
{
var go = weapon.Drop( player.MainCamera.Transform.Position, player.MainCamera.Transform.Position + player.MainCamera.Transform.Rotation.Forward * 50,
player.MainCamera.Transform.Rotation.Forward );
// Change weapon if we have one
if ( Weapons.Count > 0 )
{
SetCurrent( 1 );
}
else
{
if ( player.IsAlive )
{
TryCreateFists();
SetCurrent( Fists, false );
}
}
return go;
}
return null;
}
void TryDropCurrentWeapon() => Drop( Current );
protected override void OnUpdate()
{
for ( int i = 1; i < 5; i++ )
{
CheckSlotForInput( i );
}
if ( Input.Pressed( "Drop" ) )
{
TryDropCurrentWeapon();
}
UpdateEquipState();
}
/// <summary>
/// Clears all weapons from a player's inventory.
/// </summary>
internal void Clear()
{
Fists?.GameObject?.DestroyImmediate();
for ( int i = Weapons.Count - 1; i >= 0; i-- )
{
Weapons[i].Destroy();
}
Weapons.Clear();
Current = null;
}
/// <summary>
/// Get an inventory.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public InventoryContainer GetInventory( ItemType type )
{
return Components.GetAll<InventoryContainer>().FirstOrDefault( x => x.ItemType == type );
}
/// <summary>
/// does the player have an item in any inventory container?
/// </summary>
/// <param name="resource"></param>
/// <returns></returns>
public bool HasItem( InventoryItemResource resource )
{
foreach ( var inventory in Components.GetAll<InventoryContainer>() )
{
if ( inventory.HasItem( resource ) )
{
return true;
}
}
return false;
}
public (InventoryContainer Container, int Index) FindItem( InventoryItemResource resource )
{
foreach ( var inventory in Components.GetAll<InventoryContainer>() )
{
if ( inventory.HasItem( resource ) )
{
var data = inventory.GetItem( resource );
return (inventory, data.Index);
}
}
return (null, -1);
}
}