Adding Items to MonolithRP
This comprehensive guide will walk you through the process of adding custom items to the MonolithRP gamemode. Items are defined in the gamemode/config/inventory_items/items.lua file and follow a specific structure.
Basic Item Structure
Every item in MonolithRP follows this basic pattern:
local ITEM = nil
ITEM = Monolith.InventoryItem( "item_id", L( "cfg.item.item_name" ), L( "cfg.item.desc.item_description" ) )
-- Item properties go here
ITEM.Category = ITEM.ITEM_CONSUMABLE
ITEM.Model = "models/path/to/model.mdl"
-- Additional properties...
-- Server-side functions (if needed)
if SERVER then
function ITEM:OnUse( pPlayer, data )
-- Use logic here
end
function ITEM:CanUse( pPlayer )
-- Return true/false and optional message
return true
end
end
Monolith.InventoryItems:RegisterItem( ITEM )
Required Properties
Basic Information
- Item ID: First parameter of
Monolith.InventoryItem()- unique string identifier - Name: Second parameter - localized name using
L()function - Description: Third parameter - localized description using
L()function
Essential Properties
ITEM.Category: Defines the item type (see Item Categories)ITEM.Model: 3D model path for the item
Item Categories
Items are categorized using these constants:
| Category | Description | Usage |
|---|---|---|
ITEM.ITEM_CONSUMABLE | Items that can be used/consumed | Health kits, food, drugs |
ITEM.ITEM_EQUIPMENT | Equippable items | Armor, accessories |
ITEM.ITEM_INGREDIENT | Crafting materials | Raw materials, components |
ITEM.ITEM_ATTACHMENT | Weapon/item attachments | Scopes, filters |
ITEM.ITEM_LOOT | Generic loot items | Money, valuables |
ITEM.ITEM_DEPLOYABLE | Items that spawn entities | Structures, machines |
ITEM.ITEM_DEPRECATED | Deprecated items | Legacy items |
Equipment Slots
For equipment items (ITEM.ITEM_EQUIPMENT), specify the equipment slot:
| Slot | Description |
|---|---|
ITEM.EQUIPMENT_PRIMARY | Primary weapon slot |
ITEM.EQUIPMENT_SECONDARY | Secondary weapon slot |
ITEM.EQUIPMENT_ARMOR | Armor slot |
ITEM.EQUIPMENT_MISC | Miscellaneous equipment |
ITEM.Category = ITEM.ITEM_EQUIPMENT
ITEM.EquipSlot = ITEM.EQUIPMENT_ARMOR
Common Properties
Stack and Storage
ITEM.Stackable = true -- Can items stack together
ITEM.MaxStack = 32 -- Maximum stack size
ITEM.Worth = 250 -- Base value in dollars
ITEM.Store = 5 -- Store ID where sold (-1 = not sold)
Behavior Flags
ITEM.DropOnDeath = true -- Drop when player dies
ITEM.DeleteOnJobChange = true -- Delete when changing jobs
ITEM.CanConfiscate = true -- Police can confiscate
ITEM.NoMarket = true -- Cannot be sold on player market
ITEM.IgnoreStore = true -- Ignore store calculations
ITEM.NoDurability = true -- Item doesn't degrade
ITEM.PropertyOnly = false -- Can only be used in properties
Level Requirements
ITEM.Level = 25 -- Required player level
Action Properties
-- Static action time
ITEM.ActionLength = 5
-- Dynamic action time based on conditions
ITEM.ActionLength = function( pPlayer )
local bInCombat = pPlayer:InCombat()
return bInCombat and 10 or 5
end
-- Action configuration
ITEM.ActionExtraTable = {
ActionTimeRemainingText = L( "cfg.item.action.using" ),
CancelOnAnyMovement = true
}
Server-Side Functions
OnUse Function
Called when a player uses the item:
if SERVER then
function ITEM:OnUse( pPlayer, data )
-- Heal player
pPlayer:SetHealth( math.min( pPlayer:Health() + 50, pPlayer:GetMaxHealth() ) )
pPlayer:EmitSound( "items/medshot4.wav" )
end
end
CanUse Function
Determines if the item can be used:
if SERVER then
function ITEM:CanUse( pPlayer )
-- Check if player needs healing
local canUse = pPlayer:Health() < pPlayer:GetMaxHealth()
local errorMessage = L( "cfg.item.notif.healthFull" )
return canUse, errorMessage
end
end
Equipment Functions
For equippable items:
if SERVER then
function ITEM:OnEquip( pPlayer, data )
-- Apply equipment effects
pPlayer:EquipCosmeticStringID( "gasmask", true )
pPlayer:EmitSound( "items/equip.wav" )
end
function ITEM:OnUnequip( pPlayer, data )
-- Remove equipment effects
pPlayer:EquipCosmeticStringID( "gasmask", false )
end
function ITEM:OnDrop( pPlayer, data, ent )
-- Handle item being dropped
if pPlayer:IsEquippedCosmetic( "gasmask" ) then
pPlayer:EquipCosmeticStringID( "gasmask", false )
end
end
end
Armor System
For armor items, define damage reduction:
ITEM.HitGroupReduction = {
[ HITGROUP_HEAD ] = 0.4, -- 60% damage reduction
[ HITGROUP_CHEST ] = 0.6, -- 40% damage reduction
[ HITGROUP_STOMACH ] = 0.6, -- 40% damage reduction
[ HITGROUP_GEAR ] = 0.6 -- 40% damage reduction
}
Lower values = more protection (0.0 = no damage, 1.0 = full damage)
Crafting System
For craftable items:
ITEM.CraftingCategory = L( "cfg.item.category.equipment" )
ITEM.CraftingSkill = "crafting" -- Required skill
ITEM.CraftingSkillLevel = 45 -- Required skill level
ITEM.CraftingRecipe = {
mat_plastic = 10, -- Required materials
mat_metal = 4,
mat_metal_steel = 2,
}
Containers
For container items:
ITEM.IsContainer = true
if SERVER then
function ITEM:OnUse( pPlayer, data )
local eEnt = ents.Create( "prop_physics" )
eEnt:SetModel( self.Model )
eEnt:SetPos( pPlayer:GetPos() + Vector( 50, 0, 20 ) )
eEnt:Spawn()
eEnt:Activate()
eEnt:SetNWBool( "IsContainer", true )
eEnt.Container = Monolith.InventoryContainers:CreateContainer(
eEnt,
L( "cfg.item.container_name" ),
10, -- Slot count
L( "cfg.item.container_desc" )
)
if data.extra.Container then
eEnt.Container = data.extra.Container
eEnt.Container:SetEntity( eEnt )
end
eEnt.Container:SetOwner( pPlayer )
end
end
Icon System
Customize item icons:
ITEM.IconCamData = {
pos = Vector(287.15, 242.00, 175.35),
ang = Angle(25, 220, 0),
entAng = Angle(60, 45, 0),
fov = 5.1,
}
Attachments
For items with attachments:
ITEM.Attachments = {
mat_gas_filter_job = true
}
-- For attachment items
ITEM.IsAttachment = true
Price Calculation
Dynamic pricing:
function ITEM:CalculatePrice( data )
local basePrice = 200
local finalPrice = data.count * basePrice
return finalPrice
end
Advanced Examples
Medical Item
ITEM = Monolith.InventoryItem( "medkit_advanced", L( "cfg.item.medkit_advanced" ), L( "cfg.item.desc.medkit_advanced" ) )
ITEM.Category = ITEM.ITEM_CONSUMABLE
ITEM.Model = "models/w_models/weapons/w_eq_medkit.mdl"
ITEM.MaxStack = 5
ITEM.Worth = 2500
ITEM.Level = 40
ITEM.DropOnDeath = true
ITEM.Store = 11
ITEM.ActionLength = function( pPlayer )
return pPlayer:InCombat() and 15 or 8
end
ITEM.ActionExtraTable = {
ActionTimeRemainingText = L( "cfg.item.action.usingAdvancedMedkit" ),
CancelOnAnyMovement = true
}
if SERVER then
function ITEM:OnUse( pPlayer, data )
local healAmount = 75
local maxHealth = pPlayer:GetMaxHealth()
pPlayer:SetHealth( math.min( pPlayer:Health() + healAmount, maxHealth ) )
pPlayer:EmitSound( "items/medshot4.wav" )
-- Add temporary health boost
timer.Simple( 1, function()
if IsValid( pPlayer ) then
pPlayer:SetMaxHealth( maxHealth * 1.1 )
timer.Simple( 300, function() -- 5 minute boost
if IsValid( pPlayer ) then
pPlayer:SetMaxHealth( maxHealth )
end
end )
end
end )
end
function ITEM:CanUse( pPlayer )
local healthPercent = pPlayer:Health() / pPlayer:GetMaxHealth()
if healthPercent >= 0.9 then
return false, L( "cfg.item.notif.healthAlmostFull" )
end
if pPlayer:InCombat() then
return true -- Allowed but takes longer
end
return true
end
end
Monolith.InventoryItems:RegisterItem( ITEM )
Deployable Item
ITEM = Monolith.InventoryItem( "security_camera", L( "cfg.item.security_camera" ), L( "cfg.item.desc.security_camera" ) )
ITEM.Category = ITEM.ITEM_DEPLOYABLE
ITEM.Model = "models/props/cs_militia/security_camera.mdl"
ITEM.Worth = 5000
ITEM.Stackable = false
ITEM.Store = 8
ITEM.Level = 60
ITEM.PropertyOnly = true
ITEM.Class = "security_camera"
if SERVER then
function ITEM:OnUse( pPlayer, data )
local trace = pPlayer:GetEyeTrace()
local camera = ents.Create( "security_camera" )
camera:SetPos( trace.HitPos + trace.HitNormal * 10 )
camera:SetAngles( ( pPlayer:GetPos() - trace.HitPos ):Angle() )
camera:Spawn()
camera:Activate()
camera:SetOwner( pPlayer )
pPlayer:AddNotification( L( "cfg.item.notif.cameraDeployed" ) )
end
function ITEM:CanUse( pPlayer )
if not pPlayer:IsInProperty() then
return false, L( "cfg.item.notif.mustBeInProperty" )
end
return true
end
end
Monolith.InventoryItems:RegisterItem( ITEM )
Best Practices
1. Naming Conventions
- Use descriptive, unique item IDs
- Follow the existing localization pattern
- Use consistent prefixes (e.g.,
consumable_,weapon_,tool_)
2. Balance Considerations
- Set appropriate worth values
- Consider level requirements for powerful items
- Balance action times with item effectiveness
3. Performance
- Use
if SERVER thenblocks for server-only functions - Avoid expensive operations in frequently called functions
- Use timers appropriately for delayed effects
4. User Experience
- Provide clear error messages in
CanUsefunctions - Use appropriate sound effects
- Give meaningful action text
5. Testing
- Test items in different scenarios (combat, non-combat)
- Verify stacking behavior
- Test with different player levels
- Ensure proper cleanup of entities/effects
Troubleshooting
Common Issues
- Item doesn't appear: Check the item ID is unique and registration is called
- Localization missing: Ensure language strings are defined
- Model not showing: Verify model path is correct and exists
- Functions not working: Check
if SERVER thenblocks are properly placed - Stacking issues: Review
StackableandMaxStackproperties
Debug Tips
- Use
print()statements to debug function calls - Check console for Lua errors
- Test items in single-player first
- Use developer console commands to spawn items directly
This guide covers the essential aspects of adding items to MonolithRP. For more complex functionality, examine existing items in the codebase and adapt their patterns to your needs.