This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2015-10-09 08:33:04 -04:00

259 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TrueCraft.API.Windows;
using TrueCraft.API;
using TrueCraft.API.Networking;
using TrueCraft.Core.Networking.Packets;
namespace TrueCraft.Core.Windows
{
public abstract class Window : IWindow, IDisposable, IEventSubject
{
public abstract IWindowArea[] WindowAreas { get; protected set; }
public event EventHandler<WindowChangeEventArgs> WindowChange;
public bool IsDisposed { get; private set; }
public IRemoteClient Client { get; set; }
public virtual void MoveToAlternateArea(int index)
{
int fromIndex = GetAreaIndex(index);
var from = GetArea(ref index);
var slot = from[index];
if (slot.Empty)
return;
var to = GetLinkedArea(fromIndex, slot);
int destination = to.MoveOrMergeItem(index, slot, from);
if (WindowChange != null && destination != -1)
WindowChange(this, new WindowChangeEventArgs(destination + to.StartIndex, slot));
}
public sbyte ID { get; set; }
public abstract string Name { get; }
public abstract sbyte Type { get; }
/// <summary>
/// When shift-clicking items between areas, this method is used
/// to determine which area links to which.
/// </summary>
/// <param name="index">The index of the area the item is coming from</param>
/// <param name="slot">The item being moved</param>
/// <returns>The area to place the item into</returns>
protected abstract IWindowArea GetLinkedArea(int index, ItemStack slot);
public abstract void CopyToInventory(IWindow inventoryWindow);
/// <summary>
/// Gets the window area to handle this index and adjust index accordingly
/// </summary>
protected IWindowArea GetArea(ref int index)
{
foreach (var area in WindowAreas)
{
if (area.StartIndex <= index && area.StartIndex + area.Length > index)
{
index = index - area.StartIndex;
return area;
}
}
throw new IndexOutOfRangeException();
}
/// <summary>
/// Gets the index of the appropriate area from the WindowAreas array.
/// </summary>
protected int GetAreaIndex(int index)
{
for (int i = 0; i < WindowAreas.Length; i++)
{
var area = WindowAreas[i];
if (index >= area.StartIndex && index < area.StartIndex + area.Length)
return i;
}
throw new IndexOutOfRangeException();
}
public virtual int Length
{
get
{
return WindowAreas.Sum(a => a.Length);
}
}
public virtual int MinecraftWasWrittenByFuckingIdiotsLength { get { return Length; } }
public bool Empty
{
get
{
return !WindowAreas.Any(a => a.Items.Any(i => !i.Empty));
}
}
public virtual ItemStack[] GetSlots()
{
int length = WindowAreas.Sum(area => area.Length);
var slots = new ItemStack[length];
foreach (var windowArea in WindowAreas)
Array.Copy(windowArea.Items, 0, slots, windowArea.StartIndex, windowArea.Length);
return slots;
}
public virtual void SetSlots(ItemStack[] slots)
{
foreach (var windowArea in WindowAreas)
{
if (windowArea.StartIndex < slots.Length && windowArea.StartIndex + windowArea.Length <= slots.Length)
Array.Copy(slots, windowArea.StartIndex, windowArea.Items, 0, windowArea.Length);
}
}
public virtual ItemStack this[int index]
{
get
{
foreach (var area in WindowAreas)
{
if (index >= area.StartIndex && index < area.StartIndex + area.Length)
return area[index - area.StartIndex];
}
throw new IndexOutOfRangeException();
}
set
{
foreach (var area in WindowAreas)
{
if (index >= area.StartIndex && index < area.StartIndex + area.Length)
{
var eventArgs = new WindowChangeEventArgs(index, value);
OnWindowChange(eventArgs);
if (!eventArgs.Handled)
area[index - area.StartIndex] = value;
return;
}
}
throw new IndexOutOfRangeException();
}
}
public virtual bool PickUpStack(ItemStack slot)
{
throw new NotSupportedException();
}
protected internal virtual void OnWindowChange(WindowChangeEventArgs e)
{
if (WindowChange != null)
WindowChange(this, e);
}
public event EventHandler Disposed;
public virtual void Dispose()
{
for (int i = 0; i < WindowAreas.Length; i++)
{
WindowAreas[i].Dispose();
}
WindowChange = null;
if (Disposed != null)
Disposed(this, null);
Client = null;
IsDisposed = true;
}
public virtual short[] ReadOnlySlots
{
get { return new short[0]; }
}
public static void HandleClickPacket(ClickWindowPacket packet, IWindow window, ref ItemStack itemStaging)
{
if (packet.SlotIndex >= window.Length || packet.SlotIndex < 0)
return;
var existing = window[packet.SlotIndex];
if (window.ReadOnlySlots.Contains(packet.SlotIndex))
{
if (itemStaging.ID == existing.ID || itemStaging.Empty)
{
if (itemStaging.Empty)
itemStaging = existing;
else
itemStaging.Count += existing.Count;
window[packet.SlotIndex] = ItemStack.EmptyStack;
}
return;
}
if (itemStaging.Empty) // Picking up something
{
if (packet.Shift)
{
window.MoveToAlternateArea(packet.SlotIndex);
}
else
{
if (packet.RightClick)
{
sbyte mod = (sbyte)(existing.Count % 2);
existing.Count /= 2;
itemStaging = existing;
itemStaging.Count += mod;
window[packet.SlotIndex] = existing;
}
else
{
itemStaging = window[packet.SlotIndex];
window[packet.SlotIndex] = ItemStack.EmptyStack;
}
}
}
else // Setting something down
{
if (existing.Empty) // Replace empty slot
{
if (packet.RightClick)
{
var newItem = (ItemStack)itemStaging.Clone();
newItem.Count = 1;
itemStaging.Count--;
window[packet.SlotIndex] = newItem;
}
else
{
window[packet.SlotIndex] = itemStaging;
itemStaging = ItemStack.EmptyStack;
}
}
else
{
if (existing.CanMerge(itemStaging)) // Merge items
{
// TODO: Consider the maximum stack size
if (packet.RightClick)
{
existing.Count++;
itemStaging.Count--;
window[packet.SlotIndex] = existing;
}
else
{
existing.Count += itemStaging.Count;
window[packet.SlotIndex] = existing;
itemStaging = ItemStack.EmptyStack;
}
}
else // Swap items
{
window[packet.SlotIndex] = itemStaging;
itemStaging = existing;
}
}
}
}
}
}