// using System.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TagFighter.Effects;
using UnityEngine;
namespace TagFighter.Equipment
{
public class OutfitChangingEventArgs : EventArgs
{
public Item ChangingFrom { get; }
public Item ChangingTo { get; }
public IItemSlot ChangingSlot { get; }
public OutfitChangingEventArgs(IItemSlot changingSlot, Item changingFrom, Item changingTo) {
ChangingSlot = changingSlot;
ChangingFrom = changingFrom;
ChangingTo = changingTo;
}
}
public class OutfitChangedEventArgs : EventArgs
{
public Item ChangedFrom { get; }
public Item ChangedTo { get; }
public IItemSlot ChangedSlot { get; }
public OutfitChangedEventArgs(IItemSlot changedSlot, Item changedFrom, Item changedTo) {
ChangedSlot = changedSlot;
ChangedFrom = changedFrom;
ChangedTo = changedTo;
}
}
public interface IWatchableOutfit
{
public event EventHandler<OutfitChangingEventArgs> OutfitChanging;
public event EventHandler<OutfitChangedEventArgs> OutfitChanged;
}
public class Outfit : MonoBehaviour, IWatchableOutfit, IEnumerable<IItemSlot>
{
[SerializeField] List<OutfitItemSlot> _itemSlots;
public int SlotCount {
get => _itemSlots.Count;
}
public event EventHandler<OutfitChangingEventArgs> OutfitChanging;
public event EventHandler<OutfitChangedEventArgs> OutfitChanged;
public IItemSlot this[int index] {
get {
if (index < 0 || index > _itemSlots.Count) {
throw new IndexOutOfRangeException("Index out of range");
}
return _itemSlots[index];
}
}
protected void OnOutfitChanging(OutfitChangingEventArgs e) {
OutfitChanging?.Invoke(this, e);
}
protected void OnOutfitChanged(OutfitChangedEventArgs e) {
OutfitChanged?.Invoke(this, e);
}
protected void Awake() {
foreach (var itemSlot in _itemSlots) {
itemSlot.OwningOutfit = this;
}
}
protected void Start() {
foreach (var itemSlot in _itemSlots.Where(itemSlot => itemSlot.EquippedItem != null)) {
itemSlot.Equip(itemSlot.EquippedItem);
OnOutfitChanging(new(itemSlot, null, itemSlot.EquippedItem));
OnOutfitChanged(new(itemSlot, null, itemSlot.EquippedItem));
}
}
public IEnumerator<IItemSlot> GetEnumerator() {
return _itemSlots.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
[Serializable]
class OutfitItemSlot : IItemSlot
{
[SerializeField] ItemSlotType _validItemSlot;
[SerializeField] Item _equippedItem;
public Item EquippedItem {
get => _equippedItem;
private set => _equippedItem = value;
}
public Outfit OwningOutfit { get; set; }
public bool CanEquip(Item item) {
var canEquip = item.GetEffects(_validItemSlot).Any();
return canEquip;
}
public ItemSlotType GetValidItemSlot() {
return _validItemSlot;
}
public bool IsSlotEmpty() {
return EquippedItem == null;
}
public bool TryEquip(Item item) {
if (EquippedItem != null) {
return false;
}
if (OwningOutfit.Any(itemSlot => itemSlot.EquippedItem == item)) {
return false;
}
if (!CanEquip(item)) {
return false;
}
// Debug.Log($"Equip {item}");
var changingFrom = EquippedItem;
Equip(item);
OwningOutfit.OnOutfitChanging(new(this, changingFrom, item));
OwningOutfit.OnOutfitChanged(new(this, changingFrom, item));
return true;
}
public bool TryUnequip() {
if (IsSlotEmpty()) {
return true;
}
var changingFrom = EquippedItem;
EquippedItem = null;
OwningOutfit.OnOutfitChanging(new(this, changingFrom, null));
OwningOutfit.OnOutfitChanged(new(this, changingFrom, null));
return true;
}
public void Equip(Item item) {
EquippedItem = item;
var ownerTransform = OwningOutfit.transform;
// Debug.Log($"ApplyItemEffects on {ownerTransform}");
var context = new EffectContext(new(ownerTransform), new(ownerTransform));
foreach (var effect in item.GetEffects(_validItemSlot)) {
effect.Mode.ImmediateAction(context, effect.Effect);
}
}
}
}
public interface IItemSlot
{
public bool CanEquip(Item item);
public Item EquippedItem { get; }
public ItemSlotType GetValidItemSlot();
public bool IsSlotEmpty();
public bool TryEquip(Item item);
public bool TryUnequip();
}
}