-- ============================================================================ -- M-Addon :: configuration -- One entry per harvestable in Config.Resources. Everything about a resource -- lives inside its own block — adding an ore means copying one block and -- changing the values. Anything you leave out falls back to Config.Defaults. -- -- Comments and keys are English (maintainability); every value the player can -- see is Slovenian. -- ============================================================================ Config = {} -- Language for every player-facing string. Must match a file in locales/ -- (sl.json, en.json). Set to false to follow the server's own `ox_locale` -- convar instead, which lets one setting drive every ox_lib resource. Config.Locale = 'sl' -- Global economy dial. 2.0 doubles every payout without touching a single -- resource entry. Applied server-side, after the per-reward roll. Config.RewardMultiplier = 1.0 -- Props only exist while a job is active. Wander further than this from the -- work area and the job ends by itself. Config.AutoStopDistance = 500.0 -- Accent colour, shared with M-Minigames through the GetAccent() export so -- both resources reskin together. Must match --accent in web/style.css. Config.Accent = '#E0E0E0' -- Extra units of the primary reward item granted for a perfect minigame run. -- 0 disables the bonus entirely. Config.PerfectBonus = 1 -- Fallback minigame per tool, used when a resource sets no `minigame` key. -- false = that tool gets no minigame by default. Config.ToolMinigames = { ['pickaxe'] = { 'oreStrike', 'fracturePoints' }, ['jackham'] = { 'jackRhythm' }, ['drill'] = { 'heatControl', 'drillStability' }, ['none'] = { 'sortingBins' } -- bare hands } Config.Debug = false -- draws radius markers + ox_target zone debug Config.RenderDistance = 100.0 -- how close a player must be for props to exist Config.UseLevels = true Config.UseLeaderboard = true -- ============================================================================ -- LEVELS -- 1 mined item = 1 XP. These are the *total* XP needed to reach each level. -- Levels only gate access via `minLevel` — no yield or speed bonuses. -- ============================================================================ Config.Levels = { 0, 50, 150, 300, 500, 750, 1050, 1400, 1800, 2250, 2750, 3300, 3900, 4550, 5250, 6000, 6800, 7650, 8550, 9500, 10500, 11550, 12650, 13800, 15000 } -- ============================================================================ -- DEFAULTS -- Fallbacks for anything omitted from a Config.Resources entry. -- ============================================================================ Config.Defaults = { radius = 50.0, amount = 15, duration = 6000, -- number or { min, max } in ms respawnTime = 120, -- number or { min, max } in seconds renderDistance = 100.0, category = 'Ostalo', icon = 'fa-solid fa-cube', -- Animation is picked automatically when an entry sets `anim = false`. -- Keyed by tool item name; `none` covers bare-hands harvesting. anims = { ['pickaxe'] = { anim = { dict = 'melee@large_wpn@streamed_core', clip = 'ground_attack_on_spot', flag = 49 }, prop = { model = 'prop_tool_pickaxe', bone = 28422, offset = vec3(0.0, -0.02, -0.02), rotation = vec3(-80.0, 0.0, 20.0) } }, ['jackham'] = { anim = { dict = 'amb@world_human_const_drill@male@drill@base', clip = 'base', flag = 49 }, prop = { model = 'prop_tool_jackham', bone = 28422, offset = vec3(0.0, 0.0, 0.0), rotation = vec3(0.0, 0.0, 0.0) } }, ['drill'] = { anim = { dict = 'anim@heists@fleeca_bank@drilling', clip = 'drill_straight_idle', flag = 49 }, prop = { model = 'hei_prop_heist_drill', bone = 28422, offset = vec3(0.0, 0.0, 0.02), rotation = vec3(-90.0, 0.0, 0.0) } }, ['none'] = { anim = { dict = 'amb@world_human_gardener_plant@male@base', clip = 'base', flag = 49 }, prop = false } }, -- Named particle presets. A resource picks one by name with -- effect = 'weld' -> looped while the player works -- destroyEffect = 'dust' -> one-shot when the node is harvested -- Both default to false (no particles at all). -- offset is relative to the prop's own origin: 0,0,0 puts the effect -- directly on the prop. Raise Z only if a model's origin sits at its base. effects = { -- Thermal lance burning through metal — the heist cutting-torch effect. -- This is the closest thing GTA has to welding: bright white core, -- molten spatter and smoke. Best pick for ore/scrap work. weld = { dict = 'scr_ornate_heist', name = 'scr_heist_ornate_thermal_burn', scale = 1.0, offset = vec3(0.0, 0.0, 0.1) }, -- Angle-grinder sparks: a wide fan of orange sparks, no smoke. -- Swap `weld` for this if the lance reads too bright for your scene. grind = { dict = 'core', name = 'ent_amb_metal_grinding', scale = 1.0, offset = vec3(0.0, 0.0, 0.1) }, -- Small electrical sparks. Subtlest of the three. sparks = { dict = 'core', name = 'ent_amb_sparking_wires', scale = 1.0, offset = vec3(0.0, 0.0, 0.1) }, dust = { dict = 'core', name = 'ent_dst_rocks', scale = 1.0, offset = vec3(0.0, 0.0, 0.0) }, smoke = { dict = 'core', name = 'ent_dst_gen_gobstop', scale = 1.0, offset = vec3(0.0, 0.0, 0.0) } }, -- Visuals for rare nodes; the per-resource chance lives in `rareChance`. rare = { particle = { dict = 'core', name = 'ent_amb_gas_manhole' }, blip = { sprite = 618, color = 5, scale = 0.7 } } } -- ============================================================================ -- HUD TRACKER -- Passive panel shown while a job is active. It never takes NUI focus, so it -- can never swallow mouse or keyboard input. -- ============================================================================ Config.HudEnabled = true Config.HudPosition = 'right' -- 'right' or 'left' Config.HudHideInVehicle = false -- Sound played by the quest-complete toast. Config.QuestSound = { name = 'SelectionComplete', set = 'HUD_MINI_GAME_SOUNDSET' } -- ============================================================================ -- QUESTS -- Accepted from the tablet, tracked server-side, claimed manually. -- -- objective accepts: -- { item = 'zelezo', amount = 50 } -- single material -- { items = { 'zelezo', 'aluminij' }, amount = 50 } -- 50 of each -- { items = { { item = 'zelezo', amount = 100 }, -- per-item amounts -- { item = 'aluminij', amount = 100 } } } -- -- rewards.money pays ESX cash, rewards.bank pays the bank account, and -- rewards.items go through ox_inventory with a CanCarryItem check — a reward -- that will not fit is held, never deleted. -- ============================================================================ Config.Quests = { { id = 'zelezo_1', label = 'Železna zbirka I', category = 'Rude', description = 'Delavnica na Sandy Shores je ostala brez zalog. Mojster ponuja pošteno plačilo vsakemu, ki mu prinese dovolj železa za nove tirnice. Nič posebnega, a začeti je treba nekje.', objective = { item = 'zelezo', amount = 50 }, requiredLevel = 0, rewards = { xp = 50, money = 250 }, repeatable = true, cooldown = 3600 }, { id = 'zelezo_2', label = 'Železna zbirka II', category = 'Rude', description = 'Naročilo je zdaj veliko večje — celotna proga potrebuje material. Delo bo dolgo in naporno, zato ti obljubijo tudi nov kramp, da ti staro orodje ne odpove sredi izmene.', objective = { item = 'zelezo', amount = 200 }, requiredLevel = 10, rewards = { xp = 50, money = 450, items = { { item = 'pickaxe', amount = 1 } } }, repeatable = false }, { id = 'plastika_1', label = 'Čiščenje odlagališča', category = 'Odpadki', description = 'Mestna služba ne zmore več sama. Plačajo vsakomur, ki z odlagališča pobere odvrženo plastiko in jo odda v predelavo. Umazano delo, a nihče te ne bo spraševal ničesar.', objective = { item = 'plastika', amount = 40 }, requiredLevel = 0, rewards = { xp = 30, money = 200 }, repeatable = true, cooldown = 3600 }, { id = 'plastika_2', label = 'Reciklažni obrat', category = 'Odpadki', description = 'Predelovalni obrat je dobil velik posel in potrebuje surovino v večjih količinah. Če boš dovolj vztrajen, se plačilo lepo pozna.', objective = { item = 'plastika', amount = 150 }, requiredLevel = 5, rewards = { xp = 40, money = 350 }, repeatable = true, cooldown = 7200 }, { id = 'aluminij_1', label = 'Lahka kovina I', category = 'Rude', description = 'Avtomehanik zbira aluminij za ohišja in dele karoserije. Material je lažji od železa, a ga je treba iskati dlje. Plača je temu primerna.', objective = { item = 'aluminij', amount = 75 }, requiredLevel = 5, rewards = { xp = 35, money = 400 }, repeatable = true, cooldown = 3600 }, { id = 'aluminij_2', label = 'Lahka kovina II', category = 'Rude', description = 'Letalski servis na letališču potrebuje resne količine aluminija in ne mara čakati. Delo je zahtevno, zato ti priložijo tudi vrtalnik iz svoje delavnice.', objective = { item = 'aluminij', amount = 250 }, requiredLevel = 15, rewards = { xp = 50, money = 800, items = { { item = 'drill', amount = 1 } } }, repeatable = false }, { id = 'guma_1', label = 'Stare gume', category = 'Odpadki', description = 'Za vsakim servisom se kopičijo odslužene gume in nihče jih noče odpeljati. Kdor jih zbere in odda, dobi plačilo brez odvečnih vprašanj.', objective = { item = 'guma', amount = 30 }, requiredLevel = 10, rewards = { xp = 20, money = 200 }, repeatable = true, cooldown = 3600 }, { id = 'jeklo_1', label = 'Jeklena konstrukcija', category = 'Rude', description = 'Gradbišče v Cypress Flats stoji, ker manjka jeklo za nosilce. Delo zahteva pnevmatsko kladivo in nekaj potrpljenja, plačilo pa je med boljšimi.', objective = { item = 'jeklo', amount = 60 }, requiredLevel = 15, rewards = { xp = 30, money = 300 }, repeatable = true, cooldown = 7200 }, { id = 'jeklo_2', label = 'Velika livarna', category = 'Rude', description = 'Livarna je prevzela naročilo, ki ga sama ne zmore pokriti. Iščejo izkušene delavce in so pripravljeni plačati vrhunsko — poleg denarja dobiš še lastno pnevmatsko kladivo.', objective = { item = 'jeklo', amount = 200 }, requiredLevel = 25, rewards = { xp = 50, money = 600, items = { { item = 'jackham', amount = 1 } } }, repeatable = false }, { id = 'mesanica_1', label = 'Mešano naročilo', category = 'Rude', description = 'Kupec ne želi ene same kovine, ampak oboje hkrati in v enakem razmerju. Zahteva več načrtovanja, saj boš moral menjati območja sredi dela.', objective = { items = { { item = 'zelezo', amount = 100 }, { item = 'aluminij', amount = 100 } } }, requiredLevel = 12, rewards = { xp = 30, money = 460 }, repeatable = true, cooldown = 10800 }, { id = 'odpadki_1', label = 'Velika pomlad', category = 'Odpadki', description = 'Občina je razpisala večjo akcijo čiščenja in plača po količini oddanega materiala. Plastike je največ, gume pa je težje najti v takšnih količinah.', objective = { items = { { item = 'plastika', amount = 100 }, { item = 'guma', amount = 50 } } }, requiredLevel = 12, rewards = { xp = 40, money = 400 }, repeatable = true, cooldown = 10800 }, { id = 'vsestranski', label = 'Vsestranski delavec', category = 'Rude', description = 'Največje naročilo, kar jih je. Zahteva vse materiale hkrati in te bo poslalo čez celotno mapo. Kdor to dokonča, velja med rudarji za resnega delavca — plačilo in nov vrtalnik sta temu primerna.', objective = { items = { 'zelezo', 'aluminij', 'jeklo', 'plastika', 'guma' }, amount = 50 }, requiredLevel = 20, rewards = { xp = 80, money = 800, items = { { item = 'drill', amount = 1 } } }, repeatable = false } } -- ============================================================================ -- SECURITY -- ============================================================================ Config.MaxHarvestDistance = 3.0 -- server-side distance tolerance, in metres Config.HarvestCooldown = 1500 -- hard minimum between two harvests, in ms Config.AntiCheat = { logViolations = true, kickAfter = 8, -- 0 = never kick kickReason = 'M-Addon: neveljavne zahteve' } -- ============================================================================ -- POLICE DISPATCH -- Fires a generic event so any dispatch resource can hook in. Per-resource -- chance/cooldown live in each entry's `policeAlert`. -- ============================================================================ Config.Police = { event = 'M-Addon:policeAlert', jobs = { 'police', 'sheriff' }, blip = { sprite = 51, color = 1, scale = 1.0, duration = 60 } } -- ============================================================================ -- NPC(s) — opens the tablet -- ============================================================================ Config.NPCs = { { model = 's_m_y_construct_01', coords = vec4(2832.5886, 2799.9304, 57.4762, 100.4729), scenario = 'WORLD_HUMAN_CLIPBOARD', invincible = false, frozen = true, blip = { enabled = false, sprite = 618, color = 46, scale = 0.8, label = 'Rudarski nadzornik' } } } -- Prop held while the tablet is open. Config.TabletProp = { model = 'prop_cs_tablet', bone = 28422, offset = vec3(0.03, 0.002, -0.05), rotation = vec3(20.0, -90.0, 0.0), anim = { dict = 'amb@world_human_seat_wall_tablet@female@base', clip = 'base' } } Config.AdminAce = 'maddon.admin' -- ============================================================================ -- RESOURCES -- Minimal entry (everything else falls back to Config.Defaults): -- -- { id = 'zelezo', label = 'Železo', coords = vec3(...), -- props = { 'prop_rock_4_a' }, tool = 'pickaxe', reward = 'zelezo' } -- -- Tool behaviour is decided per entry: -- tool = false -> bare hands -- tool = 'pickaxe', consume = false -> permanent, kept after use -- tool = 'dinamit', consume = true -> consumable, removed on every harvest -- tool = 'drill', removeChance = 5 -> kept, 5% chance per harvest to be lost -- -- reward accepts a shorthand string (1x at 100%) or the long form: -- reward = 'zelezo' -- reward = { { item = 'zelezo', min = 1, max = 3, chance = 100 }, -- { item = 'aluminij', min = 1, max = 1, chance = 15 } } -- -- Minigames (requires M-Minigames; skipped cleanly if it is not running): -- minigame = false -> plain progress bar, no minigame -- minigame = 'oreStrike' -> always this one -- minigame = { 'oreStrike', 'jackRhythm' } -> random pick per harvest -- minigame = nil -> pick from Config.ToolMinigames -- minigameDifficulty = 'medium' -> or a 0.0-1.0 number -- -- Optional keys, all off by default: -- minLevel, jobs, anim, blip, policeAlert, -- rareChance, rareReward, depleteAfter, depleteTime -- ============================================================================ Config.Resources = { { id = 'zelezo', label = 'Železo', category = 'Rude', icon = 'fa-solid fa-cube', coords = vec3(285.2352, 2860.3049, 43.6418), radius = 20.0, amount = 25, props = { 'prop_rub_carwreck_2', }, tool = 'drill', effect = 'weld', reward = 'zelezo', duration = 6000, respawnTime = 120, minigame = { 'heatControl', 'drillStability' }, minigameDifficulty = 'easy', blip = { sprite = 618, color = 5, scale = 0.8 } }, { id = 'aluminij', label = 'Aluminij', category = 'Rude', icon = 'fa-solid fa-cubes', coords = vec3(2469.5439, 3771.8811, 41.2851), radius = 25.0, amount = 20, props = { 'imp_prop_impexp_front_bumper_02a' }, tool = 'drill', effect = 'weld', reward = 'aluminij', duration = 6500, respawnTime = 140, minigame = { 'heatControl', 'drillStability' }, minigameDifficulty = 'medium', minLevel = 5 }, { id = 'jeklo', label = 'Jeklo', category = 'Rude', icon = 'fa-solid fa-industry', coords = vec3(2405.7039, 3108.2788, 48.1211), radius = 20.0, amount = 15, props = { 'prop_byard_pipes01' }, tool = 'jackham', effect = 'weld', reward = { { item = 'jeklo', min = 1, max = 2, chance = 100 } }, duration = 9000, respawnTime = 200, minLevel = 15, minigame = 'jackRhythm', minigameDifficulty = 'medium' }, { id = 'plastika', label = 'Plastika', category = 'Odpadki', icon = 'fa-solid fa-recycle', coords = vec3(2239.6648, 1601.5458, 73.9644), radius = 20.0, amount = 20, props = { 'm23_2_prop_m32_plasticcan_01a' }, tool = 'none', reward = 'plastika', duration = 4000, respawnTime = 90, minigame = 'sortingBins', minigameDifficulty = 'easy' }, { id = 'guma', label = 'Guma', category = 'Odpadki', icon = 'fa-solid fa-circle-notch', coords = vec3(2348.0806, 2597.1648, 46.5163), radius = 20.0, amount = 12, props = { 'prop_tyre_01' }, tool = 'none', reward = 'guma', duration = 5000, respawnTime = 120, minLevel = 10, minigame = 'sortingBins', minigameDifficulty = 'medium' }, }