CityRP Documentation Repository

Items

Last updated

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 shorthand ITEM: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 /giveitem arrives as the replacement, through cityrp.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.