diff --git a/PkmnLibRSharp/FFI/StaticData/Item.cs b/PkmnLibRSharp/FFI/StaticData/Item.cs
new file mode 100644
index 0000000..53f66f5
--- /dev/null
+++ b/PkmnLibRSharp/FFI/StaticData/Item.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Runtime.InteropServices;
+using PkmnLibSharp.StaticData;
+
+namespace PkmnLibSharp.FFI.StaticData
+{
+ internal static class Item
+ {
+ [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr item_new(IntPtr name, ItemCategory category, BattleItemCategory battleCategory,
+ int price, IntPtr flags, ulong flagsLength);
+
+ [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern void item_drop(IntPtr ptr);
+
+ [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern IntPtr item_name(IntPtr ptr);
+
+ [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern ItemCategory item_category(IntPtr ptr);
+
+ [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern BattleItemCategory item_battle_category(IntPtr ptr);
+
+ [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int item_price(IntPtr ptr);
+
+ [DllImport(Data.DllName, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern byte item_has_flag(IntPtr p, IntPtr flag);
+
+ }
+}
\ No newline at end of file
diff --git a/PkmnLibRSharp/StaticData/Item.cs b/PkmnLibRSharp/StaticData/Item.cs
new file mode 100644
index 0000000..42d8e8a
--- /dev/null
+++ b/PkmnLibRSharp/StaticData/Item.cs
@@ -0,0 +1,115 @@
+using System.Collections.Generic;
+using System.Linq;
+using PkmnLibSharp.Utils;
+using Interface = PkmnLibSharp.FFI.StaticData.Item;
+
+namespace PkmnLibSharp.StaticData
+{
+ ///
+ /// An item category defines which bag slot items are stored in.
+ ///
+ public enum ItemCategory : byte
+ {
+ ///
+ /// This is where most items should go.
+ ///
+ MiscItem,
+
+ ///
+ /// Pokeballs are used for capturing Pokemons.
+ ///
+ Pokeball,
+
+ ///
+ /// Medicine is used for healing HP, PP, and status effects
+ ///
+ Medicine,
+
+ ///
+ /// Berry is used for all berries.
+ ///
+ Berry,
+
+ ///
+ /// TMHM is used for Technical and Hidden Machines.
+ ///
+ TMHM,
+
+ ///
+ /// Form Changer is used for items that change forms, such as mega stones.
+ ///
+ FormChanger,
+
+ ///
+ /// Key Items are single stored items, generally used for story progression.
+ ///
+ KeyItem,
+
+ ///
+ /// Mail is used for mail items.
+ ///
+ Mail,
+ }
+
+ ///
+ /// A battle item category defines how the item is categorized when in battle.
+ ///
+ public enum BattleItemCategory : byte
+ {
+ ///
+ /// This item can't be used in battle.
+ ///
+ None,
+
+ ///
+ /// This item is used for healing Pokemon.
+ ///
+ Healing,
+
+ ///
+ /// This item is used for healing Pokemon from a status.
+ ///
+ StatusHealing,
+
+ ///
+ /// This item is used for capturing Pokemon.
+ ///
+ Pokeball,
+
+ ///
+ /// This item does not belong in above categories, but is still a battle item.
+ ///
+ MiscBattleItem,
+ }
+
+ public class Item : ExternPointer
+ {
+ public class CacheData
+ {
+ public string? Name { get; internal set; }
+ public ItemCategory? Category { get; internal set; }
+ public BattleItemCategory? BattleCategory { get; internal set; }
+ public int? Price { get; internal set; }
+ }
+
+ public Item(string name, ItemCategory category, BattleItemCategory battleItemCategory, int price,
+ IEnumerable flags)
+ {
+ var ptrArray = flags.Select(x => x.ToPtr()).ToArray();
+ var ptrToPtrArray = ptrArray.ArrayPtr();
+ var ptr = Interface.item_new(name.ToPtr(), category, battleItemCategory, price, ptrToPtrArray,
+ (ulong)ptrArray.Length);
+ InitializePointer(ptr, true);
+ }
+
+ public string Name => Cache.Name ??= Interface.item_name(Ptr).PtrString()!;
+ public ItemCategory Category => Cache.Category ??= Interface.item_category(Ptr);
+ public BattleItemCategory BattleCategory => Cache.BattleCategory ??= Interface.item_battle_category(Ptr);
+ public int Price => Cache.Price ??= Interface.item_price(Ptr);
+
+ public bool HasFlag(string flag) => Interface.item_has_flag(Ptr, flag.ToPtr()) == 1;
+
+ protected override CacheData CreateCache() => new CacheData();
+ protected override void Destructor() => Interface.item_drop(Ptr);
+ }
+}
\ No newline at end of file
diff --git a/PkmnLibRSharpTests/StaticData/ItemTests.cs b/PkmnLibRSharpTests/StaticData/ItemTests.cs
new file mode 100644
index 0000000..d423bab
--- /dev/null
+++ b/PkmnLibRSharpTests/StaticData/ItemTests.cs
@@ -0,0 +1,31 @@
+using System;
+using NUnit.Framework;
+using PkmnLibSharp.StaticData;
+
+namespace PkmnLibRSharpTests.StaticData
+{
+ public class ItemTests
+ {
+ [Test]
+ public void BasicTests()
+ {
+ using var item = new Item("foobar", ItemCategory.Mail, BattleItemCategory.StatusHealing, 500,
+ Array.Empty());
+ Assert.AreEqual("foobar", item.Name);
+ Assert.AreEqual(ItemCategory.Mail, item.Category);
+ Assert.AreEqual(BattleItemCategory.StatusHealing, item.BattleCategory);
+ Assert.AreEqual(500, item.Price);
+ }
+
+ [Test]
+ public void FlagTests()
+ {
+ using var item = new Item("foobar", ItemCategory.Mail, BattleItemCategory.StatusHealing, 500,
+ new []{"foo", "zet"});
+ Assert.That(item.HasFlag("foo"));
+ Assert.That(item.HasFlag("zet"));
+ Assert.That(!item.HasFlag("bar"));
+ }
+
+ }
+}
\ No newline at end of file