HeroHunt AppNew

HeroHunt App: Configuration

Every option in config/config.lua, from the phone app listing and discovery map to spawns, rarities, Candy and tasks, plus the hero and task catalogs.

v1.0.0Escrow protectedQBox · QBCore · ESX · Standalone

Tip

After editing, restart only the resource with ensure hype-herohunt-app; a full server restart is not needed. Active spawns are saved in the database and come back after the restart.

The script has three config files:

FileContent
config/config.luaEvery option on this page
config/heroes.luaThe hero catalog, see Heroes
config/tasks.luaDaily, weekly and general tasks, see Tasks catalog

Each file returns one table; the sections below follow the order of config.lua. Durations use the unit in their name (...Seconds, ...Ms) and distances are in meters. Invalid hero and task entries are skipped on start and printed to the server console.

General

config/config.lua
Debug = false,
Framework = "auto",
Ownership = "character",

Prop

Type

With "character", a collection belongs to the citizenid on QBox and QBCore or the identifier on ESX. With "account", it belongs to the player's Rockstar license.

Pick Ownership before going live

Collections are stored under the owner key. Switching between "character" and "account" later does not move existing collections; players start with an empty one.

App

How the app appears in lb-phone and its App Store.

config/config.lua
App = {
    identifier = "hype-herohunt",
    name = "HeroHunt",
    description = "Explore the city, discover heroes and complete your collection.",
    developer = "Hype Studios",
    defaultApp = false,
    price = 0,
    size = 52400,
},

Prop

Type

The app icon is web/build/icon.svg. The app follows the light or dark theme set in the phone settings.

UI

Prop

Type

Discovery

The discovery area is the circle around the player on the map. Heroes inside it can be caught.

config/config.lua
Discovery = {
    Radius = 100.0,
    PreviewRadius = 150.0,
    SyncIntervalMs = 3000,
    PositionIntervalMs = 500,
    PositionMinMove = 1.0,
    Area = {
        fill = "#7c5cff",
        fillOpacity = 0.12,
        border = "#7c5cff",
        borderOpacity = 1.0,
        borderWidth = 2,
    },
},

Prop

Type

Spawns and positions are only streamed while the app is open on screen. Closing the phone stops the updates.

Spawn

Every SpawnIntervalSeconds, the server looks at each player in RoutingBucket. If fewer than TargetPerPlayer heroes are within SpawnRadius, it picks new points between MinPlayerDistance and SpawnRadius from the player (at most 4 per player per round), skips points that break the distance, density or blacklist rules and sends the rest to that player's game for a ground check. Valid points become spawns that every player sees.

config/config.lua
Spawn = {
    Enabled = true,
    MaxActiveHeroes = 300,
    SpawnIntervalSeconds = 30,
    SpawnsPerTick = 12,
    DespawnAfterSeconds = 1800,
    TargetPerPlayer = 6,
    SpawnRadius = 180.0,
    MinPlayerDistance = 20.0,
    MinSpawnDistance = 15.0,
    AreaRadius = 150.0,
    MaxPerArea = 10,
    -- ...
},

Prop

Type

The ground check rejects points without ground or navmesh, in water, inside interiors, within 3 meters of a vehicle and points where the safe position is far from the ground height.

Blacklist

Circles where heroes never spawn. Each entry has a label (only for you), an x, y center and a radius.

config/config.lua
Blacklist = {
    { label = "Fort Zancudo", x = -2200.0, y = 3100.0, radius = 900.0 },
    { label = "Bolingbroke", x = 1690.0, y = 2600.0, radius = 220.0 },
    { label = "Mission Row PD", x = 440.0, y = -982.0, radius = 45.0 },
    { label = "Pillbox Hospital", x = 307.0, y = -595.0, radius = 45.0 },
},

Regions

Named circles used by the region filter of tasks. Every spawn stores the first region (in list order) whose circle contains it, and the label appears in task titles such as Catch heroes in Downtown (3).

config/config.lua
Regions = {
    { id = "vinewood", label = "Vinewood", x = 300.0, y = 200.0, radius = 650.0 },
    { id = "downtown", label = "Downtown", x = 150.0, y = -850.0, radius = 700.0 },
    { id = "vespucci", label = "Vespucci", x = -1300.0, y = -1200.0, radius = 650.0 },
    { id = "sandy", label = "Sandy Shores", x = 1850.0, y = 3700.0, radius = 600.0 },
    { id = "paleto", label = "Paleto Bay", x = -250.0, y = 6300.0, radius = 550.0 },
},

Prop

Type

Capture

Prop

Type

Rarities

The key of each entry is the rarity id used in heroes.lua and in task filters.

config/config.lua
Rarities = {
    common    = { order = 1, color = "#94a3b8", spawnWeight = 60, catchChance = 1.0, captureCandy = 1 },
    uncommon  = { order = 2, color = "#22c55e", spawnWeight = 25, catchChance = 1.0, captureCandy = 2 },
    rare      = { order = 3, color = "#3b82f6", spawnWeight = 10, catchChance = 1.0, captureCandy = 3 },
    epic      = { order = 4, color = "#a855f7", spawnWeight = 4,  catchChance = 1.0, captureCandy = 5 },
    legendary = { order = 5, color = "#f59e0b", spawnWeight = 1,  catchChance = 1.0, captureCandy = 10 },
},

