Configuration

Config = {}

-- XP awarded for successful street deals (per accept)
Config.StreetDealXP = 2
-- Level/XP
Config.DrugLevel = {
    [1] = 0,
    [2] = 500,
    [3] = 1500,
    [4] = 3000,
    [5] = 5000,
    [6] = 8000,
    [7] = 12000,
    [8] = 15000,
    [9] = 17500,
    [10] = 20000,
}

Config.DrugBuyers = {
    [1] = {
        CategoryName = "Weed",
        ItemList = {
            -- Street drugs
            { Item= "joint", Label= "Joint", img= "weed_baggy", minPrice= 7, maxPrice= 10, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "weed_purplehaze", Label= "Purple Haze 2g", img= "weed_baggy", minPrice= 32, maxPrice= 38, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "weed_whitewidow", Label= "White Widow 2g", img= "weed_baggy", minPrice= 21, maxPrice= 26, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "weed_ogkush", Label= "OGKush 2g", img= "weed_baggy", minPrice= 22, maxPrice= 27, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "weed_amnesia", Label= "Amnesia 2g", img= "weed_baggy", minPrice= 20, maxPrice= 25, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "weed_ak47", Label= "AK47 2g", img= "weed_baggy", minPrice= 20, maxPrice= 25, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "weed_skunk", Label= "Skunk 2g", img= "weed_baggy", minPrice= 16, maxPrice= 20, allowStreetDeal= true, allowDealerDeal= false },

            -- Dealer items
            { Item= "weed_brick", Label= "Weed Brick 100g", img= "weed_brick", minPrice= 820, maxPrice= 960, allowStreetDeal= false, allowDealerDeal= true },
        },
        DrugContacts = {
            { ContactName= "Thomas Kluff", Level= 1, XP= 100 },
            { ContactName= "Mike Obi", Level= 2, XP= 100 },
            { ContactName= "Bryne Mendes", Level= 3, XP= 100 },
            { ContactName= "Bruno Lars", Level= 4, XP= 100 },
            { ContactName= "Daniel Robs", Level= 5, XP= 100 },
        },
        DrugBuyerLocations = {
            -- x, y, z, heading
            { 339.48, -217.0, 54.22, 66.55 },
            { 497.46, -544.56, 24.75, 129.08 },
            { 1270.29, -1906.14, 39.43, 102.26 },
            { -1126.28, -1457.51, 4.93, 38.51 },
            { -3220.26, 900.8, 7.56, 187.06 },
        },
    },
    [2] = {
        CategoryName = "Coke, Crack, XTC",
        ItemList = {
            -- Street items
            { Item= "cokebaggy", Label= "Coke 2g", img= "cocaine_baggy", minPrice= 55, maxPrice= 70, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "crack_baggy", Label= "Crack 2g", img= "crack_baggy", minPrice= 28, maxPrice= 36, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "xtcbaggy", Label= "XTC 2g", img= "xtc_baggy", minPrice= 25, maxPrice= 32, allowStreetDeal= true, allowDealerDeal= false },

            -- Dealer items
            { Item= "coke_small_brick", Label= "Coke Package 25g", img= "coke_brick", minPrice= 415, maxPrice= 525, allowStreetDeal= false, allowDealerDeal= true },
            { Item= "coke_brick", Label= "Coke Brick 100g", img= "coke_brick", minPrice= 2270, maxPrice= 2510, allowStreetDeal= false, allowDealerDeal= true },
        },
        DrugContacts = {
            { ContactName= "Andreas Slavk", Level= 1, XP= 100 },
            { ContactName= "Toby Bryne", Level= 2, XP= 100 },
        },
        DrugBuyerLocations = {
            -- x, y, z, heading
            { 339.48, -217.0, 54.22, 66.55 },
            { 497.46, -544.56, 24.75, 129.08 },
            { 1270.29, -1906.14, 39.43, 102.26 },
            { -1126.28, -1457.51, 4.93, 38.51 },
            { -3220.26, 900.8, 7.56, 187.06 },
        },
    },
    [3] = {
        CategoryName = "Meth",
        ItemList = {
            { Item= "meth", Label= "Meth 1g", img= "meth_baggy", minPrice= 42, maxPrice= 50, allowStreetDeal= true, allowDealerDeal= false },
            { Item= "meth_tray", Label= "Meth Tray 50g", img= "meth_tray", minPrice= 1390, maxPrice= 1510, allowStreetDeal= false, allowDealerDeal= true },
        },
        DrugContacts = {
            { ContactName= "Phil Morb", Level= 1, XP= 100 },
            { ContactName= "Denis Klaf", Level= 2, XP= 100 },
        },
        DrugBuyerLocations = {
            -- x, y, z, heading
            { 339.48, -217.0, 54.22, 66.55 },
            { 497.46, -544.56, 24.75, 129.08 },
            { 1270.29, -1906.14, 39.43, 102.26 },
            { -1126.28, -1457.51, 4.93, 38.51 },
            { -3220.26, 900.8, 7.56, 187.06 },
        },
    },
    -- You can add as many categories as you want with the corresponding item of your choice
    --[[
    [4] = {
        CategoryName = "Test Category",
        ItemList = {
            { Item= "item_name", Label= "Item Name", img= "img_name", minPrice= 50, maxPrice= 60, allowStreetDeal= false, allowDealerDeal= true },
        },
        DrugContacts = {
            { ContactName= "Phil Morb", Level= 1, XP= 100 },
            { ContactName= "Denis Klaf", Level= 2, XP= 100 },
        },
        DrugBuyerLocations = {
            -- x, y, z, heading
            { 339.48, -217.0, 54.22, 66.55 },
        },
    },
    ]]
}

