Installation Guide

Step-by-step guide to install oxide-animalcontroljob with o-link, unified progression, and the current configuration layout.

Step-by-step setup for oxide-animalcontroljob.

Prerequisites

Required resources

ResourcePurpose
ox_libLocale, callbacks, timers, UI helpers
oxmysqlDatabase driver
o-linkFramework and system abstraction used by this resource

This resource depends on your server's o-link setup for:

  • player identity and character lookup
  • notifications
  • phone messaging
  • money handling
  • inventory for dart weapon management
  • targeting
  • progress bars
  • menu support when Config.menuStyle = 'menu'

Installation

Place the resource

Place oxide-animalcontroljob inside your server's resources folder.

Add startup order

Start dependencies before the job resource:

server.cfg
ensure ox_lib
ensure oxmysql
ensure o-link
ensure oxide-animalcontroljob

Database — nothing to do

The job creates its own database tables the first time it starts, so there is no SQL script to run. (sql/install.sql is still included if you prefer to create the tables yourself or want to see the schema.)

The progression table below is shared by current Oxide job resources. It is only created if another Oxide job hasn't already created it:

sql/install.sql
CREATE TABLE IF NOT EXISTS `job_progression` (
    `char_id`            VARCHAR(60)      NOT NULL,
    `job`                VARCHAR(40)      NOT NULL,
    `level`              TINYINT          NOT NULL DEFAULT 1,
    `total_count`        INT              NOT NULL DEFAULT 0,
    `daily_streak`       INT              NOT NULL DEFAULT 0,
    `last_activity_date` DATE             NULL,
    `complaints`         TINYINT UNSIGNED NOT NULL DEFAULT 0,
    `timeout_until`      DATETIME         NULL,
    PRIMARY KEY (`char_id`, `job`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

oxide-animalcontroljob stores progression rows with job = 'animalcontrol'.

The job creates two more shared tables in the same way:

  • oxide_settings, where the job saves its settings
  • job_pending_payouts, where shift pay waits for a player who disconnected or logged out on shift, until their next login

Migrate old data if needed

Only needed if you previously ran an older version of an Oxide job that used its own progression table. In that case, run sql/migrate_unified_progression.sql once — it copies player progress from the old tables into the shared table and removes the old ones. Back up your database first. If this is a fresh install, skip this step.

If you are updating multiple Oxide jobs that use this migration, only run the script once total.

Install the vehicle model

The resource uses the kennel vehicle model by default, based on the Vapid Kennel Animal Control Truck add-on. Ensure that vehicle model is installed on your server, or set Model under Animal control truck (Config.Vehicle.model) in /animalcontrol settings (Vehicle) to a model your server already uses.

Register the dart weapon and darts

The tranquilizer gun uses the WEAPON_G2 weapon hash by default with item name weapon_g2, and it fires the dedicated ammo_dart item through its own AMMO_ANIMALCONTROL_DART ammo type — not pistol ammo. You must register both in your framework so the inventory system recognizes them. If you prefer a different tranquilizer weapon, set Weapon under Tranquilizer gun (Config.Tranquilizer.weaponName) in /animalcontrol settings (Animals) instead; a custom tranquilizer weapon needs its own ammo type and dart item.

Item images: Copy weapon_g2.png and ammo_dart.png from the resource's itemimages/ folder into your inventory image directory:

  • QBCore (qb-inventory): qb-inventory/html/images/
  • ESX / Qbox (ox_inventory): ox_inventory/web/images/

Step 1: Add the weapon to qb-core/shared/weapons.lua:

qb-core/shared/weapons.lua
[`weapon_g2`] = {
    name = 'weapon_g2',
    label = 'Tranquilizer Gun',
    weapontype = 'Pistol',
    ammotype = 'AMMO_ANIMALCONTROL_DART',
    damagereason = 'Tranquilized',
},

Step 2: Add the weapon item to qb-core/shared/items.lua:

qb-core/shared/items.lua
weapon_g2 = { name = 'weapon_g2', label = 'Tranquilizer Gun', weight = 1000, type = 'weapon', ammotype = 'AMMO_ANIMALCONTROL_DART', image = 'weapon_g2.png', unique = true, useable = true, shouldClose = true, description = 'A tranquilizer gun used by animal control' },

Step 3: If you use qb-weapons (durability system), add the weapon to qb-weapons/config.lua inside Config.DurabilityMultiplier:

qb-weapons/config.lua
weapon_g2                    = 0.15,

Without this, qb-weapons will throw attempt to perform arithmetic on a nil value (local 'DecreaseAmount') at server/main.lua:166 the first time the player fires the tranquilizer. Any custom weapon missing from DurabilityMultiplier causes the same crash.

Step 4: Add the dart item to qb-core/shared/items.lua:

qb-core/shared/items.lua
ammo_dart = { name = 'ammo_dart', label = 'Tranquilizer Dart', weight = 20, type = 'item', image = 'ammo_dart.png', unique = false, useable = true, shouldClose = true, description = 'One dart for an animal control tranquilizer gun' },

Step 5: Add this entry inside Config.AmmoTypes in qb-weapons/config.lua:

qb-weapons/config.lua
ammo_dart = { ammoType = 'AMMO_ANIMALCONTROL_DART', amount = 1 },

Step 6: Below the existing Config.WeaponRepairCosts table in qb-weapons/config.lua, add:

qb-weapons/config.lua
Config.WeaponRepairCosts.animalcontrol = Config.WeaponRepairCosts.pistol

This keeps the dart gun on your configured pistol repair price.

Keep Config.Tranquilizer.ammoItem = 'ammo_dart'. Each item loads one dart; the starter pack and each resupply contain five items by default.

Both entries are ready to paste in itemimages/ox_inventory_weapons.lua in the resource folder:

itemimages/ox_inventory_weapons.lua
return {
    Weapons = {
        ['WEAPON_G2'] = { label = 'Tranquilizer Gun', weight = 1000, durability = 0.1, ammoname = 'ammo_dart', client = { image = 'weapon_g2.png' } },
    },

    Ammo = {
        ['ammo_dart'] = { label = 'Tranquilizer Dart', weight = 20 },
    },
}

Step 1: Copy the ['WEAPON_G2'] entry into the Weapons table in ox_inventory/data/weapons.lua.

Step 2: Copy the ['ammo_dart'] entry into the Ammo table in the same file.

Keep Config.Tranquilizer.ammoItem = 'ammo_dart'. Qbox uses ox_inventory, so these same steps apply.

Until the gun and ammo_dart are registered, nobody can clock in — players get an equipment error instead of half a kit.

Review configuration

Adjust:

  • shared/config.lua
  • shared/config/job.lua
  • shared/config/locations.lua
  • shared/config/events.lua
  • shared/config/animals.lua
  • shared/config/vehicles.lua
  • shared/config/props.lua
  • shared/config/visuals.lua
  • shared/config/tutorials.lua
  • shared/config/outfits.lua

These files are factory defaults, imported into the database the first time the job starts. After that, change settings in-game with /animalcontrol settings (admins only); they save and apply live. Editing a file then takes effect only after a restart and pressing Reset to default on that setting in the menu. The one exception is Config.UseHudAccent in shared/config.lua, which is always read from the file (edit it and restart). See How Settings Work.

See the Configuration Reference for the full config surface.

Updating an Existing Installation

Updating from a version that used pistol ammo for the dart gun:

Register ammo_dart and update the gun's ammo mapping using the steps for your inventory above, and copy itemimages/ammo_dart.png into your inventory's image folder. Do this before starting the new version — until you do, nobody can clock in.
Install the updated resource, including its weapon metadata and built web files, then fully restart the server and have players reconnect, because the gun's weapon data changed.
Existing saved WEAPON_G2 settings using ammo_pistol, pistol_ammo, or ammo-9 automatically migrate to ammo_dart on first start. Other equipment settings remain as saved. Custom tranquilizer weapons need their own dedicated ammo pool and compatible dart item.
Confirm the gun accepts darts and that switching to an ordinary pistol does not gain ammunition. Ordinary pistol ammo already in player inventories is preserved.

No SQL is needed for this update. The settings table is created automatically on first start.

Extra darts require enough earned shift pay to cover their price; the initial pack is free. Equipment identifiers can be changed in settings after all active shifts end.

Existing saved events at (0, 0, 0) are excluded from dispatch without replacing the owner's list. Edit or remove that scene in /animalcontrol settings. An empty call list leaves dispatch idle.

Verification

Start the server and confirm ox_lib, oxmysql, o-link, and oxide-animalcontroljob load without dependency errors.
Join the server and verify the animal control office blip and dispatcher NPC appear.
Interact with the dispatcher through your configured o-link target system.
Clock in, confirm the truck spawns, and wait for a dispatch call.
Accept a call and verify the timer, scene interactions, and payout flow work as expected.

Optional Setup

Phone messaging

When Config.usePhone = true (the default), the animal control office sends the player phone messages: a welcome when they clock in, notices for a destroyed truck, an escaped or killed animal, and a shift cancelled after going down on the job, and the detailed pay summary at clock-out (when Config.shiftSummary = 'text'). The phone also rings for each incoming call. Make sure your o-link phone module is configured for the phone resource your server uses.

Supported phones: qb-phone, lb-phone, gksphone, okokPhone, qs-smartphone, qs-smartphone-pro, yseries and Oxide Phone. How the messages arrive depends on the phone:

Arrives asPhones
Text message from the officeOxide Phone, gksphone, okokPhone, qs-smartphone (Quasar V3)
Mailqb-phone, lb-phone, yseries, qs-smartphone-pro, older qs-smartphone versions

Texts and the call ring need o-link 1.11.0

Texts and the call ring need o-link 1.11.0 or newer. With an older o-link, every message arrives as mail, as before, and the phone doesn't ring. If a text can't be sent for any reason, the message is sent as mail instead.

Incoming call ring: when dispatch sends a call, the phone shows a notification titled "Incoming Call" with the call type. Only the crew leader's phone rings (or the solo officer's). The call is still accepted or declined on screen, exactly as before. The ring works on every supported phone except qb-phone and older qs-smartphone versions.

Gigs app on Oxide Phone

If you run Oxide Phone, its Gigs app shows the animal control offices (and whether each has room), the player's current call (offered or in progress, their crew role, and pay so far), and their level. While the player carries an Oxide Phone and the Gigs app is on, shift updates and the call ring arrive there as Gigs notifications instead. The pay summary at clock-out still arrives as a text or mail. You don't need to set anything up beyond running Oxide Phone and this job.

Summary and notification-only setups

If you want a popup end-of-shift summary, set Shift summary (Config.shiftSummary) to Popup summary in /animalcontrol settings (General).

The popup opens on clock-out with either menu style. A shift that ends any other way than a clock-out still sends the summary as a text.

If your server has no phone, or you prefer notifications only, turn off Use phone (Config.usePhone) in /animalcontrol settings (General).

Nothing is sent to the phone then, and the phone doesn't ring. The on-screen notifications still show, and with Config.shiftSummary = 'text' the pay summary becomes a notification showing the net pay.

Stealth detection

Stray and wildlife jobs check whether the player is sneaking (crouched) when approaching an animal. If your server uses a custom crouch script from another resource, the game may not recognize players as sneaking even when they look crouched. In that case, turn off Use crouch detection under Stealth (Config.Stealth.useNativeStealth) in /animalcontrol settings (Animals, Advanced tab) — spook checks then use random chance instead of crouch detection, so the job stays playable.

Permission for the builder tool

The /animalcontrolbuilder admin command (used to create new offices and call locations in-game) is restricted to admins. To make someone an admin, add them to the admin group and grant that group the admin ace in your server.cfg:

server.cfg
add_principal identifier.license:<their-license> group.admin
add_ace group.admin admin allow

If you already run QBCore, Qbox, or ESX admins, they pass automatically — no extra setup is needed.

Regular players who are not admins see a "No permission" message if they try the command. The same admin check covers the /animalcontrol settings editor.

See the Admin Guide for builder usage and SQL management.

Notes for UI developers

The packaged web/dist build is already included and referenced by the manifest. Rebuilding the UI is only necessary if you edit files under web/src.

Next Steps