Prop

Type

The spawn weight applies per hero, so a rarity with more heroes spawns more often overall. With the default catalog (20 common, 14 uncommon, 9 rare, 5 epic and 2 legendary heroes), the odds of each spawn are:

RarityHeroesWeightOdds per spawn
Common2060~72.2%
Uncommon1425~21.1%
Rare910~5.4%
Epic54~1.2%
Legendary21~0.1%

To add a rarity, add an entry here and a label for it under rarity in every locale file.

Candy

Prop

Type

Converting gives the hero's candyValue from heroes.lua for each copy. Catching gives the rarity's captureCandy.

Tasks

Prop

Type

Security

Prop

Type

The catch cooldown is Capture.CooldownMs. Conversions and task rewards also carry a unique request id, so the same request is never paid twice.

History

Prop

Type

Heroes

The hero catalog is config/heroes.lua. It ships with 50 heroes. Add an entry to add a hero:

config/heroes.lua
return {
    { id = "hero_001", name = "Volty", rarity = "common", candyValue = 1, image = "heroes/hero_001.png", enabled = true },
    -- ...
    { id = "hero_051", name = "Nova", rarity = "epic", candyValue = 8, image = "heroes/hero_051.png",
      silhouette = "heroes/hero_051_s.png", catchChance = 0.6 },
}

Prop

Type

  • The number on each card is the hero's position in the file. Add new heroes at the end to keep the numbers.
  • The 50 included heroes have their portraits and silhouettes in web/build/heroes/. For a new hero, put both images there (or use https URLs) and set silhouette yourself. If an image cannot be loaded, the app shows a neutral robot icon instead.
  • To retire a hero, set enabled = false instead of deleting the line. Players who own copies still see it, but it no longer counts toward the collection total.
  • An entry with an invalid or duplicate id or an unknown rarity is skipped, for example: Config: heroes[51].rarity = mythic is invalid, skipped.

Tasks catalog

Tasks are defined in config/tasks.lua. Progress is only tracked from real server events: catches and conversions.

config/tasks.lua
return {
    -- Daily pool
    { id = "d_capture_5", period = "daily", type = "capture", target = 5, reward = { type = "candy", amount = 8 } },
    { id = "d_uncommon_2", period = "daily", type = "capture", target = 2, filter = { minRarity = "uncommon" }, reward = { type = "candy", amount = 10 } },
    { id = "d_downtown_3", period = "daily", type = "capture", target = 3, filter = { region = "downtown" }, reward = { type = "candy", amount = 10 } },

    -- Weekly pool
    { id = "w_epic_1", period = "weekly", type = "capture", target = 1, filter = { minRarity = "epic" }, reward = { type = "candy", amount = 45 } },

    -- General progress
    { id = "g_first_capture", period = "general", type = "capture", target = 1, title = "tasks.custom.first_capture", reward = { type = "candy", amount = 5 } },
    -- ...
}

The default file has 9 daily, 7 weekly and 10 general tasks.

Prop

Type

Periods

PeriodBehaviour
dailyResets every day at Tasks.ResetHour. Tasks.DailyCount tasks are picked from the daily pool
weeklyResets every week on Tasks.WeekStartsOn. Tasks.WeeklyCount tasks are picked from the weekly pool
generalPermanent milestones, always active and completed once

The pick is based on the date, so every player gets the same daily and weekly tasks and they change at each reset. Editing a pool and restarting the resource can change the current pick.

Types

TypeProgressFilters
captureEach catchminRarity, rarity, region, hero
discoverEach hero caught for the first time during the periodregion
discovered_totalTotal number of different heroes discovered, not period based-
capture_raritiesNumber of different rarities caught during the period-
convertEach copy converted to Candy-
earn_candyCandy earned from catches and conversions (task rewards do not count)-

Filters

Prop

Type

Custom titles

Without title, the title is generated from the type and filter, for example Catch 2 Uncommon or rarer heroes. To use your own text, add a key under tasks.custom in every locale file and point title (or description) to it. The task target is passed in as %s.

locales/en.json
"tasks": {
    "custom": {
        "first_capture": "Catch your first hero",
        "complete_collection": "Complete the collection",
        "night_hunter": "Catch %s heroes at night"
    }
}
config/tasks.lua
{ id = "g_night_hunter", period = "general", type = "capture", target = 20, title = "tasks.custom.night_hunter", reward = { type = "candy", amount = 25 } },

Tasks are written to the hero_tasks table on every start. Tasks removed from the file are disabled there, and their progress stays in the database.

Locales

The language comes from ox_lib, so it is set in server.cfg rather than in the config:

server.cfg
setr ox:locale "en"

en and tr are included. If the code has no matching file, English is used. To add a language, copy locales/en.json, translate it, save it with the language code as its name (e.g. de.json) and set ox:locale to that code. The same file holds the app texts, rarity names, task titles, the task notification and the error messages. Hero names come from heroes.lua and region names from Regions.

config.lua
heroes.lua
tasks.lua
en.json
tr.json
fxmanifest.lua

On this page