-- Dealer deal price/tension tuning extracted from server logic
Config.DealTuning = {
    -- Hard cap multiplier over item maxPrice (server default: 1.10)
    HardCapMult = 1.10,
    Tension = { -- Tension bounds and failure thresholds
        Min = 0,
        Max = 100,
    },
    DealDelays = {
        -- Number of failed/hesitated attempts at a location before auto-fail (server default: 3)
        MaxFailures = 3,
    },

    -- Case: price <= minPrice
    UnderMin = {
        -- Successful deal, tension reduced by a random value in this range
        TensionDelta = { Min = -2, Max = -1 },
    },

    -- Case: minPrice < price <= maxPrice
    WithinRange = {
        -- Chance formula: baseChance = BaseAtMin - floor(pct * DropAcrossRange)
        -- pct = (price - minPrice) / (maxPrice - minPrice)
        BaseAtMin       = 85,
        DropAcrossRange = 20,
        FirstDealBonus  = 5,
        MinBaseChance   = 40,

        -- On success: small tension decrease
        SuccessTensionDelta = { Min = -1, Max = 0 },
        -- On fail: tension increase and delay increments
        FailTensionDelta    = { Min = 2,  Max = 6 },
        FailMessage         = "The buyer hesitates... try a better price.",
    },

    -- Case: maxPrice < price <= hardCap
    OverCap = {
        -- Chance formula: chance = AtMaxPrice - floor(overPct * DropPerOverPct)
        -- overPct = (price - maxPrice) / max(maxPrice, 1)
        AtMaxPrice      = 10,
        DropPerOverPct  = 50,   -- 0.20 over => -10 => 0% chance
        MinChance       = 0,

        SuccessTensionDelta = { Min = 10, Max = 15 },
        FailTensionDelta    = { Min = 20, Max = 35 },
        FailMessage         = "Too expensive. Lower your price.",
    },

    -- Case: price > hardCap
    AboveHardCap = {
        TensionDelta = { Min = 30, Max = 45 },
        FailMessage  = "Ridiculous price! Don't try to rip me off.",
    },
}

-- Offer/Spawn timings and distances
Config.ClientTuning = {
    -- Timeouts in milliseconds
    StreetOfferTimeoutMs = 1 * 60 * 1000,   -- 1 minute for street NPC offers
    DealerOfferTimeoutMs = 2 * 60 * 1000,   -- 2 minutes for dealer offers
    OfferGlobalTimeoutMs = 10 * 60 * 1000,  -- 10 minutes before offers/NPCs auto-expire

    -- Category and NPC pacing
    CategoryCooldownMs   = 5 * 60 * 1000,   -- cooldown per category after meeting
    NPCCooldownMs        = 60 * 1000,       -- cooldown per NPC before re-approach
    NextNPCDelayMs       = 2500,            -- delay before next NPC can be approached

    -- Spawning
    MinSpawnDistance     = 70.0,            -- minimum distance for NPC spawn
}

-- Phone prop
Config.PhoneHold = {
    Model     = 'prop_prologue_phone',
    Bone      = 28422,  -- Right hand
    PosOffset = { x = 0.03, y = 0.0,  z = -0.02 },
    RotOffset = { x = 0.0,  y = 0.0,  z = 15.0  }
}

