Skip to main content

Config = {}

Config.Debug = false -- Enables extra debug prints.
Config.Locale = 'en' -- Active locale key from Config.Locales.

Config.Framework = 'auto' -- auto / esx / qb / qbox / standalone
Config.Notification = 'auto' -- auto / ox / esx / qb
Config.UI = 'auto' -- auto / ox / custom
Config.Inventory = 'auto' -- auto / ox / esx / qb / qbox
Config.Interact = 'auto' -- auto / target / textui / custom
Config.Target = 'auto' -- auto / ox_target / qb-target / qtarget / false

Config.ImagePath = 'nui://ox_inventory/web/images/' -- Optional image path for item previews or metadata.
Config.PhoneItem = 'illegal_phone' -- Usable item that opens the trap phone when enabled.

Config.Phone = {
    UseCommand = true, -- Enables the trap phone command.
    Command = 'trapphone', -- Command used to open the trap phone.
    RegisterUsableItem = true -- Registers Config.PhoneItem through the detected framework when possible.
}

Config.Payment = {
    Type = 'account', -- account / item
    Account = 'black_money', -- Used when Type = account.
    CashItem = 'black_money' -- Used when Type = item.
}

Config.Dispatch = {
    Enabled = false, -- Master switch for police dispatch alerts fired from completed sales or house-police outcomes.
    System = 'none', -- none / cd_dispatch / codem_dispatch / kartik-mdt / lb-tablet / origen_police / piotreq_gpt / ps-dispatch / rcore_dispatch
    Chance = 20, -- Percent chance to send dispatch after a successful sale. Example: 20 = 20% chance.
    RequirePolice = true, -- true = only roll dispatch when at least one configured police job is online.
    PoliceJobs = { 'police' }, -- Job names treated as police for online checks and dispatch recipient tables.
    Title = 'Drug Dealing In Progress', -- Main dispatch title.
    Message = 'Possible drug dealing reported in the area.', -- Main dispatch message/body.
    CodemCode = '10-14', -- Code used by codem-dispatch.
    PiotreqEvent = 'nahs_drugsell:piotreqgptalert', -- Server event used for piotreq_gpt integrations.
    OrigenEvent = 'SendAlert:police', -- Server event used for origen_police integrations.
    Blip = {
        sprite = 161, -- Dispatch blip sprite.
        color = 5, -- Gold/yellow style dispatch blip color.
        scale = 1.2, -- Dispatch blip scale.
        flashes = false, -- Flashing blip toggle where supported.
        time = 5, -- Minutes or resource-specific time unit where supported.
        radius = 0 -- Dispatch radius where supported.
    }
}

Config.Enabled = {
    Corner = true, -- Enables corner buyers that walk up to you on foot.
    Street = true, -- Enables nearby pedestrian street sales.
    Vehicle = true, -- Enables seated in-vehicle sales.
    Window = true, -- Enables vehicle window sales.
    TrapPhone = true, -- Enables the trap phone sales submenu.
    MeetUps = true, -- Enables trap phone meet-up routes.
    HouseSales = true, -- Enables trap phone house-drop routes.
    Payphone = true, -- Enables payphone lead sales from world booth props only.
    SellAll = true, -- Enables the sell-all option anywhere it applies.
    Reputation = true, -- Enables reputation pages in the phone.
    Achievements = true, -- Enables achievements pages in the phone.
    TopSellers = true -- Enables the leaderboard pages in the phone.
}

Config.Sales = {
    InteractDistance = 2.0, -- Distance used for nearby deal prompts. Example: 2.0 = about two meters.
    DoorPlaceDistance = 2.0, -- Distance used for house-door interactions. Example: 2.0 = stand close to the door.
    StreetScanRadius = 6.0, -- Radius used to look for nearby street-sale pedestrians.

    CornerBuyerDelayMin = 22, -- Seconds before the next possible corner buyer. Example: 22 = 22 seconds.
    CornerBuyerDelayMax = 42, -- Maximum seconds before the next possible corner buyer.
    VehicleBuyerDelayMin = 26, -- Seconds before the next possible vehicle/window buyer.
    VehicleBuyerDelayMax = 45, -- Maximum seconds before the next possible vehicle/window buyer.

    DirectDealTimeout = 90, -- Seconds before a direct buyer deal expires.
    MeetLeadTimeout = 240, -- Seconds before a meet-up or payphone lead expires.
    HouseLeadTimeout = 180, -- Seconds before a house lead expires.
    HouseKnockDuration = 2.6, -- Seconds spent knocking on the door.
    HouseDropDuration = 4.2, -- Seconds spent placing the package down.

    SuccessfulBuyerDespawnMin = 15, -- Minimum seconds a successful buyer lingers before cleanup.
    SuccessfulBuyerDespawnMax = 30, -- Maximum seconds a successful buyer lingers before cleanup.

    BuyerSpawnRadius = 42.0, -- General spawn radius for generated buyers.
    BuyerApproachSpeed = 2.1, -- Walk speed for buyers approaching on foot.
    BuyerWindowApproachSpeed = 2.35, -- Walk speed for buyers approaching a vehicle window.
    VehicleMaxSpeedMph = 10.0, -- Vehicle must stay at or below this speed during a handoff.
    DisableVehicleRouteOnExit = true, -- true = leaving the vehicle shuts vehicle/window routes down; false = route stays active after exit.
    WaypointArriveDistance = 45.0, -- Distance from the meet point before the buyer can spawn.

    StreetAcceptBase = 0.58, -- Base street acceptance chance before reputation is factored in.
    StreetAcceptRepBonusPer100 = 0.12, -- Extra acceptance chance per 100 reputation.
    StreetAcceptMax = 0.88 -- Hard cap for street acceptance chance.
}

