Roleplay jobs
Ripperdoc: Viktor's clinic
Run a ripperdoc at Viktor's clinic: quotes the patient accepts on an offer card, the operating chair, real cyberware installed and paid once, what happens on a cancel or a restart, chrome from the Kabuki dealer, server setup, configuration and console commands.
On this page10 sections
- How a procedure plays
- The patient
- The ripperdoc
- What everyone nearby sees
- Money, implants and what can go wrong
- After a restart
- Stocking the clinic
- The chrome dealer
- Buying from players
- Prices
- Set up the clinic
- Requirements
- Load the resources
- Let the clinic write and the dealer sell
- Start the clinic
- Staff the clinic and fill the stock
- Console and ACL
- Configuration
- Move the chair
- For resource authors
- When something is refused
- Limits
A ripperdoc quotes a patient, the patient accepts on an offer card, sits in Vik's operating chair and gets real platform cyberware installed. The patient pays once, after the chrome is in. The clinic's implants come out of a stock the ripperdoc keeps filled at a chrome dealer, or by buying boxes from other players.
The job is the rp_ripperdoc
resource, version 2.0, from the Open2077/open77-resources repository. It is built on the
world-interaction libraries and is experimental like them.
| Where | Viktor Vektor's clinic, under the Misty's Esoterica alley in Little China (Watson). The chrome dealer is in Kabuki Market. |
| Who works | Players with the rp_jobs job ripper (label "Ripperdoc"), on duty |
| Who pays | The patient, from cash first, then bank |
| Who is paid | The ripper society |
| What is installed | Gorilla Arms, Reinforced Tendons, Cyberdeck, Self-ICE and Active Purge, in seven grades |
| Runs on | Server and client |
How a procedure plays
The patient
-
Find a ripperdoc. Type
/ripperto list your implants and the ripperdocs on duty, then go to Vik's clinic. -
Take the chair. Press E on Sit in the operating chair at the white reclining chair, or type
/ripper lienext to it. Walk away to get up. You can also wait standing and sit down after the quote. -
Read the quote. Stand near the ripperdoc and ask for a quote. It arrives in chat and as a toast, with the implant, the grade, the price, the time under the knife and the cyberpsychosis risk:
QUOTE from Ada Kovac: install Gorilla Arms (Street) for 1500 eddies, 15 s under the knife. Risk: cyberpsychosis past 4 implants (you carry 0). Nothing is paid until the chrome is in. Answer on the offer card within 30 s.An offer card opens in the middle of the screen at the same time.
-
Answer. Press Y to accept or N to decline, within 30 seconds. Both keys can be rebound under Pause > Settings > Key bindings;
/interaction acceptand/interaction declinein chat also work. If you were already in the chair, you are stood up to answer and seated again after accepting. Accepting pays nothing yet: the price and the implant are put on hold. -
Stay in the chair. While the ripperdoc operates, a bar shows the time under the knife. Press X to stop it; nothing is charged. Getting off the chair also stops it.
-
Done. Chat and a toast confirm the new chrome, and
/implantslists your implants as the platform reports them. A patient who now carries more than four implants gets a 60-second screen effect and a cyberpsychosis warning.
The ripperdoc
You need the ripper job and must be on duty: type /service to clock in.
- Quote. Inside the clinic, within 4 m of the patient, hold ALT, click the patient and pick
Quote (or type
/ripper quote <playerId>). The catalogue opens: one row per implant grade with its price, the clinic's stock and the time under the knife. An implant the patient already carries shows Remove at half its grade's price. Picking a row sends the quote./ripper quote <playerId> arms streetskips the menu. - Wait for the answer. When the patient accepts, the operating station beside the chair offers the procedure, for example E Install Gorilla Arms (Street). Its card is drawn over the patient, in front of you.
- Operate. Once the patient is in the chair, stand at the station and press E (or type
/ripper operate). You kneel beside the patient and a bar runs on both screens, 12 to 22 seconds depending on the implant. X stops it and nothing is charged. When the bar ends, the implant is installed and then the patient pays: the price goes to therippersociety and the implant box leaves the clinic's stock. Once the implant is going in, it cannot be stopped. - Keep track.
/rippershows your board: duty, the current procedure, the stock, the society's balance and the last 24 hours of procedures.
| Command | What it does |
|---|---|
/ripper |
Ripperdoc: the board. Anyone else: their implants and the ripperdocs on duty. |
/ripper quote <playerId> [implant] [grade] |
Send a quote; without an implant, open the catalogue. |
/ripper remove <playerId> <implant> |
Quote the removal of an installed implant. |
/ripper operate |
Start the accepted procedure, standing at the station. |
/ripper cancel |
Withdraw a quote, or stop a procedure before the implant goes in. Patients can use it too. |
/ripper restock [implant] [grade] [count] |
Order boxes at the chrome dealer. |
/ripper buy <playerId> <implant> [grade] [count] |
Buy implant boxes from a player in the clinic. |
/ripper stock |
The clinic's stock. |
/ripper lie |
Sit in the operating chair. |
/ripper help |
The usage line. |
/operer <playerId> |
Same as /ripper quote <playerId>. |
/implants |
Your installed implants. |
Implant names for the commands are arms, legs, deck, ice and purge. Grades are street
and industrial for arms, training and athlete for legs, and street for the other three.
What everyone nearby sees
The patient sitting in the chair and the ripperdoc kneeling at work beside them. The server plays both postures, so every player in the clinic sees the same scene.
Money, implants and what can go wrong
Accepting a quote puts the price and one implant box on hold in a single operation. Nothing is paid and nothing leaves the stock until the implant is installed. Only then is the hold paid, once.
| What happens | Money | Implant box |
|---|---|---|
| The implant is installed | The price is taken from the patient's cash, then bank, and paid to the ripper society |
Leaves the clinic's stock |
| An implant is removed | Half the installed grade's price, paid the same way | Nothing returns to the stock |
| The patient presses N or does not answer within 30 s | Nothing is taken | Stays in stock |
Either player presses X during the operation, or types /ripper cancel |
Nothing is taken | Stays in stock |
| The patient walks more than 25 m from the chair, or gets off the chair during the operation | Nothing is taken | Stays in stock |
| The patient dies or disconnects | Nothing is taken | Stays in stock |
| The ripperdoc disconnects or clocks out | Nothing is taken | Stays in stock |
| The accepted quote waits more than 3 minutes for the operation | Nothing is taken | Stays in stock |
| The cyberware system refuses the implant or does not answer in time | Nothing is taken | Stays in stock |
When a procedure ends without the implant, both players are told why. There is never a refund to make, because nothing was paid.
A procedure charges exactly once. A second press of E is refused, and a payment retried after a database hiccup returns the first receipt instead of charging again.
After a restart
Holds do not survive a restart, so the clinic keeps a small journal of open procedures:
- The implant had not gone in. The procedure is released at the next start and both players are told. Nothing was paid; the box is still in stock.
- The implant was going in. The clinic settles it from the patient's cyberware record when they are back: if the implant is installed, the price is charged once; if it is still not installed 30 seconds after the start, the procedure is released. A wallet that cannot pay at that point is logged as unpaid, and the implant stays.
Stocking the clinic
The chrome dealer
At the chrome dealer in Kabuki Market, an on-duty ripperdoc presses E on Buy chrome for the
clinic to open the order menu, or types /ripper restock arms industrial 2.
- An order holds up to 5 boxes and takes a 6-second bar at the vendor's counter.
- The dealer charges 60% of the retail price, paid by the
rippersociety, or by the ripperdoc's cash when the society is short. One Gorilla Arms (Street) box costs 900 eddies. - The boxes are delivered to the clinic's stash in the same operation. The stash holds 30 boxes.
The dealer creates the boxes within an hourly limit you set (the mint rule), and the money it is paid is burned. The clinic never creates money: the patient pays the society, and the society pays the dealer.
Buying from players
In the clinic, /ripper buy <playerId> <implant> [grade] [count] offers to buy up to 5 implant
boxes from a player within 3 m. The seller accepts the hand-over on the offer card; the boxes go
into the clinic's stash and the seller receives half the retail price per box, paid by the society,
or by the ripperdoc's cash when the society is short.
Implant boxes weigh 2 kg each. Carrying one is illegal unless the holder has the ripper job.
Prices
| Implant | Grade | Price | Time | Dealer price | Buy-back |
|---|---|---|---|---|---|
| Gorilla Arms | Street | 1500 | 15 s | 900 | 750 |
| Gorilla Arms | Industrial | 3200 | 22 s | 1920 | 1600 |
| Reinforced Tendons | Training | 1200 | 12 s | 720 | 600 |
| Reinforced Tendons | Athlete | 2500 | 18 s | 1500 | 1250 |
| Cyberdeck | Street | 2000 | 20 s | 1200 | 1000 |
| Self-ICE | Street | 1800 | 14 s | 1080 | 900 |
| Active Purge | Street | 1600 | 14 s | 960 | 800 |
Prices are in eddies. A removal costs half the installed grade's price. A patient carries one implant per slot: to change grade, remove the installed implant first.
Set up the clinic
Requirements
- A MySQL or MariaDB database. The coordinator and the cyberware records need it.
- The platform libraries
open77_transactions,open77_actions,open77_player_interactions,open77_cyberware,open77_uikit,open77_contextmenuandopen77_notifications, with the librariesopen77_actionsdepends on (open77_animations,open77_props,open77_interactions). - The RP pack resources
rp_jobs,rp_inventoryandrp_economy.rp_zonesandrp_identityare optional. - Optional:
open77_hackingfor the Cyberdeck, Self-ICE and Active Purge, which otherwise show as unavailable;open77_seatingandopen77_furniturefor a seating-mode chair. - Clients with the RP animation archive for the postures:
seatedsleeporseatedfor the patient,repair,examineortablet2for the ripperdoc (animation catalogue).
Load the resources
In server.jsonc, add the resources to resources.load after the ones you already have,
libraries first:
"resources": {
"load": [
// ...your existing resources...
"open77_animations", "open77_props", "open77_interactions",
"open77_transactions", "open77_actions", "open77_player_interactions", "open77_cyberware",
"open77_uikit", "open77_contextmenu", "open77_notifications",
"open77_hacking",
"rp_jobs", "rp_inventory", "rp_economy", "rp_zones", "rp_identity",
"rp_ripperdoc"
]
}
In the same file, make pockets, stashes and wallets accounts of open77_transactions:
"convars": {
"rp_inventory_backend": "transactions"
}
Let the clinic write and the dealer sell
Two open77_transactions settings decide which resources may change which accounts and who may
create items (who may write). Set them
once in the server console:
tunable.set open77_transactions writers rp_ripperdoc:cash+bank+soc+char+stash/stock, rp_economy:cash+bank+soc, rp_inventory, <your other writers>
tunable.set open77_transactions mint3 rp_ripperdoc sys:ripperdoc.supplier * 40
- writers. The default
*lets every resource write and needs no change. If your server uses a list, add the three entries above to it: the clinic writes the patient's wallets, the society, the seller's pockets and its own stock stash. Keep your other jobs' entries. - mint rule. Lets the clinic create up to 40 implant boxes an hour at the dealer. Use any free
mint1tomint6, or append the rule to an existing one with;. Size the cap to your server. Without it, every order is refused with "The dealer cannot sell that (operator: mint rule missing)."
transactions mints in the server console lists every mint rule with this hour's use.
Start the clinic
ensure open77_transactions
ensure open77_actions
ensure rp_ripperdoc
These three declare auto_start false. To start them with the server, put the same lines in
server.jsonc:
"startup": {
"commands": [
"ensure open77_transactions",
"ensure open77_actions",
"ensure rp_ripperdoc"
]
}
The server log then shows:
[rp_ripperdoc] coordinator ready (store=sql)
[rp_ripperdoc] boxed implants defined through rp_inventory: 7
[rp_ripperdoc] catalogue arms defined (arms/gorilla_arms, 2 grade(s))
[rp_ripperdoc] history=sql table=rp_ripperdoc_operations
[rp_ripperdoc] ready: clinics viktor (placed chair), 3 targets, supplier kabuki_chrome, job ripper; recovery: 0 released, 0 to settle
Every finished procedure is also written as a row of the SQL table rp_ripperdoc_operations.
Staff the clinic and fill the stock
The ripper job ships with rp_jobs; a boss or an admin hands it out. In the server console:
setjob 12 ripper 3 # player 12 becomes the clinic's boss
ripper.seed viktor all 1 # one box of each implant into the clinic's stock
The boss then hires staff with /embaucher <playerId> [grade], or by ALT+clicking a player and
picking Hire into Ripperdoc, and everyone clocks in with /service. For a quick test,
ripper.setup <playerId> gives a player the job and puts them on duty in one step.
Console and ACL
These commands are restricted: run them from the server console, or grant them to admins.
| Command | What it does |
|---|---|
ripper.status |
Counters and the procedures in progress |
ripper.seed [clinic] [item or all] [count] |
Put boxes into a clinic's stock, under the dealer's mint rule |
ripper.setup <playerId> |
Give the ripper job and put the player on duty |
ripper.journal |
The open procedures a restart would settle |
To let an admin use them in game, add the permissions to their entry in your ACL file (server ACL):
"permissions": [
"command.ripper.*",
"command.setjob"
]
The player commands (/ripper, /operer, /implants) need no ACL: the clinic checks the job and
duty itself.
Configuration
Everything is in the resource's shared/config.lua (RpRipperConfig). Prices are in eddies,
durations in milliseconds and positions in metres. After an edit, run restart rp_ripperdoc
between procedures.
| Key | Default | Meaning |
|---|---|---|
job, society |
ripper, ripper |
The rp_jobs job that may work here, and the society that is paid |
clinics.viktor.chair.mode |
placed |
placed: the patient sits at the chair point. seating: a furniture seat through open77_seating (chair.furniture, optional chair.spot) |
clinics.viktor.chair.position, yaw |
-1546.92, 1234.22, 11.6, 145 |
Vik's reclining chair; z is the floor and yaw the way the patient faces |
clinics.viktor.chair.arrivalRadius |
1.0 |
How close the body must arrive to the chair point |
clinics.viktor.chair.profiles |
seatedsleep, seated |
The patient's posture: the first one the server knows is played |
clinics.viktor.chair.actionLabel |
Sit in the operating chair |
The chair's prompt |
clinics.viktor.chair.lieMaxMs |
300000 |
A seated patient is stood up after this long |
clinics.viktor.station.position, yaw |
-1546.40, 1233.74, 11.6, 55 |
Where the ripperdoc stands to operate, beside the patient and facing them |
clinics.viktor.zone, zoneRadius |
viktor_clinic, 12.0 |
The rp_zones zone to work in; without rp_zones, the distance to the chair |
clinics.viktor.stockCapacityG |
60000 |
The stock's capacity in grams: 30 boxes |
supplier.position, yaw |
-1172.45, 2024.30, 7.764, -60 |
The chrome dealer's counter, Kabuki Market |
supplier.mode |
mint |
mint sells boxes for money. components burns the parts listed in each grade's components instead; the shipped grades list none |
supplier.payFrom, priceFactor |
society, cash, 0.6 |
Who pays an order, and the dealer's share of the retail price |
supplier.maxCount, durationMs |
5, 6000 |
Boxes per order, and the order's bar |
quote.distance |
4.0 |
How close the ripperdoc must be to quote |
quote.inviteTimeoutMs |
30000 |
Time the patient has to answer |
quote.validMs |
180000 |
How long an accepted quote waits for the operation |
quote.leashM |
25.0 |
How far an accepted patient may walk from the chair |
operation.profiles |
repair, examine, tablet2 |
The ripperdoc's posture at the station: the first one the server knows is played |
operation.installTimeoutMs, holdTtlMs |
20000, 600000 |
How long the cyberware system may take to answer, and the longest hold |
payFrom |
cash, bank |
The patient's wallets, in order |
removalPriceFactor |
0.5 |
A removal's share of the grade's price |
buyback.ratio, maxCount, payFrom |
0.5, 5, society, cash |
Buying boxes from players |
cyberpsychosisThreshold |
4 |
More implants than this after an install shows the effect below; 0 shows it on the first |
cyberpsychosis |
drugged, strength 0.5, 60 s |
The screen effect |
catalogue |
5 implants, 7 grades | Per grade: price, time under the knife, the boxed item and the platform's grade settings |
items |
7 boxes | The implant boxes: label, weight, and the job allowed to carry them |
Move the chair
To use another chair, record the new points in game, then edit the clinic:
- Stand where the patient's body should sit. Type
/posto copy your position, and/rotfor your yaw. - Paste them into
chair, keepingzat floor level, withyawfacing the way the patient should look. - Move
stationnext to the new seat, on a side free of furniture, facing the patient. About 0.7 m from the seat lets the ripperdoc reach the patient's arm. - For a flat bed, put
lieorbedsideliefirst inprofiles. Those postures float on a reclining chair, which is why the default usesseatedsleep. - Mark the points as walked (
measured = true, and asourcenote), thenrestart rp_ripperdoc.
-- shared/config.lua, in C.clinics.viktor
chair = {
mode = "placed",
position = { x = -1546.92, y = 1234.22, z = 11.6 }, -- from /pos, z at floor level
yaw = 145.0, -- the way the patient faces
arrivalRadius = 1.0,
profiles = { "seatedsleep", "seated" },
actionLabel = "Sit in the operating chair",
-- ...the other chair fields unchanged...
measured = true,
source = "walked in game",
},
station = {
position = { x = -1546.40, y = 1233.74, z = 11.6 }, -- beside the seat, facing the patient
yaw = 55.0,
label = "Operating station",
measured = true,
source = "walked in game",
},
A chair outside Vik's clinic also needs a zone: the ripperdoc must stand inside zone to quote and
operate. Point zone to an rp_zones zone around the new room.
For resource authors
The clinic publishes a host-wide event after every completed step and exposes read-only exports:
-- server, after every committed step
AddEventHandler("rp:job:completed", function(e)
-- e.job == "ripperdoc"; e.kind is "operation" or "restock"
-- operation: e.data = { action = "install" | "remove", implant, grade, price, patient, clinic, ... }
-- restock: e.data = { source = "supplier" | "player", item, count, cost, paidBy, clinic }
end)
AddEventHandler("rp_ripperdoc:operation", function(ripperId, patientId, action, implantKey, gradeId, price) end)
exports.rp_ripperdoc:isOnChair(playerId) -- boolean
exports.rp_ripperdoc:implantCount(playerId) -- integer, or nil and a reason
exports.rp_ripperdoc:catalogue() -- the implants, their grades and availability
exports.rp_ripperdoc:procedure(playerId) -- the player's procedure, or nil
For a smaller clinic written from scratch, see open77_ripperdoc_example in
Cyberware.
When something is refused
The clinic explains every refusal in words; a refusal it has no words for reads "That did not work. Try again in a moment.", and the server log keeps the reason. The ones an operator can fix:
| The player reads | Fix |
|---|---|
| "The dealer cannot sell that (operator: mint rule missing)." | Add the dealer's mint rule. |
| "The dealer is out of chrome for this hour." | The hourly cap is used up: wait, or raise the cap. |
| "The clinic's accounts are not writable (operator: writers policy)." | Add the clinic to writers. |
| "The clinic is closed for now (its ledger is not ready)." | Check open77_transactions and the database. |
| "That implant is not available on this server right now." | For the hacking implants, start open77_hacking. |
| "Clock in first: /service." | The ripperdoc is off duty. |
| "Work inside the clinic." | The ripperdoc is outside the clinic's zone. |
| "The patient must sit in the operating chair first (E on the chair)." | The patient has to sit before the operation. |
| "The clinic has no box of that implant left: restock at the chrome dealer." | Restock, or ripper.seed. |
Limits
- One procedure per clinic at a time, and one stock per clinic.
- Prompts close together. The default station is 0.7 m from the chair, and a card answers the
nearest player. Move
stationif the wrong card shows. The patient seated in the chair does not block the station; another player standing on the station's point (within about half a metre) does, and the ripperdoc reads "Someone is standing there." - Seating mode needs a furniture id near the clinic (
chair.furniture) and the seating prompt for it; until then, keep the chairplaced. - Postures. A server whose animation catalogue lacks a configured posture runs the action without it and logs that once at start.
- Hacking implants need
open77_hacking. - No refunds. A procedure that ends without the implant releases the hold. Nothing was paid, so nothing is refunded.
// For agents & LLMsthis page as Markdownllms.txtllms-full.txt
