init
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Dict;
|
||||
using VOID.Generic.Objects.Abstract.Events;
|
||||
using VOID.Generic.Objects.Accessory;
|
||||
using VOID.Generic.Objects.Armor;
|
||||
using VOID.Generic.Objects.Item.Events;
|
||||
using VOID.Generic.Objects.Unit.Equipment;
|
||||
using VOID.Generic.Objects.Unit.Events;
|
||||
using VOID.Generic.Objects.Weapon;
|
||||
using VOID.Generic.Objects.Wearable;
|
||||
using VOID.Generic.Objects.Wearable.Events;
|
||||
using static VOID.Generic.Util.WearableUtils;
|
||||
|
||||
namespace VOID.Generic.Objects.Unit
|
||||
{
|
||||
/// <summary>
|
||||
/// Module of <see cref="UnitObject"/> which manage currently equipped items by this unit.<br/>
|
||||
/// List of available equip slots: <see cref="EquipmentSlotType"/>
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class UnitObjectEquipment : ObjectComponent<UnitObject>
|
||||
{
|
||||
#region Initialize
|
||||
|
||||
protected override void SelfInitialize()
|
||||
{
|
||||
// Empty GameObject where all items from backpack are "attached"
|
||||
_equipmentGameObject = parent.transform.Find("_equipment")?.gameObject;
|
||||
if (_equipmentGameObject == null)
|
||||
{
|
||||
_equipmentGameObject = new GameObject("_equipment");
|
||||
_equipmentGameObject.transform.parent = parent.gameObject.transform;
|
||||
_equipmentGameObject.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
// Equip all items pre-equipped from inspector
|
||||
Enum.GetValues(typeof(EquipmentSlotType)).OfType<EquipmentSlotType>()
|
||||
.Where(slotType => GetEquipped(slotType))
|
||||
.ForEach(slotType => FakeEquipOnInitForPrefab(GetEquipped(slotType), slotType));
|
||||
}
|
||||
|
||||
private WearableObject FakeEquipOnInitForPrefab(WearableObject wearable, EquipmentSlotType slotType)
|
||||
{
|
||||
// If item is prefab asset then we need to instantiate it first
|
||||
if (wearable.gameObject.scene.IsValid() == false)
|
||||
{
|
||||
wearable = UnityEngine.Object.Instantiate(wearable).GetComponent<WeaponObject>();
|
||||
}
|
||||
|
||||
var pickEvent = new PickEvent
|
||||
{
|
||||
item = wearable,
|
||||
unit = parent
|
||||
};
|
||||
var equipEvent = new EquipEvent
|
||||
{
|
||||
wearable = wearable,
|
||||
unit = parent,
|
||||
slotIndex = (int)slotType,
|
||||
slotType = slotType
|
||||
};
|
||||
|
||||
wearable.itemEvents.onPickedBefore.Invoke(pickEvent);
|
||||
wearable.itemEvents.onPickedAfter.Invoke(pickEvent);
|
||||
wearable.wearableEvents.onEquippedBefore.Invoke(equipEvent);
|
||||
wearable.wearableEvents.onEquippedAfter.Invoke(equipEvent);
|
||||
parent.unitEvents.onEquipBefore.Invoke(equipEvent);
|
||||
parent.unitEvents.onEquipAfter.Invoke(equipEvent);
|
||||
|
||||
return wearable;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// For each <see cref="EquipmentSlotType"/> func checking if given wearable can be equipped
|
||||
/// </summary>
|
||||
private static readonly Dictionary<EquipmentSlotType, Func<WearableObject, bool>> CanWearInSlotType = new()
|
||||
{
|
||||
[EquipmentSlotType.MainHand] = wearable => IsWeaponCarryType(wearable, WeaponCarryType.TwoHand, WeaponCarryType.OneHandAny, WeaponCarryType.OneHandMain),
|
||||
[EquipmentSlotType.OffHand] = wearable => IsWeaponCarryType(wearable, WeaponCarryType.OneHandAny, WeaponCarryType.OneHandOff),
|
||||
[EquipmentSlotType.Helmet] = wearable => IsType(wearable, ArmorType.Helmet),
|
||||
[EquipmentSlotType.Armor] = wearable => IsType(wearable, ArmorType.Armor),
|
||||
[EquipmentSlotType.Pants] = wearable => IsType(wearable, ArmorType.Pants),
|
||||
[EquipmentSlotType.Belt] = wearable => IsType(wearable, ArmorType.Belt),
|
||||
[EquipmentSlotType.Boots] = wearable => IsType(wearable, ArmorType.Boots),
|
||||
[EquipmentSlotType.Gloves] = wearable => IsType(wearable, ArmorType.Gloves),
|
||||
[EquipmentSlotType.Necklace] = wearable => IsType(wearable, AccessoryType.Necklace),
|
||||
[EquipmentSlotType.RingOne] = wearable => IsType(wearable, AccessoryType.Ring),
|
||||
[EquipmentSlotType.RingTwo] = wearable => IsType(wearable, AccessoryType.Ring),
|
||||
};
|
||||
|
||||
[ShowInInspector, ReadOnly] private GameObject _equipmentGameObject;
|
||||
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem mainHand;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem offHand;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem helmet;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem armor;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem pants;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem belt;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem boots;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem gloves;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem necklace;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem ringOne;
|
||||
[SerializeField, DisableInPlayMode] private EquippedItem ringTwo;
|
||||
|
||||
/// <summary>
|
||||
/// Returns equipped WearableObject in given slot.
|
||||
/// </summary>
|
||||
public WearableObject GetEquipped(EquipmentSlotType equipmentSlotType)
|
||||
{
|
||||
var equipItem = GetEquippedItemByType(equipmentSlotType);
|
||||
return equipItem.wearable ? equipItem.wearable : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns equopped WearableObject in given slot index. By enum: <see cref="EquipmentSlotType"/>
|
||||
/// </summary>
|
||||
public WearableObject GetEquipped(int equipmentSlotIndex)
|
||||
{
|
||||
return GetEquipped((EquipmentSlotType)equipmentSlotIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if given WearableObject can be equipped in given Slot.
|
||||
/// </summary>
|
||||
public bool CanEquipInSlot(EquipmentSlotType equipmentSlotType, WearableObject wearable)
|
||||
{
|
||||
return CanWearInSlotType.GetValueOrDefault(equipmentSlotType).Invoke(wearable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if given WearableObject can be equipped in given Slot index. By enum: <see cref="EquipmentSlotType"/>
|
||||
/// </summary>
|
||||
public bool CanEquipInSlot(int equipmentSlotIndex, WearableObject wearable)
|
||||
{
|
||||
return CanEquipInSlot((EquipmentSlotType)equipmentSlotIndex, wearable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Equip given WearableObject in first valid slot.
|
||||
/// </summary>
|
||||
public void Equip(WearableObject wearable)
|
||||
{
|
||||
var equipRingOne = !ringOne.wearable || ringTwo.wearable;
|
||||
var equipRingTwo = ringOne.wearable && !ringTwo.wearable;
|
||||
var equipmentSlotType = wearable switch
|
||||
{
|
||||
ArmorObject when IsType(wearable, ArmorType.Armor) => EquipmentSlotType.Armor,
|
||||
ArmorObject when IsType(wearable, ArmorType.Belt) => EquipmentSlotType.Belt,
|
||||
ArmorObject when IsType(wearable, ArmorType.Boots) => EquipmentSlotType.Boots,
|
||||
ArmorObject when IsType(wearable, ArmorType.Gloves) => EquipmentSlotType.Gloves,
|
||||
ArmorObject when IsType(wearable, ArmorType.Helmet) => EquipmentSlotType.Helmet,
|
||||
ArmorObject when IsType(wearable, ArmorType.Pants) => EquipmentSlotType.Pants,
|
||||
AccessoryObject when IsType(wearable, AccessoryType.Necklace) => EquipmentSlotType.Necklace,
|
||||
AccessoryObject when IsType(wearable, AccessoryType.Ring) && equipRingOne => EquipmentSlotType.RingOne,
|
||||
AccessoryObject when IsType(wearable, AccessoryType.Ring) && equipRingTwo => EquipmentSlotType.RingTwo,
|
||||
WeaponObject when IsWeaponCarryType(wearable, WeaponCarryType.TwoHand, WeaponCarryType.OneHandAny, WeaponCarryType.OneHandMain) => EquipmentSlotType.MainHand,
|
||||
WeaponObject when IsWeaponCarryType(wearable, WeaponCarryType.OneHandAny, WeaponCarryType.OneHandOff) => EquipmentSlotType.OffHand,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(wearable))
|
||||
};
|
||||
|
||||
Equip(equipmentSlotType, wearable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Equip given WearableObject in given slot index. By enum: <see cref="EquipmentSlotType"/>
|
||||
/// </summary>
|
||||
public void Equip(int equipmentSlotIndex, WearableObject wearable)
|
||||
{
|
||||
Equip((EquipmentSlotType)equipmentSlotIndex, wearable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Equip given WearableObject in given slot.
|
||||
/// </summary>
|
||||
public void Equip(EquipmentSlotType equipmentSlotType, WearableObject wearable)
|
||||
{
|
||||
if (!CanEquipInSlot(equipmentSlotType, wearable))
|
||||
{
|
||||
Debug.LogError($"Given wearableItem '{wearable.name}' cannot be equipped in that slot", wearable);
|
||||
return;
|
||||
}
|
||||
|
||||
// Someone already equipped that item
|
||||
if (wearable.wearableState.wearerUnit && wearable.wearableState.wearerUnit != parent)
|
||||
{
|
||||
Debug.LogError($"Given WearableItem '${wearable.name}' is already equipped by someone else!", wearable);
|
||||
return;
|
||||
}
|
||||
|
||||
// Someone else already carrying that item
|
||||
if (wearable.itemState.carriedBy && wearable.itemState.carriedBy != parent)
|
||||
{
|
||||
Debug.LogError($"Given WearableItem '{wearable.name}' is already carried by someone else!", wearable);
|
||||
return;
|
||||
}
|
||||
|
||||
// If item remove itself then we need to remove it from
|
||||
wearable.basicEvents.onRemove.AddListener(OnItemRemove);
|
||||
|
||||
// Update equipped item
|
||||
var equippedItem = GetEquippedItemByType(equipmentSlotType);
|
||||
equippedItem.wearable = wearable;
|
||||
equippedItem.gameObject.transform.SetParent(_equipmentGameObject.transform);
|
||||
equippedItem.gameObject.transform.SetLocalPositionAndRotation(Vector3.zero, new Quaternion());
|
||||
|
||||
parent.unitEvents.onEquipmentEquip.Invoke(new EquipmentEquipEvent
|
||||
{
|
||||
unit = parent,
|
||||
wearable = wearable,
|
||||
equipmentSlot = equipmentSlotType
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unequip WearableObject from given slot index. By enum: <see cref="EquipmentSlotType"/>
|
||||
/// </summary>
|
||||
public void UnEquip(int index)
|
||||
{
|
||||
UnEquip((EquipmentSlotType)index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unequip WearableObject.
|
||||
/// </summary>
|
||||
public void UnEquip(WearableObject wearable)
|
||||
{
|
||||
var equipmentSlotType = wearable switch
|
||||
{
|
||||
WeaponObject when wearable == mainHand.wearable => EquipmentSlotType.MainHand,
|
||||
WeaponObject when wearable == offHand.wearable => EquipmentSlotType.OffHand,
|
||||
ArmorObject when wearable == helmet.wearable => EquipmentSlotType.Helmet,
|
||||
ArmorObject when wearable == armor.wearable => EquipmentSlotType.Armor,
|
||||
ArmorObject when wearable == pants.wearable => EquipmentSlotType.Pants,
|
||||
ArmorObject when wearable == belt.wearable => EquipmentSlotType.Belt,
|
||||
ArmorObject when wearable == boots.wearable => EquipmentSlotType.Boots,
|
||||
ArmorObject when wearable == gloves.wearable => EquipmentSlotType.Gloves,
|
||||
AccessoryObject when wearable == necklace.wearable => EquipmentSlotType.Necklace,
|
||||
AccessoryObject when wearable == ringOne.wearable => EquipmentSlotType.RingOne,
|
||||
AccessoryObject when wearable == ringTwo.wearable => EquipmentSlotType.RingTwo,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(wearable))
|
||||
};
|
||||
|
||||
UnEquip(equipmentSlotType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unequip WearableObject from given slot.
|
||||
/// </summary>
|
||||
public void UnEquip(EquipmentSlotType equipmentSlotType)
|
||||
{
|
||||
var equippedItem = GetEquippedItemByType(equipmentSlotType);
|
||||
var tempWearable = equippedItem.wearable;
|
||||
|
||||
tempWearable.basicEvents.onRemove.RemoveListener(OnItemRemove);
|
||||
|
||||
// Remove reference from equipped slot
|
||||
equippedItem.wearable = null;
|
||||
|
||||
parent.unitEvents.onEquipmentUnEquip.Invoke(new EquipmentUnEquipEvent
|
||||
{
|
||||
unit = parent,
|
||||
wearable = tempWearable,
|
||||
equipmentSlot = equipmentSlotType
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see cref="EquippedItem"/> for given <see cref="EquipmentSlotType"/>.
|
||||
/// </summary>
|
||||
private EquippedItem GetEquippedItemByType(EquipmentSlotType equipmentSlot)
|
||||
{
|
||||
return equipmentSlot switch
|
||||
{
|
||||
EquipmentSlotType.MainHand => mainHand,
|
||||
EquipmentSlotType.OffHand => offHand,
|
||||
EquipmentSlotType.Helmet => helmet,
|
||||
EquipmentSlotType.Armor => armor,
|
||||
EquipmentSlotType.Pants => pants,
|
||||
EquipmentSlotType.Belt => belt,
|
||||
EquipmentSlotType.Boots => boots,
|
||||
EquipmentSlotType.Gloves => gloves,
|
||||
EquipmentSlotType.Necklace => necklace,
|
||||
EquipmentSlotType.RingOne => ringOne,
|
||||
EquipmentSlotType.RingTwo => ringTwo,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(equipmentSlot), equipmentSlot, null)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When item remove itself then also remove it from equipment.
|
||||
/// </summary>
|
||||
private void OnItemRemove(RemoveEvent removeEvent)
|
||||
{
|
||||
UnEquip(removeEvent.obj as WearableObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user