Bounty Hunter¶
hobbs_bountyhunter, current version 1.0.1
Overview¶
Puts a bounty board at every sheriff office you configure. Players read the posters, ride out alone or as a posse of up to four, deal with a gang of bandits and bring the wanted man back to the office, dead or alive. Some jobs ask for the man alive, some ask you to free hostages from a hideout and walk them home. Every finished job pays cash and XP, XP moves the player up five ranks, and the harder posters only open up at higher ranks.
The script ships with 70 posters: 55 gang jobs in five difficulties and 15 hostage rescues. Bandits spawn at one of 37 spawn points spread over the whole map, hostage jobs use one of 16 hideouts. Jobs, ranks and cooldowns are stored in the database, so nothing is lost on a restart. If you want, every hunt start, payout, failure, new rank and admin action goes to Discord.
How it plays
- You walk up to the bounty board at a sheriff office and press E. A board opens with three tabs: Posters, Posse and Career.
- On the Posse tab you type the server ID of a friend and invite them. They get a notification and answer at any board. Up to four riders, the one who invites is the leader.
- On the Posters tab you pick a job. Each poster shows the wanted man, what he is wanted for, the difficulty, the money range for your rank and the XP. Posters above your rank are shown but locked, posters any posse took in the last 90 minutes say "Taken".
- The leader accepts. Every member has to stand within 10 meters of the board. A route and a blip point to the spawn area, which is drawn fresh for every hunt.
- When the first member gets within 100 meters of the spot, the gang spawns and attacks. The leader's game spawns them, the server checks that they really arrived. The wanted man is marked with his own blip and name, the rest are plain bandits.
- Dead or alive: shoot everyone, or leave the boss standing and bring him in alive. Alive only: the boss has to survive, if he dies the job fails. Once the gang is down you get a message to bring the target back to the same office you took the poster from.
- Hostage rescue: the hostages kneel tied up next to the guards. Once the last guard is dead they are free and each one follows a member of the posse, on foot or riding behind on the horse. Every hostage that reaches the office counts.
- Back at the office the leader drops the target near the turn-in spot. The turn-in happens on its own a few seconds later, or you press "Turn in bounty" on the board. Every member standing within 100 meters gets their share of the cash and XP, a message shows the sum, and a new rank is announced if you crossed the line.
- After a hunt every member waits 29 minutes before the next one, and the same poster stays locked for 90 minutes for the whole server.
Requirements¶
| Resource | Note |
|---|---|
vorp_core |
Characters, cash, notifications and the death and revive events |
nss_libs |
Prompts, blips, the database layer, character data and client-server events |
oxmysql |
Database behind nss_libs |
No job is needed. Any character can read a board and take a job, the only gate is the rank. The admin command needs the VORP group admin or the admin flag on the character.
Installation¶
- Unpack the resource into
resourcesand keep the folder namehobbs_bountyhunter. - Run
sql/install.sqlon your database. It creates three tables:hobbs_bountyhunter_xp(XP, rank and statistics per character),hobbs_bountyhunter_hunts(every hunt with state, members, payout and XP) andhobbs_bountyhunter_member_cooldowns(when each character last finished a hunt). The resource also creates the tables on its own at start and adds the streak and payout columns, so the file is a convenience, not a must. - There are no items and no item images to add, and no jobs to create.
-
Add it to
server.cfgafter its dependencies: -
Open
server_config.luaand paste your Discord webhook URLs if you want the log. Empty means off. - Set
Config.Localeinconfig/config.luatoenorde. - Start the server. Watch the console for a yellow warning about empty spawn points, the list is filled by default, so you should see none. Any hunt that was still running when the server went down is set to failed on boot and the cooldown for its members is written.
Note
server_config.lua stays on the server. Everything in config/ is sent to every client, so never put a webhook URL into a config file.
Configuration¶
Settings are split over config/config.lua (general), config/boards.lua (the boards), config/bounties.lua (the posters and spawn points), config/hostages.lua (hideouts and hostage behaviour), config/npc.lua (bandits), config/payouts.lua (money and XP), config/ratelimit.lua and server_config.lua (Discord). All texts live in locales.lua.
General¶
Config.Locale = 'en' -- "en" or "de"
Config.Debug = false -- console output, and it switches cooldowns and the poster lock off
Config.AdminGroups = { 'admin' } -- VORP groups that may use the admin command
Config.AdminCommand = 'bounty' -- /bounty admin ...
Config.Notify = {
dict = 'generic_textures',
duration = 5000,
topics = {
info = { icon = 'tick' },
warn = { icon = 'cross', duration = 6000 },
posse = { icon = 'tick' },
reward = { icon = 'tick', duration = 7000 },
hostage = { icon = 'tick' },
rank = { icon = 'tick', duration = 7000 },
},
}
Notifications go through vorp_core (NotifyLeft). Each topic has its own title in locales.lua (notify_title_<topic>), so the player sees "Posse", "Bounty" or "Hostage rescue" above the text.
Config.Debug is for testing on a development server. Besides the console output it turns off the 29 minute cooldown and the 90 minute poster lock, so you can run the same job again and again. Leave it false on a live server.
Posse¶
Config.Posse = {
Max = 4, -- members including the leader
InviteTtlMs = 20000, -- an invite expires after this time
ShowMemberBlips = false, -- blips of the posse members on the map
LockedDuringHunt = true, -- no leave, kick or invite while a hunt runs
}
A player is always in a posse, alone until they invite someone. The leader invites by server ID on the Posse tab. The invited player has 20 seconds to accept at a board. Only a player who is riding alone and not on a hunt can be invited, otherwise the leader sees "is already in a posse".
With LockedDuringHunt = true the posse is frozen from accept to payout. I kept it that way because a member who leaves in the middle of a job would still count for the payout split, and a new one would appear out of nowhere at the office. If a member disconnects during a hunt they are dropped anyway. When the leader drops, the next member becomes leader. When nobody is left, the hunt fails.
ShowMemberBlips = true puts a blip on every posse member. Handy on a small server, noisy on a big one.
Boards¶
Config.Boards = {
ChunkRadius = 50.0, -- the board prop exists within this distance
PromptRadius = 2.0, -- default prompt distance, a board can override it with interactDist
StartAllMembersRadius = 10.0, -- every member has to be this close to the board to start a hunt
PromptKey = 0xCEFD9220, -- E
}
The boards themselves are in config/boards.lua. Seven ship with the script: Blackwater, Valentine, Annesburg, Rhodes, Strawberry, Saint Denis and Tumbleweed. Treat them as examples, move or replace them to fit your map.
Config.SheriffBoards = {
{
id = 'valentine',
name = 'Valentine',
vector = vector4(-270.01, 807.2, 119.36, 100.0),
turnInVector = vector3(-276.21, 815.75, 119.14),
prop = 'mp005_p_mp_bountyboard01x',
interactDist = 1.5,
turnInDistance = 5.0,
},
-- ...
}
| Key | Meaning |
|---|---|
id |
Short name, used in the database and in notifications. Keep it unique |
name |
Town name. The label becomes board_label from the locale, "Sheriff office Valentine" |
vector |
Position and heading of the board |
turnInVector |
Where the target or the hostages have to be brought. Leave it out to use the board position |
prop |
Board model. Leave it out where the town already has a board, as in Annesburg, Rhodes and Tumbleweed |
interactDist |
How close you have to stand for the prompt, default Config.Boards.PromptRadius |
turnInDistance |
How close the target or hostage has to be to the turn-in spot, default 8 |
blipSprite |
Optional, replaces Config.Blips.Boards.Sprite for this board only |
The prop is only created while a player is within ChunkRadius, so an empty town costs nothing. A job is always turned in at the board where it was taken, no matter where the gang spawned. Put turnInVector in front of the office door or next to the jail, somewhere a player can drop a body without blocking the board.
Bounties¶
Everything about the posters is in config/bounties.lua. The texts (label, description, wanted for) are in locales.lua under bounty_<key>_label, bounty_<key>_desc and bounty_<key>_wanted.
Config.BountySpawnAnchors = {
vector3(1931.41, 1959.48, 263.65),
vector3(1597.04, -1844.32, 52.4),
-- ... 37 in total
}
Config.Bounties = {
west_dakota_raiders = {
type = 'dead_or_alive',
target_name = 'Elias Crowe',
min_tier = 'bronze',
difficulty = 1,
enemies = {
{ count = 4 },
},
payout = { xp = 10 },
time_limit_sec = 60 * 45,
},
dakota_horse_thieves = {
type = 'alive_only',
target_name = 'Silas Boone',
min_tier = 'bronze',
difficulty = 2,
enemies = {
{ count = 3 },
{ count = 2, mounted_count = 2 },
},
payout = { xp = 16 },
time_limit_sec = 60 * 45,
},
hostage_stagecoach_passengers = {
type = 'prisoner_rescue',
min_tier = 'gold',
difficulty = 3,
enemies = {
{ count = 5 },
{ weapon = 'WEAPON_REPEATER_CARBINE', count = 3 },
},
hostages = 2,
payout = { xp = 24 },
time_limit_sec = 60 * 45,
},
-- ...
}
| Key | Meaning |
|---|---|
type |
dead_or_alive, alive_only or prisoner_rescue |
target_name |
Name of the wanted man, shown on the poster, on his blip and above his head. Not used for rescues |
min_tier |
Rank needed to take the poster: bronze, silver, gold, outlaw or legend |
difficulty |
1 to 5. Scales bandit health and accuracy (config/npc.lua) and the money (config/payouts.lua) |
enemies |
Groups of { count, weapon?, mounted_count? }. Without weapon each bandit gets a random one from RandomWeaponPool. mounted_count bandits of the group come on horseback |
hostages |
Rescues only, 1 or 2. The hideout needs at least that many kneeling spots |
fail_on_target_death |
true fails the job when the target dies. Always on for alive_only |
payout |
{ xp }. The money is not set here, it comes from the difficulty |
time_limit_sec |
Optional, default Config.HuntWatchdog.MaxDurationSec |
The first bandit the gang spawns is the wanted man. On a dead or alive job you can shoot him, or kill the others and bring him in breathing, which counts as "caught alive" in the career stats. On an alive only job his death fails the hunt on the spot. A spawn point is drawn at random from Config.BountySpawnAnchors for every start, never the same one twice in a row for the same poster, so players cannot learn where a gang waits.
The shipped posters are grouped like this:
| Difficulty | Rank | Bandits | XP | Posters |
|---|---|---|---|---|
| 1 | bronze | 4 | 10 | 13 |
| 2 | bronze | 5 to 6 | 16 | 13 |
| 3 | silver | 7 to 9 | 24 | 11 |
| 4 | gold | 10 to 13 | 34 | 9 |
| 5 | legend | 14 to 20 | 50 | 9 |
| rescue 1 to 5 | gold | like the gang jobs | 10 to 50 | 15 |
To add a poster, copy an entry, give it a new key, and add the three texts to every language block in locales.lua. To take one away, delete the entry or set its type off:
A type set to false disappears from every board. If you do not want the hostage walk on your server, that is the switch.
Timing and the gang are controlled here:
Config.HuntWatchdog = {
TickMs = 60000,
MaxDurationSec = 60 * 45, -- a hunt fails after this time
BountyKeyLockSec = 60 * 90, -- the same bounty cannot be taken again for this long, server wide
CooldownSec = 60 * 29, -- pause for every member after a hunt
}
Config.NPC = {
CleanupGraceMs = 30000, -- bandits are removed this long after the last member left the area
SpawnTriggerDistance = 100.0, -- bandits spawn when a member is this close to the spawn point
SpawnIntervalMs = 100, -- pause between two bandit spawns
LeaderFailDistance = 200.0, -- hunt fails when the leader is further away from the spawn point
EnableDistanceFailCheck = true,
RetargetTickMs = 3000, -- how often a bandit looks for a new target
SpawnValidationRadius = 150.0, -- max. distance of a reported bandit from the spawn point
SpawnReportMinFraction = 0.75, -- less than this share of the bandits reported = hunt fails
}
Config.Performance = {
MaxEnemiesPerBounty = 20, -- hard cap, larger jobs are cut down at start
}
The cooldown is written for every member when a hunt ends, whichever way it ends. The poster lock keeps a posse from farming the same gang, and because it is server wide it also keeps two posses from riding to the same spot. With CooldownSec = 60 * 29 and a 45 minute limit a group can do roughly one job an hour, which is what the payout table is balanced for. If you cut the cooldown, cut the money too.
LeaderFailDistance kicks in once the gang has spawned. A leader who rides 200 meters away from the spawn point loses the job, so bandits are not left standing around. Set EnableDistanceFailCheck = false if your players like to pull the gang towards a town.
The leader's game spawns the gang and reports every bandit to the server. The server drops any bandit that is too far from the spawn point or has the wrong model, and if fewer than 75 percent of them arrive the hunt fails with "The gang could not be tracked down". That is the guard against a client sending made-up bandits, do not loosen it.
Bandits¶
config/npc.lua controls how the bandits fight and look.
Config.NPCDefaults = {
Combat = {
attributes = { [46] = true, [5] = true, [1] = true }, -- fights unarmed, always fights, uses cover
flee_disable = true,
range = 2, -- 0 near, 1 medium, 2 far
movement = 3, -- 0 stationary, 1 defensive, 2 offensive, 3 charge
accuracy = 60, -- fallback, see AccuracyRangeByDifficulty
health_mult = { 1.2, 1.4, 1.6, 2.0, 2.5 }, -- by difficulty 1 to 5
relationship = 'HATES_PLAYER',
},
RandomOutfit = true,
HorseRandomOutfit = true,
AccuracyRangeByDifficulty = {
[1] = { min = 60, max = 70 },
[2] = { min = 70, max = 80 },
[3] = { min = 80, max = 90 },
[4] = { min = 85, max = 95 },
[5] = { min = 95, max = 100 },
},
BanditModelPool = {
'G_M_M_UNIBANDITOS_01',
'G_M_M_UNIDUSTER_01',
-- ...
},
RandomWeaponPool = {
'WEAPON_REVOLVER_CATTLEMAN',
'WEAPON_REVOLVER_SCHOFIELD',
'WEAPON_REPEATER_CARBINE',
'WEAPON_SHOTGUN_DOUBLEBARREL',
},
HorseModels = {
'A_C_HORSE_KENTUCKYSADDLE_BLACK',
-- ...
},
HorseTack = { Enabled = true, Randomize = true, Saddles = { ... }, Bridles = { ... } },
}
Every bandit gets a random model from the pool, a random outfit and, if the group has no weapon, a random gun from RandomWeaponPool. Accuracy is drawn per bandit from the range of the job's difficulty, health is the base health times health_mult. A difficulty 5 bandit has two and a half times the health and shoots at 95 to 100 percent accuracy, that is on purpose, legend posters are meant for a full posse.
If your players find the gangs too hard, lower the top of AccuracyRangeByDifficulty first, for example [5] = { min = 80, max = 90 }. Health comes second, because a bandit who takes a whole cylinder to drop feels wrong in this game.
Hostages¶
config/hostages.lua holds the hostage behaviour and the hideouts.
Config.Hostages = {
Models = {
'a_f_m_skpprisononline_01',
'a_m_m_skpprisoner_01',
'a_m_m_skpprisonline_01',
},
Anims = {
{ dict = 'mech_busted@unapproved', name = 'idle_b' },
{ dict = 'script_proc@robberies@shop@rhodes@gunsmith@inside_basement_reshoot', name = 'cry_loop_captor' },
},
Health = 300, -- after being freed. Tied up they cannot be hurt.
Spacing = 1.5, -- distance between hostages when a hideout has only one point
RideAlong = true, -- mount behind the rider or on a free wagon seat
RideAlongSpeed = 2.0,
RideAlongTries = 2,
RideAlongRetryMs = 3500,
DeliverRadius = 10.0, -- a hostage is safe this close to the turn in point of the board
WalkOffSeconds = 8, -- a delivered hostage walks away and disappears after this time
CollectSeconds = 600, -- time the posse has to reach the board when the last hostage died on the way
LostMeters = 500.0, -- no living member closer than this ...
LostSeconds = 120, -- ... for this long = the hostage counts as lost
MissingSeconds = 20, -- a hostage the server does not see for this long is lost, a bandit counts as dead
TickMs = 2500,
SweepMs = 15000, -- the server removes leftovers this long after the end
Locations = {
{ name = 'Near Flatneck Station', guards = { x = -339.92, y = -140.3, z = 49.17 },
hostages = {
{ x = -328.68, y = -151.09, z = 51.08, h = 21.4 },
{ x = -326.65, y = -149.11, z = 51.08, h = 113.95 },
} },
-- ... 16 in total
},
}
The hostage models are civilians on purpose. Bandit models bring a horse along when they spawn, and a hostage with a horse would ride off. While tied up a hostage cannot be hurt, so a careless shot into the camp does not cost the job. After the last guard falls the hostages stand up, each one is given to the closest member who is alive, spread evenly, and follows that member. On a horse they climb up behind the rider, on a wagon they take a free seat, on foot they walk.
A hostage is "safe" once it is within DeliverRadius of the board's turn-in spot. It walks off and disappears after WalkOffSeconds. A hostage is lost when no living member has been within LostMeters for LostSeconds, or when the server does not see it for MissingSeconds. A hostage shot after being freed is dead. Pay and XP are scaled by hostages delivered divided by hostages total, so one of two hostages brought home pays half. No hostage delivered means the job failed.
There is no turn-in step for a rescue. As soon as every hostage is delivered, dead or lost, the server pays out on its own if the posse is at the board. If nobody is within PresenceRadius at that moment, the members get "Come to the office to collect your pay" and have CollectSeconds to get there.
Hideouts are written in two ways. With hostages you set one kneeling spot per hostage, position plus the facing h, and you need at least as many spots as the job has hostages. With coords and heading the script lines the hostages up along that heading with Spacing between them. guards is where the bandits spawn and where the route leads, leave it out to use the middle of the hostage spots. The guards spot must be within Config.NPC.SpawnValidationRadius of the hostages or the gang is rejected. A hideout is drawn at random for every rescue, never the one the same poster used last time and never one another posse is in right now. The shipped hideouts are examples, replace them with spots that fit your map.
Payouts and ranks¶
config/payouts.lua decides the money, Config.Tiers and Config.XP in config/config.lua the ranks.
Config.Payouts = {
TierMoneyMultiplier = {
bronze = 1.00,
silver = 1.10,
gold = 1.25,
outlaw = 1.35,
legend = 1.50,
},
PosseSizeMultiplier = {
[1] = 1.0,
[2] = 1.5,
[3] = 2.0,
[4] = 3.0,
},
Split = 'even', -- 'even' or 'leader_60'
PresenceRadius = 100.0, -- members have to be this close to the turn in point, 0 = off
CurrencyType = { money = 0 }, -- vorp currency: 0 cash, 1 gold
DifficultyMoneyRange = {
[1] = { min = 10, max = 15 },
[2] = { min = 15, max = 19 },
[3] = { min = 19, max = 23 },
[4] = { min = 23, max = 26 },
[5] = { min = 26, max = 30 },
},
}
Config.Tiers = {
{ key = 'bronze', min = 0, color = '#cd7f32' },
{ key = 'silver', min = 500, color = '#c0c0c0' },
{ key = 'gold', min = 1500, color = '#c8a84b' },
{ key = 'outlaw', min = 3000, color = '#c41e1e' },
{ key = 'legend', min = 5000, color = '#9b30ff' },
}
Config.XP = {
TurnInBonusFraction = 0.5, -- bonus on top of the job XP when turning in
}
The money is worked out at turn-in, in this order:
- A base sum is drawn at random from
DifficultyMoneyRangefor the job's difficulty. - It is multiplied by the highest
TierMoneyMultiplieramong the members present. One legend hunter in the posse lifts the whole pot. - It is multiplied by
PosseSizeMultiplierfor the number of members present. A missing size uses the last entry. - On a rescue it is multiplied by hostages delivered divided by hostages total.
- The pot is split.
evengives everyone the same,leader_60gives the leader 60 percent and shares the rest. Money is whole dollars, any dollar left over from the split goes to the leader.
Only members within PresenceRadius of the turn-in spot at that moment are paid, get XP and get the statistics. A member who stayed at the spawn point gets nothing. The cash is added to each member with vorp_core, nothing is taken from anyone.
XP works the same way: the poster's XP times the posse multiplier, divided by the members present, plus TurnInBonusFraction of that as a bonus. The sum is compared against Config.Tiers and the rank moves up when the XP crosses min. A rank is never taken away.
Example: a posse of two turns in a difficulty 3 job, one of them gold. The base roll gives 20, times 1.25 for the gold member, times 1.5 for two riders is 37 dollars, split 19 and 18. XP is 24 times 1.5 divided by 2, that is 18, plus a 9 bonus, 27 each.
The posse multiplier climbs steeply (a full posse triples the pot) because four riders split it four ways and a four man job at difficulty 5 is a real fight. If you run a lot of solo hunters and want them to earn more, raise DifficultyMoneyRange rather than flattening the posse table, or the big gangs are not worth the ride.
The Career tab shows rank, XP to the next rank, bounties completed and failed, brought in dead, caught alive, hostages rescued, current and best streak, best time and total payout. A failed or cancelled hunt counts as failed for every member and resets the streak.
Blips¶
Config.Blips = {
Boards = { Enabled = true, Sprite = 'blip_wanted_poster', Color = 'BLIP_MODIFIER_MP_COLOR_32', Size = 'small' },
Members = { Sprite = 'blip_ambient_hunter', Color = 'BLIP_MODIFIER_MP_COLOR_32', Size = 'small' },
HuntArea = { Sprite = 'blip_ambient_marked_for_death', Color = 'BLIP_MODIFIER_MP_COLOR_32', Size = 'small' },
HuntTurnIn = { Sprite = 'blip_mp_cash_checkpoint', Color = 'BLIP_MODIFIER_MP_COLOR_20', Size = 'small' },
Target = { Sprite = 'blip_ambient_hunter', Color = 'BLIP_MODIFIER_MP_COLOR_6', Size = 'small' },
Targets = { Sprite = 'blip_ambient_corpse', Color = 'BLIP_MODIFIER_MP_COLOR_32', Size = 'small' },
Hostage = { Sprite = 'blip_ambient_companion', Color = 'BLIP_MODIFIER_MP_COLOR_3', Size = 'small' },
Route = { Enabled = true, ColorHash = 'COLOR_YELLOW' },
}
Sprites are RedM blip names, colors BLIP_MODIFIER_MP_COLOR_*, sizes small, medium or big. Boards.Enabled = false hides the board blips if you want players to find the offices themselves. Route.Enabled = false turns off the GPS line to the spawn point and back to the office, the blips stay.
Rate limit¶
Config.RateLimit = {
windowMs = 3000,
default = 8,
['bh:hunt:start'] = 3,
['bh:hunt:kill'] = 30,
-- ...
}
How many requests of one kind a player may send within windowMs. Above the limit the request is dropped and the player sees "Not so fast, stranger." once. The defaults are generous for normal play, you only need to touch them if a legit action gets blocked on a server with very high ping.
Discord webhooks¶
server_config.lua is the only file that never reaches a client.
Config.Webhooks = {
Start = '', -- hunt started
Complete = '', -- hunt completed and paid
Failed = '', -- hunt failed or cancelled
TierUp = '', -- new rank
Admin = '', -- admin command used
BigPayoutThreshold = 100, -- payouts from this sum get the bigwin color
Username = 'Bounty office',
Avatar = '',
Colors = {
start = 15844367,
complete = 5763719,
failed = 15158332,
tierup = 3447003,
admin = 10181046,
bigwin = 16766720,
},
}
One URL per event, all five can point to the same channel. Each post is an embed with the poster, difficulty, leader and members as character IDs, hunt id, and for a completed hunt the payout, XP and duration. A payout at or above BigPayoutThreshold gets the bigwin color and the title "Big bounty collected!". Embed titles and field names come from locales.lua, colors are Discord decimal colors.
Language¶
locales.lua has an en and a de block with every prompt, notification, UI label, rank name, webhook text and the 70 poster texts. To add a language, copy a block, translate it and set Config.Locale to its key. %s and %d are filled in order, keep them.
Commands and keys¶
| Command | Who | Does |
|---|---|---|
/bounty admin list |
admin | Lists every running hunt with id, poster, leader, members and kills |
/bounty admin cancel <hunt_id> |
admin | Cancels a hunt, the members are told it was an admin |
/bounty admin xp <charid> <amount> |
admin | Gives XP to a character, the rank follows |
/bounty admin tier <charid> <tier> |
admin | Sets a rank directly: bronze, silver, gold, outlaw or legend |
/bounty without admin prints the help line. The command name is Config.AdminCommand, the groups are Config.AdminGroups. Every admin action is posted to the Admin webhook.
At a board:
| Key | Action |
|---|---|
| E | Open the board (Config.Boards.PromptKey) |
Inside the board:
| Key | Action |
|---|---|
| Q / E | Switch tabs |
| Enter | Select the highlighted entry |
| Esc | Back, or close the board |
| Hold the Remove button | Kick a member (leader only) |
Everything else is a click: accept a poster, invite by server ID, accept or decline an invitation, leave the posse, cancel the running hunt, turn in the bounty. Cancel and leave ask for a confirmation first.
There are no exports. The script talks to other resources only through nss_libs and vorp_core.
FAQ¶
The board prompt does not show.
Stand within interactDist of the board position (1.5 meters on the shipped boards). The prompt is only built once the board is within ChunkRadius, so if you just teleported, wait a second. The board needs no job, so the rank is the only thing that can hide a poster, not the prompt.
I accepted a poster and nothing happened.
Every member has to be within StartAllMembersRadius (10 meters) of the board, and the leader sees who is not. The leader also sees a message when a member is still on cooldown, when the poster is locked for the server or when the rank is too low. Only the leader can accept.
The gang does not spawn.
Bandits spawn when a member of the posse gets within SpawnTriggerDistance (100 meters) of the spawn point, and the leader's game does the spawning. If the leader is far behind the group, the first member at the spot will see nobody until the leader catches up. The hunt fails with "The gang could not be tracked down" when fewer than 75 percent of the bandits could be spawned near the point, which usually means a spawn anchor sits inside a rock or under water. Check the Config.BountySpawnAnchors entry the route pointed to.
"Drop the body first, then turn in."
The target cannot be turned in while a player carries it. Put it down within turnInDistance of the board's turnInVector and the turn-in runs on its own, or press "Turn in bounty".
The job failed with "Too far from the target".
The leader rode more than LeaderFailDistance (200 meters) from the spawn point after the gang had spawned. Lure the gang if you must, but keep the leader close, or raise the distance.
Who gets paid?
Every member who is online and within PresenceRadius (100 meters) of the turn-in spot when the hunt is turned in. The pot is scaled by the number of members present, not the number who started. A member who logs out before the turn-in gets nothing and still gets the cooldown.
Can I turn in at a different office? No. A poster is always turned in where it was taken, the blip and the route point there once the gang is down. The notification names the office.
A player cannot take a hostage poster.
Every rescue needs the gold rank (min_tier = 'gold'), which is 1500 XP. Lower min_tier in config/bounties.lua if you want them earlier.
What happens on a server restart? Running hunts are set to failed on boot, the bandits and hostages are gone with the restart anyway. Members get the 29 minute cooldown as after any failed hunt. XP, ranks, statistics and cooldowns are in the database and survive. Posses are in memory only, so players form them again at a board.
Can I run two posses at once? Yes. Every posse has its own hunt, its own spawn point and, for rescues, its own hideout. A poster another posse is on shows as "Taken" until its 90 minute lock runs out.
How much does this cost in performance?
Outside a hunt the client only watches the distance to the boards and streams the board props. The gang is at most MaxEnemiesPerBounty (20) peds per posse, spawned by one client and removed 30 seconds after the last member leaves the area. The server checks running hunts once a minute (HuntWatchdog.TickMs) and hostages every 2.5 seconds (Hostages.TickMs). Kill statistics are written in batches, not per shot.
Changelog¶
1.0.1¶
First release.