AI/Guests/Inventory/Components/Consumable.cs
using Sandbox.Diagnostics;
namespace HC3.Inventory;
public partial class Consumable : Component, IItemEvents
{
/// <summary>
/// The need we're satisfying
/// </summary>
[Property] public NeedDefinition Need { get; set; }
/// <summary>
/// Can this consumable create trash?
/// </summary>
[Property] public bool CreatesTrash { get; set; }
/// <summary>
/// The trash pile (dropped) prefab.
/// </summary>
[Property] public GameObject TrashPilePrefab { get; set; }
/// <summary>
/// The item prefab for the trash.
/// </summary>
[Property] public GameObject TrashItemPrefab { get; set; }
/// <summary>
/// A tag to apply to the visitor, for a set amount of time
/// </summary>
[Property, Group( "Tags" )] public string Tag { get; set; }
/// <summary>
/// How long to apply the tag for?
/// </summary>
[Property, Group( "Tags" )] public float Duration { get; set; }
void IItemEvents.OnUsed( Item item )
{
if ( !Networking.IsHost )
return;
if ( CreatesTrash )
{
TryDropTrash( item.Guest );
}
Assert.True( Need.IsValid(), "Need is not valid for Consumable" );
item.Guest.Needs.GetNeed( Need ).Level = 0;
}
void TryDropTrash( Guest guest )
{
// We'll always drop trash if the park has no bins for us.
if ( !Scene.GetAllComponents<Bin>().Any() )
{
DropTrashPile( guest );
return;
}
// Only drop trash if we're a delinquent.
if ( guest.Delinquency < 0.2f )
{
GiveTrashItem( guest );
return;
}
// There's a high chance we'll drop trash.
if ( Game.Random.Float() > 0.8f )
{
GiveTrashItem( guest );
return;
}
// We're commiting a crime here, because there is bins and we're not using them.
guest.CommitCrime( 0.05f );
DropTrashPile( guest );
}
void DropTrashPile( Guest guest )
{
var startPosition = guest.WorldPosition + Vector3.Up * 16f;
startPosition.x += Game.Random.Float( -2f, 2f );
startPosition.y += Game.Random.Float( -2f, 2f );
var trace = Scene.Trace
.WithTag( "path" )
.Ray( startPosition, startPosition + Vector3.Down * 64f )
.Run();
if ( !trace.Hit || TrashPilePrefab is null )
{
GiveTrashItem( guest );
return;
}
var go = TrashPilePrefab?.Clone( trace.HitPosition );
var randomYaw = Rotation.FromAxis( trace.Normal, Game.Random.Float( 0f, 360f ) );
go.WorldRotation = Rotation.LookAt( randomYaw.Forward, trace.Normal );
go.NetworkSpawn();
}
void GiveTrashItem( Guest guest )
{
if ( TrashItemPrefab is null )
return;
guest.Inventory.Add( TrashItemPrefab );
}
}