Config.ModeRules = {
    corner = {
        label = 'Corner', -- Spawned foot buyer walks up to you for a quick exchange.
        payoutMultiplier = 0.90,
        repMultiplier = 1.20,
        failChanceBonus = -0.03
    },
    street = {
        label = 'Street', -- World ped sales. Better acceptance with reputation.
        payoutMultiplier = 1.00,
        repMultiplier = 1.00,
        failChanceBonus = 0.10
    },
    vehicle = {
        label = 'Vehicle', -- Buyer gets inside the vehicle when a seat is free.
        payoutMultiplier = 1.08,
        repMultiplier = 0.95,
        failChanceBonus = 0.01
    },
    window = {
        label = 'Window', -- Buyer stays outside on the driver-side window.
        payoutMultiplier = 0.96,
        repMultiplier = 0.90,
        failChanceBonus = 0.03
    },
    meetup = {
        label = 'Meet Up', -- Trap phone GPS meet with a spawned buyer.
        payoutMultiplier = 1.12,
        repMultiplier = 1.10,
        failChanceBonus = 0.00
    },
    house = {
        label = 'House', -- Trap phone house-door drop. No buyer ped is used.
        payoutMultiplier = 1.18,
        repMultiplier = 1.18,
        failChanceBonus = -0.04
    },
    payphone = {
        label = 'Payphone', -- Higher-risk meet route with denial and attack chances.
        payoutMultiplier = 1.15,
        repMultiplier = 1.08,
        failChanceBonus = 0.04
    }
}

Config.PayphoneOutcomes = {
    sentoff = 14, -- Nobody shows or the line goes cold.
    denied = 16, -- Buyer sees the scene and backs out.
    robbed = 10, -- Buyer takes the product and runs.
    attack = 7, -- Buyer turns hostile instead of buying.
    success = 53 -- Clean completed payphone sale.
}

Config.HouseOutcomes = {
    accept = 72, -- Occupant accepts the drop after the knock.
    denied = 14, -- Occupant declines the deal.
    sentoff = 9, -- Nobody answers or the lead goes cold at the door.
    police = 5 -- Occupant calls the police instead.
}

Config.PhoneBooths = {
    -429560270,
    -1559354806,
    -78626473,
    295857659,
    -2103798695,
    1158960338,
    1511539537,
    1281992692
} -- World payphone booth object hashes used for target/text UI detection.

Config.MeetLocations = {
    { label = 'Jamestown Drop', coords = vec4(108.87, -1088.79, 29.30, 344.92) },
    { label = 'Alta Alley', coords = vec4(-268.20, -957.89, 31.22, 199.27) },
    { label = 'South Mirror Spot', coords = vec4(1008.77, -1866.19, 30.89, 84.17) },
    { label = 'La Puerta Lot', coords = vec4(-830.63, -1208.27, 6.93, 317.41) }
}

Config.HouseLocations = {
    { label = 'Forum Drive Door', coords = vec4(-53.15, -1783.29, 28.30, 48.12) },
    { label = 'Jamestown Door', coords = vec4(320.43, -2040.62, 20.89, 49.16) },
    { label = 'Davis Back Door', coords = vec4(196.25, -1721.72, 29.67, 230.15) },
    { label = 'Grove Side Door', coords = vec4(85.62, -1959.49, 21.12, 316.84) }
}

