using System; using System.Linq; using VOID.Generic.Dict; using VOID.Generic.Objects.Accessory; using VOID.Generic.Objects.Armor; using VOID.Generic.Objects.Unit.Actions.Exceptions; 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.Actions { public class EquipAction : AbstractAction { private readonly UnitObject _unit; private readonly WearableObject _item; private readonly int _slotIndex; private readonly EquipmentSlotType _slot; public EquipAction(UnitObject unit, WearableObject item, int slotIndex) { _unit = unit; _item = item; _slotIndex = slotIndex; _slot = (EquipmentSlotType)slotIndex; } public EquipAction(UnitObject unit, WearableObject item) { _unit = unit; _item = item; _slot = FindEquipmentSlot(); _slotIndex = (int)_slot; } public override bool IsInRange() => true; protected override void OnEndIt() {} protected override void OnCancelIt() {} public override void CanDoIt() { Check( state == ActionState.Ready, UnitActionErrorType.ActionStateIsNotReady); if (_unit.basicState.turnManager) { Check( _unit.unitState.isSelfTurn, UnitActionErrorType.UnitSelfTurnNotActive); Check( _unit.unitData.currentResources.actionPoints >= 1, UnitActionErrorType.UnitNotEnoughActionPoints); } Check( _unit.unitEquipment.CanEquipInSlot(_slotIndex, _item), UnitActionErrorType.CannotEquipItemInThatSlot); Check( _unit.unitState.isControllable, UnitActionErrorType.UnitStateIsNotControllable); Check( _item.itemState.carriedBy == _unit, UnitActionErrorType.UnitDontCarryThatItem); Check( _item.wearableData.requirements.All(requirement => requirement.Check(_unit)), UnitActionErrorType.RequirementsNotMeetToEquipThatItem); } protected override void OnDoIt() { if (_unit.basicState.turnManager) _unit.unitData.UseResource(UnitResourceType.ActionPoints, 1); var equipEvent = new EquipEvent { wearable = _item, unit = _unit, slotIndex = _slotIndex, slotType = _slot }; _item.wearableEvents.onEquippedBefore.Invoke(equipEvent); _unit.unitEvents.onEquipBefore.Invoke(equipEvent); Check(!equipEvent.prevented, UnitActionErrorType.EquipIsPrevented); TryToUnEquip(); BeforePerform(); // Move item from Backpack to Equipment _unit.unitBackpack.Drop(_item); _unit.unitEquipment.Equip(_slotIndex, _item); // Execute events _item.wearableEvents.onEquippedAfter.Invoke(equipEvent); _unit.unitEvents.onEquipAfter.Invoke(equipEvent); AfterPerform(); EndIt(); } private void TryToUnEquip() { var toUnEquip = _unit.unitEquipment.GetEquipped(_slotIndex); if (toUnEquip) new UnEquipAction(_unit, toUnEquip).DoIt(); // All WearableObjects un-equip only this item where it will be equipped // EXCEPT WeaponObject - these also can un-equip additionally mainHand or offHand, only when dealing with two-handed weapons if (_item is not WeaponObject weapon) return; var mainHand = _unit.unitEquipment.GetEquipped(EquipmentSlotType.MainHand) as WeaponObject; var offHand = _unit.unitEquipment.GetEquipped(EquipmentSlotType.OffHand) as WeaponObject; // UNEQUIP MAINHAND - if it is two-hand, we try to equip something in offhand if (mainHand && _slot == EquipmentSlotType.OffHand && mainHand.weaponData.weaponCarryType is WeaponCarryType.TwoHand) new UnEquipAction(_unit, mainHand).DoIt(); // UNEQUIP OFFHAND - if we try to equip something two-handed if (offHand && weapon.weaponData.weaponCarryType == WeaponCarryType.TwoHand) new UnEquipAction(_unit, offHand).DoIt(); } private EquipmentSlotType FindEquipmentSlot() { var equippedRingOne = _unit.unitEquipment.GetEquipped(EquipmentSlotType.RingOne); var equippedRingTwo = _unit.unitEquipment.GetEquipped(EquipmentSlotType.RingTwo); return _item switch { WeaponObject when !IsWeaponCarryType(_item, WeaponCarryType.OneHandOff) => EquipmentSlotType.MainHand, WeaponObject when IsWeaponCarryType(_item, WeaponCarryType.OneHandOff) => EquipmentSlotType.OffHand, ArmorObject when IsType(_item, ArmorType.Helmet) => EquipmentSlotType.Helmet, ArmorObject when IsType(_item, ArmorType.Armor) => EquipmentSlotType.Armor, ArmorObject when IsType(_item, ArmorType.Pants) => EquipmentSlotType.Pants, ArmorObject when IsType(_item, ArmorType.Belt) => EquipmentSlotType.Belt, ArmorObject when IsType(_item, ArmorType.Boots) => EquipmentSlotType.Boots, ArmorObject when IsType(_item, ArmorType.Gloves) => EquipmentSlotType.Gloves, AccessoryObject when IsType(_item, AccessoryType.Necklace) => EquipmentSlotType.Necklace, AccessoryObject when IsType(_item, AccessoryType.Ring) && (!equippedRingOne || equippedRingTwo) => EquipmentSlotType.RingOne, AccessoryObject when IsType(_item, AccessoryType.Ring) && (equippedRingOne && !equippedRingTwo) => EquipmentSlotType.RingTwo, _ => throw new ArgumentOutOfRangeException(nameof(_item)) }; } } }