Quick navigation

Go to

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.

14 min read2,979 wordsMarkdown
On this page10 sections

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

  1. Find a ripperdoc. Type /ripper to list your implants and the ripperdocs on duty, then go to Vik's clinic.

  2. Take the chair. Press E on Sit in the operating chair at the white reclining chair, or type /ripper lie next to it. Walk away to get up. You can also wait standing and sit down after the quote.

  3. 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.

  4. Answer. Press Y to accept or N to decline, within 30 seconds. Both keys can be rebound under Pause > Settings > Key bindings; /interaction accept and /interaction decline in 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.

  5. 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.

  6. Done. Chat and a toast confirm the new chrome, and /implants lists 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.

  1. 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 street skips the menu.
  2. 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.
  3. 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 the ripper society and the implant box leaves the clinic's stock. Once the implant is going in, it cannot be stopped.
  4. Keep track. /ripper shows 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 ripper society, 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_contextmenu and open77_notifications, with the libraries open77_actions depends on (open77_animations, open77_props, open77_interactions).
  • The RP pack resources rp_jobs, rp_inventory and rp_economy. rp_zones and rp_identity are optional.
  • Optional: open77_hacking for the Cyberdeck, Self-ICE and Active Purge, which otherwise show as unavailable; open77_seating and open77_furniture for a seating-mode chair.
  • Clients with the RP animation archive for the postures: seatedsleep or seated for the patient, repair, examine or tablet2 for 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 mint1 to mint6, 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:

  1. Stand where the patient's body should sit. Type /pos to copy your position, and /rot for your yaw.
  2. Paste them into chair, keeping z at floor level, with yaw facing the way the patient should look.
  3. Move station next 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.
  4. For a flat bed, put lie or bedsidelie first in profiles. Those postures float on a reclining chair, which is why the default uses seatedsleep.
  5. Mark the points as walked (measured = true, and a source note), then restart 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 station if 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 chair placed.
  • 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

// Guides Β· Lua API

Search the docs

1,905 guides and functions indexed

Try