Config.PedModels = {
    `g_m_y_ballaeast_01`,
    `g_m_y_famdnf_01`,
    `g_m_y_mexgoon_02`,
    `g_m_m_chigoon_01`,
    `a_m_y_stbla_02`,
    `a_m_y_smartcaspat_01`,
    `a_f_y_hipster_03`,
    `a_m_y_eastsa_02`
}

Config.StreetSale = {
    UseGlobalTarget = true, -- true = target systems use one global ped target; false = only the nearest valid ped is targeted.
    UsePedModelsOnly = false, -- true = only models listed in Config.PedModels can be sold to; false = any valid ambient ped can be used.
    IgnorePlayerPeds = true, -- Prevents targeting other players.
    RejectAnimals = true, -- Prevents animal peds.
    RejectDead = true, -- Prevents dead or dying peds.
    RejectInCombat = true, -- Prevents combat peds.
    RejectMissionEntities = true, -- Prevents mission peds from being used.
    RejectArmedPeds = false -- Set true if you want to skip armed pedestrians.
}

Config.Drugs = {
    weed = {
        label = 'Weed',
        item = 'weed',
        minQty = 1,
        maxQty = 4,
        baseMin = 72,
        baseMax = 104,
        baseFailChance = 0.18,
        repPerSale = 2,
        repPerItem = 1
    },
    baggedweed = {
        label = 'Bagged Weed',
        item = 'baggedweed',
        minQty = 1,
        maxQty = 5,
        baseMin = 84,
        baseMax = 118,
        baseFailChance = 0.17,
        repPerSale = 2,
        repPerItem = 1
    },
    coke = {
        label = 'Cocaine',
        item = 'coke',
        minQty = 1,
        maxQty = 3,
        baseMin = 120,
        baseMax = 170,
        baseFailChance = 0.26,
        repPerSale = 4,
        repPerItem = 2
    },
    crack = {
        label = 'Crack',
        item = 'crack',
        minQty = 1,
        maxQty = 3,
        baseMin = 130,
        baseMax = 182,
        baseFailChance = 0.28,
        repPerSale = 4,
        repPerItem = 2
    },
    meth = {
        label = 'Meth',
        item = 'meth',
        minQty = 1,
        maxQty = 3,
        baseMin = 128,
        baseMax = 176,
        baseFailChance = 0.30,
        repPerSale = 5,
        repPerItem = 2
    },
    pinkmeth = {
        label = 'Pink Meth',
        item = 'pinkmeth',
        minQty = 1,
        maxQty = 2,
        baseMin = 165,
        baseMax = 230,
        baseFailChance = 0.34,
        repPerSale = 6,
        repPerItem = 3
    }
}

Config.PropByDrug = {
    weed = `sf_prop_sf_bag_weed_01b`,
    baggedweed = `m25_1_prop_m51_bag_weed_01a`,
    coke = `xm3_prop_xm3_bag_coke_01a`,
    crack = `bkr_prop_coke_cutblock_01`,
    meth = `tr_prop_meth_smallbag_01a`,
    pinkmeth = `tr_prop_meth_smallbag_01a`
}

Config.Reputation = {
    TopSellerLimit = 10, -- Number of top sellers shown in the leaderboard.
    FailPenalty = 2, -- Penalty for failed or robbed deals that go wrong.
    RobPenalty = 3, -- Penalty for robbery outcomes.
    AttackPenalty = 2, -- Penalty when a payphone lead turns hostile.
    ranks = {
        { threshold = 0, label = 'Unknown' },
        { threshold = 35, label = 'Runner' },
        { threshold = 90, label = 'Mover' },
        { threshold = 180, label = 'Street Name' },
        { threshold = 320, label = 'Trusted Plug' },
        { threshold = 520, label = 'Area Supplier' },
        { threshold = 780, label = 'Pipeline' }
    },
    achievements = {
        { key = 'first_sale', title = 'First Drop', description = 'Complete your first sale.', type = 'sales', threshold = 1 },
        { key = 'ten_sales', title = 'Made a Name', description = 'Complete 10 sales.', type = 'sales', threshold = 10 },
        { key = 'fifty_sales', title = 'Known Face', description = 'Complete 50 sales.', type = 'sales', threshold = 50 },
        { key = 'hundred_sales', title = 'District Mover', description = 'Complete 100 sales.', type = 'sales', threshold = 100 },
        { key = 'grand_earner', title = 'Four Figures', description = 'Make $1,000 from sales.', type = 'earnings', threshold = 1000 },
        { key = 'five_grand', title = 'Five Up', description = 'Make $5,000 from sales.', type = 'earnings', threshold = 5000 },
        { key = 'rep_100', title = 'Street Respect', description = 'Reach 100 reputation.', type = 'rep', threshold = 100 },
        { key = 'rep_500', title = 'Network Built', description = 'Reach 500 reputation.', type = 'rep', threshold = 500 }
    }
}

