🤠 Wild Country Libs
Guide

Creating A Delivery Mission

A start location, a destination blip, server-tracked mission state, completion validation, a money reward, skill XP, and a Discord log line — the full shape of wc_corndelivery.

  1. Start location — pickup prompt

    wc_corndelivery/client/main.lua
    local pickup = vector3(2420.0, -2050.0, 28.0)
    local prompt = wc:CreatePrompt("Load Corn Sacks [G]")
    
    wc:WatchPlayerNear(pickup, 3.0, function()
      wc:SetPromptVisible(prompt, true)
    end)
  2. Server creates authoritative mission state

    Same principle as the job guide: the client requests, the server decides and remembers.

    wc_corndelivery/server/main.lua
    local ActiveDeliveries = {}
    
    RegisterNetEvent('wc_corndelivery:start', function()
      local src = source
      if ActiveDeliveries[src] then return end
    
      local ok = wc:AddItem(src, 'corn_sack', 1)
      if not ok then
        wc:Notify(src, { variant = 'fail', title = "No room for the sack." })
        return
      end
    
      ActiveDeliveries[src] = { reward = 35, startedAt = os.time() }
      TriggerClientEvent('wc_corndelivery:begin', src)
    end)
  3. Destination blip on the client

    wc_corndelivery/client/main.lua
    RegisterNetEvent('wc_corndelivery:begin', function()
      local drop = vector3(-315.0, 790.0, 120.0) -- Valentine general store
      local marker = wc:CreateMissionMarker(drop.x, drop.y, drop.z, "Corn Drop-off", { route = true })
    
      wc:WatchPlayerNear(drop, 4.0, function()
        marker:Clear()
        TriggerServerEvent('wc_corndelivery:turnIn')
      end, { timeoutMs = 480000 })
    end)
  4. Completion validation — check the item, pay, XP, log

    The server checks the player is still tracked as active and is actually carrying the sack (see Inventory) before doing anything.

    wc_corndelivery/server/main.lua
    RegisterNetEvent('wc_corndelivery:turnIn', function()
      local src = source
      local delivery = ActiveDeliveries[src]
      if not delivery then return end
    
      if not wc:HasItem(src, 'corn_sack', 1) then
        wc:Notify(src, { variant = 'fail', title = "You don't have the sack." })
        return
      end
    
      local removed = wc:RemoveItem(src, 'corn_sack', 1)
      if not removed then return end
    
      ActiveDeliveries[src] = nil
    
      wc:AddMoney(src, delivery.reward, 0)
      wc:Notify(src, { title = "Corn delivered — +$35", variant = 'avanced' })
    
      -- optional VORP skill XP (see the Skills page — no-ops safely on RSG)
      if wc:Framework_Is('vorp') then
        wc:ApplySkillBonus(src, 'trading', 15, '+15 Trading XP')
      end
    
      -- optional Discord log
      wc:SendWebhook(src, GetConvar('wc_corndelivery_webhook', ''), "Corn Delivery", "complete", {
        { "Reward", wc:FormatMoney(delivery.reward) },
      })
    end)

Common mistakes