Items
Last updated
May be stale
This page was last updated ago, on 3 October 2026. Check what it says against the code before relying on it.
Items are one of the most simple parts to CityRP 2, yet one of the widest ranging, due to their use within every sector of the gamemode, and constant development.
Types of Items
Items currently fall into 3 distinct categories.
| Item Type | Status |
|---|---|
| Table | Deprecated, Majority of Items |
| Parented Table | Deprecated, Mostly Vehicles |
| Item Class | Active, Development |
Warning
cityrp.item.register({})(Table Items and Table Items with Inherence, below) is deprecated. New items must use the Class-Based Items pattern (ITEM:New(...)) described at the end of this page. The two table-based patterns are documented here only because they still make up most existing items.
Table Items
Table items are the simplest, being mearly a table and a call to item.register.
local ITEM = {}
ITEM.name = "My Special Item"
ITEM.cost = 999
ITEM.description = [[Stuff and things are done by my super cool item.]]
ITEM.uniqueID = "specialitem"
cityrp.item.register(ITEM)
Whilst the simplest, these are also often the largest, if code is repeated, due to the fact that elements must be duplicated in their entirety. For example, for the suit items, even though there may be 10 or more suits with the same price, they must be repeated each time.
Table Items with Inherence
Similar to the table items, these items simple pass a table to cityrp.item.register. However, passing a second argument to register will cause it to take that already-registered item, and use it as a parent.
if not cityrp.plugin.get("vehicles") then return end
local ITEM = {}
ITEM.name = "1981 Ford F150"
ITEM.cost = 160000
ITEM.model = "models/talonvehicles/tal_f150_1981.mdl"
ITEM.uniqueID = "81fordf150"
cityrp.item.register(ITEM, "base_vehicle")
This means that utility functions and shared information can stay on the base, reducing the duplication between files.
However, this has the downside of requiring that each base item is registered, and thus may accidentally become available to end users.
Class-Based Items.
To combat this, the alternative is class-based items. These use a completely different style to tabular items, can contain multiple items in the same file with ease, and can base themselves without registration.
local BASE = ITEM:New("base_accessory")
:SetCost(10000)
:SetModel("models/modified/backpack_2.mdl", 1, true)
:SetCategory("Accessories")
:SetDescription([[A modern camping backpack to carry all your gear.]])
:SetOffEmote("takes off their backpack.")
BASE:Clone()
:SetName("Navy and Tangerine Camping Backpack")
:SetOnEmote("puts on their navy and tangerine camping backpack.")
:Register("backpacknavy_2")
BASE:Clone()
:SetName("Olive and Blue Camping Backpack")
:SetSkin(2, true)
:SetOnEmote("puts on their olive and blue camping backpack.")
:Register("backpackolive_2")
BASE:Clone()
:SetName("Red, White and Green Camping Backpack")
:SetSkin(3, true)
:SetOnEmote("puts on their red, white and green camping backpack.")
:Register("backpackred_2")
In the above example, the base item is the accessory base, but the camping backpacks have data which is shared between each element, which is also put into the base. The base is then cloned, data updated, and then only then is it registered.
For the rationale behind this route — why inheritance is a lazy metatable chain, how load order protects bases, and the known sharp edges — see design/items-registration.md.
Retiring an item
Two flags take an item out of the store without deleting what players already own.
outdated = true: the item has no successor. Selling it refunds its full cost, and the F1 inventory shows only a Refund button.ITEM:Replaced(newID, meta)(or the shorthandITEM:Replacement(newID, oldID, meta)): the item has a successor, and converts into it on its own. A player's stack is rewritten when their inventory loads (and saved back to the database), and an item arriving later from storage, a trade, a pickup or/giveitemarrives as the replacement, throughcityrp.inventory.update. Anything that still slips through shows only a Convert button in F1, which, like Use, converts the whole stack.
meta is optional. Give it when one item with a meta choice replaces several fixed variants, so each old variant lands on the right choice:
ITEM:Replacement("tophat", "tophat_6", "colour=Red")
Without it the stack keeps its own meta. Replacements chain, so an item replaced twice still lands on the newest. cityrp.item.resolveReplacement(itemID, meta) returns where an item ends up.
Related
- Item Actions — the
canX/onXhook pair behind Use, Give, Drop and the rest - Item Metadata Schema — per-instance metadata fields and their types