Config.Webhooks = {
    enabled = false, -- Turns webhook posting on or off.
    sales = '', -- Successful sale logs.
    robbed = '', -- Robbery outcome logs.
    failed = '', -- Denied, sent-off, or attack outcome logs.
    house = '' -- House drop logs.
}

Config.Locales = {
    en = {
        menu_phone_title = 'Trap Phone',
        menu_reputation = 'Reputation',
        menu_achievements = 'Achievements',
        menu_top_sellers = 'Top Sellers',
        menu_corner = 'Corner Sales',
        menu_street = 'Street Sales',
        menu_vehicle = 'Vehicle Sales',
        menu_window = 'Window Sales',
        menu_trap = 'Trap Phone Sales',
        menu_payphone = 'Payphone Sales',
        menu_meetups = 'Meet Up Sales',
        menu_house = 'House Sales',
        menu_back = 'Back',
        menu_sell_all = 'Sell All Available',
        menu_locked = 'Locked',
        menu_no_stock = 'No sellable product on hand right now.',
        menu_choose_drug = 'Choose Product',
        menu_choose_amount = 'Choose Amount',
        menu_active_route = 'Active Route',
        menu_status = 'Status',

        desc_corner = 'Wait for a foot buyer to walk up to you.',
        desc_street = 'Offer product to nearby pedestrians on foot.',
        desc_vehicle = 'Spawn a buyer who gets inside your vehicle for the sale.',
        desc_window = 'Spawn a buyer who works the driver window only.',
        desc_trap = 'Meet buyers at a location or work a door drop.',
        desc_payphone = 'Riskier public lead with robbery and attack chances.',
        desc_meetups = 'Set a meet point and close the deal in person.',
        desc_house = 'Go to a door, knock, and complete the drop if the client accepts.',
        desc_reputation = 'View rank, earnings, and progression.',
        desc_achievements = 'Track sales milestones.',
        desc_top = 'See who is moving the most product.',

        state_enabled = 'Enabled',
        state_disabled = 'Disabled',
        state_active = 'Active',
        state_inactive = 'Inactive',
        state_arrived = 'Arrived',
        state_enroute = 'En Route',

        title_reputation = 'Reputation Overview',
        title_achievements = 'Achievement Board',
        title_top_sellers = 'Top Sellers',
        title_trap_sales = 'Trap Phone Sales',
        title_payphone_sales = 'Payphone Sales',
        title_choose_house = 'Choose A House Route',
        title_house_drop = 'House Drop',
        title_meetup_deals = 'Meet Up Sales',
        title_choose_amount = 'Choose Amount',
        title_choose_product = 'Choose Product',

        notify_mode_enabled_title = 'Line Active',
        notify_mode_enabled_desc = 'That route is now taking business.',
        notify_mode_disabled_title = 'Line Closed',
        notify_mode_disabled_desc = 'That route has been shut down.',
        notify_busy_title = 'Busy',
        notify_busy_desc = 'Finish your current interaction first.',
        notify_no_drugs_title = 'No Product',
        notify_no_drugs_desc = 'You do not have any configured product to move.',
        notify_out_of_stock_title = 'Out Of Product',
        notify_out_of_stock_desc = 'Your active route was shut down because you are out of configured product.',
        notify_cancel_title = 'Sale Cancelled',
        notify_cancel_desc = 'You backed out before the exchange finished.',
        notify_ped_gone_title = 'Buyer Gone',
        notify_ped_gone_desc = 'The buyer lost patience and moved on.',
        notify_too_far_title = 'Too Far Away',
        notify_too_far_desc = 'You drifted too far away from the buyer.',
        notify_vehicle_moving_title = 'Moving Too Fast',
        notify_vehicle_moving_desc = 'Slow down and keep the vehicle steady for the handoff.',
        notify_vehicle_exit_title = 'Vehicle Route Disabled',
        notify_vehicle_exit_desc = 'You left the vehicle, so the vehicle line was shut down.',
        notify_declined_title = 'Buyer Declined',
        notify_declined_desc = 'They were not interested and moved off.',
        notify_expired_title = 'Window Closed',
        notify_expired_desc = 'That opportunity expired before you closed the deal.',
        notify_lead_sent_title = 'Lead Sent',
        notify_lead_sent_desc = 'A buyer dropped a location on your GPS.',
        notify_lead_arrived_title = 'Buyer Nearby',
        notify_lead_arrived_desc = 'The buyer is close. Keep it smooth.',
        notify_success_title = 'Deal Completed',
        notify_success_desc = 'The handoff was clean and the money is in.',
        notify_rank_up_title = 'Reputation Rank Up',
        notify_rank_down_title = 'Reputation Rank Down',
        notify_achievement_title = 'Achievement Unlocked',
        notify_leaderboard_up_title = 'Leaderboard Improved',
        notify_no_vehicle_title = 'No Vehicle Sale',
        notify_no_vehicle_desc = 'Get in a vehicle before enabling that route.',
        notify_door_ready_title = 'Door Ready',
        notify_door_ready_desc = 'You are at the drop. Knock and wait for the client to answer.',
        notify_payphone_cold_title = 'Line Went Cold',
        notify_payphone_cold_desc = 'Nobody showed from that public line.',
        notify_payphone_robbed_title = 'Robbed',
        notify_payphone_robbed_desc = 'The buyer snatched the product and ran.',
        notify_payphone_attack_title = 'Set Up',
        notify_payphone_attack_desc = 'This lead turned hostile.',
        notify_street_decline_title = 'Street Buyer Declined',
        notify_street_decline_desc = 'They backed out and took off.',
        notify_meetup_arrive_title = 'Meet Point Reached',
        notify_meetup_arrive_desc = 'The buyer is pulling in now.',
        notify_house_started_title = 'House Route Set',
        notify_house_started_desc = 'Head to the marked house and work the door.',
        notify_invalid_quantity_title = 'Invalid Amount',
        notify_invalid_quantity_desc = 'Choose a valid amount for that product.',
        notify_locked_title = 'Route Locked',
        notify_locked_desc = 'That route is disabled in the config.',
        notify_no_seat_title = 'No Open Seat',
        notify_no_seat_desc = 'There is no open passenger seat for that buyer right now.',
        notify_house_denied_title = 'House Denied',
        notify_house_denied_desc = 'They turned the drop away at the door.',
        notify_house_sentoff_title = 'No Answer',
        notify_house_sentoff_desc = 'Nobody answered the door for the drop.',
        notify_house_police_title = 'Police Called',
        notify_house_police_desc = 'The occupant called the police. Leave the area.',
        notify_phone_line_title = 'Calling Client',
        notify_phone_line_desc = 'Keep the line clean while the client answers.',

        alert_sale_header = 'Street Transaction',
        alert_sale_confirm = 'Confirm Sale',
        alert_sale_cancel = 'Walk Away',
        alert_house_header = 'House Drop',
        alert_house_confirm = 'Place Package',
        alert_house_cancel = 'Leave',
        alert_house_content = 'Place **x%s %s** at **%s** for **$%s**?',

        stat_rep = 'Reputation',
        stat_rank = 'Rank',
        stat_sales = 'Completed Sales',
        stat_items = 'Items Moved',
        stat_earnings = 'Gross Earnings',
        stat_position = 'Leaderboard Position',
        stat_route = 'Route',
        stat_you = 'You',

        meta_offer_each = 'Buyer offer price',
        meta_risk_bonus = 'Risk bonus',
        meta_rep_bonus = 'Rep. bonus',
        meta_buyer_total = 'Buyer wants a total of',
        meta_sale_total = 'Total sale is worth',
        meta_mode = 'Sale route',
        meta_success = 'Success chance',
        meta_stock = 'On hand',

        achievement_locked = 'Locked',
        achievement_unlocked = 'Unlocked',

        progress_review = 'Negotiating prices...',
        progress_exchange = 'Making the handoff...',
        progress_vehicle_exchange = 'Handling the vehicle sale...',
        progress_phone = 'Calling client...',
        progress_house = 'Dropping off drugs...',
        progress_street_talk = 'Talking to pedestrian...',
        progress_payphone = 'Working the payphone line...',
        progress_knock = 'Knocking on the door...',

        textui_review = '[E] Review buyer offer',
        textui_street = '[E] Offer product',
        textui_house = '[E] Work the door',
        textui_meet = '[E] Complete deal',
        target_street = 'Offer product',
        target_house = 'Work the door',
        target_meet = 'Complete deal',
        textui_payphone = '[E] Use payphone',
        target_payphone = 'Use payphone',

        sale_route_corner = 'Corner',
        sale_route_street = 'Street',
        sale_route_vehicle = 'Vehicle',
        sale_route_window = 'Window',
        sale_route_meetup = 'Meet Up',
        sale_route_house = 'House',
        sale_route_payphone = 'Payphone',

        choice_sell_all_desc = 'Move every configured stack right now.',
        choice_locked_desc = 'This route is currently disabled.',
        choice_on_hand = 'On hand'
    }
}