-- NPC name generation
Config.Names = {
    -- If true, uses initials like "A." for first names; otherwise uses full names.
    UseInitials = true,

    -- Initials pool for first names. Includes many "A." entries to bias toward A.
    FirstInitials = {
        -- Bias towards 'A.' as requested
        "A.", "A.", "A.", "A.", "A.", "A.", "A.", "A.",
        -- Other initials
        "B.", "C.", "D.", "E.", "F.", "G.", "H.", "I.", "J.", "K.",
        "L.", "M.", "N.", "O.", "P.", "Q.", "R.", "S.", "T.", "U.",
        "V.", "W.", "X.", "Y.", "Z."
    },

    -- Optional: full first names (mostly starting with 'A') if you set UseInitials = false
    FirstNames = {
        "Aaron", "Abel", "Abraham", "Ace", "Adam", "Adan", "Adrian", "Aiden",
        "Alan", "Albert", "Alejandro", "Alex", "Alexander", "Alfonso", "Ali",
        "Allan", "Alonso", "Alonzo", "Álvaro", "Alvin", "Amir", "Andre",
        "Andres", "Andrew", "Angel", "Anthony", "Antonio", "Armando", "Arturo",
        "Augusto", "Austin", "Axel"
    },

    -- Predominantly American and Latin American last names
    LastNames = {
        "Smith", "Johnson", "Williams", "Brown", "Jones", "Miller", "Davis",
        "Garcia", "Martinez", "Rodriguez", "Hernandez", "Lopez", "Gonzalez",
        "Perez", "Sanchez", "Ramirez", "Torres", "Flores", "Rivera", "Gomez",
        "Diaz", "Reyes", "Cruz", "Morales", "Ortiz", "Gutierrez", "Chavez",
        "Vargas", "Vasquez", "Castillo", "Ramos", "Soto", "Silva", "Mendoza",
        "Rojas", "Herrera", "Jimenez", "Navarro", "Cortez", "Iglesias", "Romero",
        "Contreras", "Acosta", "Cabrera", "Salazar", "Delgado", "Pineda",
        "Campos", "Alvarez"
    }
}

Config.PedHashes = {
    "a_m_m_bevhills_02",
    "a_m_m_eastsa_01",
    "a_m_m_eastsa_02",
    "a_m_m_farmer_01",
    "a_m_m_fatlatin_01",
    "a_m_m_genfat_01",
    "a_m_m_genfat_02",
    "a_m_m_golfer_01",
    "a_m_m_hasjew_01",
    "a_m_m_og_boss_01",
    "a_m_m_hillbilly_02",
    "a_m_m_indian_01",
    "a_m_m_malibu_01",
    "a_m_m_ktown_01",
}

-- Localization text for client and server
Config.Lang = {
    Client = {
        -- 3D prompts
        ShowOfferPrompt        = "[E] - Show Offer",
        StartDealWith          = "~g~[E]~s~ Start Deal with %s",

        -- Notifications / popups
        CustomerAnnoyedLeft    = "The customer got annoyed and left.",
        DealOffContactLeft     = "The deal is off! The contact left.",
        AlreadyNegotiating     = "You're already in an active negotiation. Finish your current deal first!",
        NoContactSelected      = "No contact selected.",
        ContactNotFoundInCategory = "Contact not found in any category.",
        ContactCooldown        = "Contact on cooldown in %s (%ss left).",
        NoAvailableLocations   = "No available contact locations right now. Try again shortly.",
        LocationMarkedMeet     = "Location marked. Meet the %s contact.",
        ContactImpatientLeft   = "The contact got impatient and left.",
        InsufficientLevel      = "Your level (%d) is too low. Required: %d",

        -- Misc labels
        DefaultDealerName      = "Dealer",
    },

    Server = {
        StreetDealAccepted     = "Street deal completed for $%s",
        NotEnoughItems         = "Not enough items",
        OfferDeclined          = "Offer declined",
        ErrorNoPriceData       = "Error: Price data not found!",
        YouDontHaveEnoughItems = "You don't have enough items!",

        BuyerHesitates         = "The buyer hesitates... try a better price.",
        TooExpensive           = "Too expensive. Lower your price.",
        RidiculousPrice        = "Ridiculous price! Don't try to rip me off.",
        DealSuccess            = "Deal successful! You received $%d",
    }
}

Last updated