Archaeology¶
hobbs_archaeology, current version 1.0.1
Overview¶
Scatters dig sites across the map. A player with a shovel digs one up, a find appears in the hole, they pick it up and get the item. Every site then goes on a cooldown of a few hours for the whole server, so the bones do not grow back the moment somebody leaves.
On top of that there is a researcher NPC with a research book. Every site a character digs up for the first time is entered into the book, sorted by region. Once every site on the server is documented, the researcher pays a one time reward in money, gold or items. The book, the cooldowns and the rewards are all stored in the database, so nothing is lost on a restart.
I ship it with dinosaur bones as the only find and one researcher, but every dig site can hand out its own list of items with its own odds, so you can turn it into whatever your server digs for.
How it plays¶
- The player rides past a spot where a dirt pile sticks out of the ground. Within two metres a prompt shows up, named after the region ("Archaeology, Big Valley").
- They hold G. The server checks that they carry a shovel, that the site is free and that they are standing at it. Then the digging animation plays, a shovel appears in their hand and the dig runs for 31 seconds. Walking more than three metres away, dying or pressing Delete stops it.
- When the dig is done, the pile turns into an open hole with the find lying in it and a notification tells them to pick it up carefully. The prompt now shows the find's name.
- They hold R to pick it up. The item lands in their inventory. If this is the first time this character dug up this site, the notification also says "New site documented: Big Valley (12 of 44)".
- The hole disappears for everyone, and the site stays empty for two to six hours.
- At any point they can visit the researcher, press E and open the research book. It lists every region, how many sites are documented, how many bones are suspected there and which numbered sites are still undiscovered. It never shows coordinates, so the hunt stays a hunt.
- Once every site is documented, a "Claim reward" button appears in the book. The researcher pays out once per character.
Requirements¶
| Resource | Note |
|---|---|
vorp_core |
Characters, money and gold for the reward, notifications |
vorp_inventory |
The shovel check, the finds and the reward items |
nss_libs |
Prompts, NPC, blip, streaming of the dirt piles, database access and the Discord log |
Database access runs through nss_libs, so the base setup from Getting started has to be in place. There is no job check anywhere, every player can dig.
Installation¶
- Unpack the resource into
resourcesand keep the folder namehobbs_archaeology. The folder is escrow protected, onlyconfig.lua,server_config.lua,locales.lua,sql/install.sqland the item image are open. -
Run
sql/install.sql. It creates three tables and one item:Table Holds hobbs_archaeology_cooldownsOne row per dig site that is currently on cooldown hobbs_archaeology_findsWhich character has documented which site (the research book) hobbs_archaeology_collectionsWhich character has already claimed the collection reward The item is
dino_bone("Dinosaur Bone", limit 5). The tables are also created on first start if you skip the file, the item is not. -
Copy
install/dino_bone.pngtovorp_inventory/html/img/items/. - Make sure the items
shovelandlootbox1exist in youritemstable, or changeConfig.ShovelItemandConfig.CollectionReward.itemsto items you have. The SQL file does not create these two. -
Add it to
server.cfgafter its dependencies: -
Start the server. The console should print
[hobbs_archaeology] 45 entries, 44 unique dig sites and 20 regions loaded.Every item named in the config is checked against youritemstable on start, a missing one shows up in the console with a note. Fix that before players start digging. - Open
config.lua, setConfig.Localeand replace the dig sites with your own (see below).
Note
The Discord log in server_config.lua is off by default. Nothing is sent until you turn it on and paste a webhook.
Configuration¶
Settings live in config.lua (sent to every client) and server_config.lua (server only). Texts live in locales.lua.
Language and debug¶
Every notification, prompt, item label and research book text comes from locales.lua. To add a language, copy the Locales.en block, translate it and set Config.Locale to its key. Config.Debug = true prints what the server and client are doing to the console, leave it off on a live server.
Shovel¶
The item a player must carry to dig. It is only checked, never used up. Change it if your server calls the shovel something else.
Digging¶
Config.Digging = {
durationMs = 31000, -- how long one dig takes
animDict = 'amb_work@world_human_gravedig@working@male_b@base',
animName = 'base',
shovelModel = 'p_shovel02x',
shovelBone = 'PH_R_Hand',
propDelayMs = 500, -- ms after the animation starts until the shovel shows up
cancelKey = 0x4AF4D473, -- DEL
maxMoveDistance = 3.0, -- m, walking further away cancels the dig
}
durationMs is how long the player stands there digging. The server times the dig too, so a client that reports "done" early is refused (see Security below). If you shorten the dig, that is all you need to change, the server reads the same value. The animation and shovel settings are there in case you want a different animation, I have not needed to touch them.
World¶
Config.World = {
buriedPileModel = 'mp005_p_dirtpile_big03_buried',
openedPileModel = 'mp005_p_dirtpile_cum_unburied',
streamDistance = 50.0, -- m, dirt piles show up within this range
chunkSize = nil, -- nil = streamDistance, never smaller
modelLoadTimeoutMs = 8000,
}
The buried pile is what players look for, the opened pile is what the hole looks like after the dig. Piles are only created within streamDistance of the player and removed again when they leave, so 45 sites do not mean 45 objects in the world. Raise streamDistance if you want players to spot a pile from further away, but keep in mind every client spawns the piles in range, so very large values cost performance.
Interaction¶
Config.Interaction = {
radius = 2.0, -- m, prompt range at a dig site
digKey = 0x760A9C6F, -- G
pickupKey = 0xE30CD707, -- R
}
Values are RedM control hashes. Both prompts are hold prompts.
Security¶
Config.Security = {
startDistance = 3.0,
finishDistance = 4.0,
finishToleranceMs = 1500,
sessionTimeoutSeconds = 25,
pickupTimeoutSeconds = 90,
cleanupIntervalSeconds = 10,
}
These are the server side checks. A dig only starts within startDistance of the site and only finishes within finishDistance. A dig reported finished more than finishToleranceMs before durationMs is over is refused and logged as suspicious. After the find is revealed the player has pickupTimeoutSeconds to pick it up, then the session is dropped and the find is gone. sessionTimeoutSeconds is extra grace on top of the dig duration before an abandoned dig session is cleaned up. You should not need to change any of these unless your server lags enough that honest players get "The dig is not finished yet", then raise finishToleranceMs.
Cooldown¶
After every successful dig the site is locked for everyone for a random time between the two values, two to six hours by default. The random range keeps players from timing a route. The cooldown is written to the database, so it survives restarts. For a small server where sites would otherwise sit empty all evening, something like 30 * 60 and 2 * 60 * 60 works.
Notifications¶
Notifications go through vorp_core (NotifyLeft). icon is used for good news, warnIcon for refusals. Titles are in locales.lua.
Researcher¶
Config.Researcher = {
enabled = true,
name = 'Deborah MacGuiness',
model = 'cs_dinoboneslady',
coords = vector3(1251.52, 1155.71, 151.22),
heading = 307.45,
scenario = 'WORLD_HUMAN_WRITE_NOTEBOOK',
spawnRadius = 50.0,
promptRadius = 1.5,
promptKey = 0xCEFD9220, -- E
serverDistance = 5.0, -- m, max distance to the NPC for the book (checked by the server)
blip = {
enabled = true,
icon = 'blip_ambient_secret',
color = 'BLIP_MODIFIER_MP_COLOR_32',
scale = 0.2,
},
}
The NPC with the research book. name is shown as the prompt title and inside the book ("What you recover, Deborah MacGuiness enters into this book"). The NPC only exists while a player is within spawnRadius. The server checks serverDistance before it hands out the book or pays the reward, so keep it a bit larger than promptRadius. Set blip.enabled = false if you want players to find her by word of mouth. With enabled = false there is no researcher at all, digging still works, but nobody can look at their progress or claim the reward.
Collection reward¶
Config.CollectionReward = {
enabled = true,
money = 99.0,
gold = 0.0,
items = {
{ item = 'lootbox1', amount = 1 },
},
}
Paid once per character when every unique dig site is documented. Money and gold go through vorp_core, items through vorp_inventory. The item labels in the book come from locales.lua as item_<name>, so when you add an item here, add item_<name> = "Label" to each language block too. If the player has no room for the items, the claim is refused and nothing is paid. With enabled = false the book says the reward is not offered at the moment and the button is hidden.
I set the money to 99 and left gold at 0 because the reward is meant to be a nice ending for a long hunt, not an income.
Dig sites¶
Config.Locations = {
{ name = 'Big Valley', coords = vector3(-1803.06, -943.38, 108.84), heading = 0.0,
rewards = { { item = 'dino_bone', model = 'p_dinobone01x', minAmount = 1, maxAmount = 3, weight = 100 } } },
-- ...
}
| Key | Meaning |
|---|---|
name |
Region name. Sites with the same name are grouped under it in the research book |
coords |
Where the pile stands. The object is dropped onto the ground, so the z value only has to be close |
heading |
Rotation of the pile and the find |
rewards |
List of possible finds, the server picks one by weight when the dig starts |
rewards[].item |
Inventory item that is handed out |
rewards[].model |
Prop shown lying in the hole |
rewards[].minAmount, maxAmount |
How many of the item, rolled between the two |
rewards[].weight |
Odds relative to the other entries of this site |
The shipped list has 45 entries in 20 regions, all giving one to three dino_bone. These are examples, replace them with sites that fit your map and your items. A site with two rewards could look like this:
{ name = 'Roanoke Ridge', coords = vector3(2998.2, 1660.66, 80.7), heading = 0.0, rewards = {
{ item = 'dino_bone', model = 'p_dinobone01x', minAmount = 1, maxAmount = 3, weight = 80 },
{ item = 'dino_skull', model = 'p_dinoskull01x', minAmount = 1, maxAmount = 1, weight = 20 },
} },
The research book counts sites by their coordinates. Two entries with identical coordinates count as one site in the book (the shipped list has one such pair in Lakay, the server tells you on start). The position of an entry in the list is its id in the cooldown table, so inserting a site in the middle shifts the running cooldowns to the wrong sites. Add new sites at the end, or clear hobbs_archaeology_cooldowns after a reorder. The research book is not affected by reordering, it stores coordinates.
Tip
Every item named in Config.Locations and Config.CollectionReward plus the shovel is checked against your items table on start. Missing items show up as a warning in the console.
Discord log (server_config.lua)¶
Config.Webhook = {
enabled = false,
botName = 'Archaeology',
fallback = '',
channels = {
finds = '', -- every recovered find
reward = '', -- collection rewards paid out
security = '', -- rejected attempts that look like manipulation, failed rollbacks
},
events = {
find = true,
newDiscovery = true,
rewardClaimed = true,
suspicious = true,
critical = true,
},
}
Sent through nss_libs. Each channel takes a Discord webhook URL. A channel left empty falls back to fallback, and if that is empty too nothing is sent for it. Only URLs on discord.com/api/webhooks/ or discordapp.com/api/webhooks/ are accepted, anything else is skipped with a console note. events lets you mute single message types, for example find = false if every bone is too much noise but you still want to see new discoveries. critical is for the rare case that a reward could not be paid in full and the rollback failed, the message tells you which character to look at.
server_config.lua never leaves the server, so the webhook URLs stay private.
Items¶
| Item | Used for |
|---|---|
shovel |
Required in the inventory to dig, not consumed. Not created by the SQL file |
dino_bone |
The default find, one to three per dig. Created by sql/install.sql, image in install/ |
lootbox1 |
The default collection reward item. Not created by the SQL file, replace it or create it |
Item labels shown by the script come from locales.lua (item_dino_bone, item_lootbox1), not from the items table.
Commands and keys¶
At a dig site:
| Key | Action |
|---|---|
| G (hold) | Dig up the site |
| R (hold) | Pick up the find |
| Delete | Stop digging |
At the researcher:
| Key | Action |
|---|---|
| E | Open the research book |
In the research book:
| Key | Action |
|---|---|
| Q / E | Switch tabs |
| Enter | Select |
| Esc | Back, close the book |
The book also has two font size buttons. The chosen size is saved per player.
There are no chat commands and no exports.
FAQ¶
The dig prompt does not show.
The player has to stand within Config.Interaction.radius (2 m) of the pile and the site must be free. If there is no pile, the site is on cooldown or not yet streamed in. If the client shows "Archaeology is not ready yet" on join, the server was not finished loading, usually because the database was not reachable, check the console.
The server says "You need a shovel" but the player has one.
The item name has to match Config.ShovelItem exactly. Check the items table for the real name and change the config.
Players get "The dig is not finished yet" although they waited.
The server measures the dig itself and allows finishToleranceMs (1.5 s) of slack. On a server with heavy lag that can be too tight. Raise the tolerance a little. Every refusal is also logged to the security channel if the Discord log is on.
Can the same player dig a site twice? Yes, after the cooldown. The research book only counts the first time per character, later digs still give the item.
What happens on restart or when the player leaves mid dig?
Cooldowns are read from the database on start, so locked sites stay locked. A dig that was still running is dropped, the player gets nothing and the site is free again. A find that was revealed but not picked up is gone after pickupTimeoutSeconds (90 s), the cooldown for that site already runs from the moment the dig finished.
How do I add a dig site or a new find?
Add a new entry at the end of Config.Locations. Use an item that exists in your items table and a prop model for the hole, and add an item_<name> label to every block in locales.lua. Restart the resource, the research book picks the new site up by itself, players who already finished the collection will see one site missing again, but a reward that was paid stays paid.
Where does the money come from?
Nothing is taken from players anywhere. The only money in the script is the collection reward, which is created by vorp_core when the researcher pays it. Finds are items only, what they are worth is up to your shops.
Do I need a job for the researcher or the dig sites? No. There is no job or permission check in the script. If you want digging limited to a job, that is not supported right now.
Does it cost performance?
Dirt piles are streamed in and out by distance and prompts are range based through nss_libs. The script itself has no per frame loop outside of an active dig. The server writes the cooldown when a dig finishes and the research entry when the find is picked up, and reads the research book only when it is opened.
Can two players dig the same site? No. The moment a dig starts, the site is reserved on the server and the pile disappears for everybody else. If the first player cancels, the pile comes back.
Changelog¶
1.0.1¶
First release.