Contributing to Requisitions
Requisition contracts are an alternative trading method for QM that offers a lot of opportunity for unique, flavorful exchanges, including the ability to reward trades with items alongside (or instead of) the usual cash income.
Constructed of individual entries loaded into a main contract, the requisitions system lets you heavily customize and randomize the requirements and rewards involved, and it takes care of the front-end presentation for them automatically.
How do I make a contract?
Note: You may want to check out Coding first if you're unfamiliar with BYOND development.
Fundamentally, a contract consists of a few main parts:
- The contract datum itself. (/datum/req_contract)
- Contract entries, which tell the contract what to search for. (/datum/rc_entry)
- Item rewarders (if desired), which the contract optionally uses to build rewards. (/datum/rc_itemreward)
When the game generates a contract, it picks from the list of contract datums, and uses the one it picked as a "template" to generate the actual, set-up contract ready to handle trades. (There are two ways a contract can be generated; more on that later.)
To make a contract - or in more precise terms, set up the datum ("template") used to make contract instances - all you need to do is set it up with the right data, and it'll take care of the interactions between the bits and pieces.
Setting the Stage
There are three main parts to putting together a contract; laying out the "framework" of the contract, making sure you have entries for each thing you want to require, and setting up the entry generation logic (not necessarily in that order). First, we'll tackle the framework.
Your first and most important addition is a contract name. (Technically, you don't need anything but a name and a contract entry added in New() to have a functioning contract!) You can use a fixed name, but it generally makes for better flavor to randomize it - this is typically done fairly early in a contract's New() by using pick() on a list of possible names you defined above.
Other sensible early additions can be a flavor description, a payout modifier, and a weight. Payout increases the money reward for completion, and adds together with fee modifiers from individual items; weight changes how likely the contract is to appear in the market, with a default of 100 if you opt not to specify it.
Flavor descriptions can be one of the more complex parts of the main contract to set up, but they bring a lot of roleplay quality to a contract, so it's generally recommended that you set up different random variations for them. Looking at existing contracts can be useful for seeing how these descriptions, and contracts in general, can be set up.
Before you can add an entry to a contract, you have to define it, a.k.a. set up its "template". There are a few different types of these, but they're fairly similar in terms of how you set them up. Here are some common elements:
- An entry name. This is used for the auto-generated list of contract requirements. For items, always describe them with the singular term (i.e. pizza instead of pizzas, wrench instead of wrenches) - the code that sets up the entries will automatically add the appropriate pluralization, so you can easily use the same entry for one item or multiple.
- The fee modifier (or feemod for short). This augments the overall payout, multiplied for each unit of the thing that's being sold (individual items, stack counts of stackables, units of reagent, etc). It should be directly set, but you can also add to it with commodity prices for the types of entry that have a "commodity" variable.
- The type of the thing you want the entry to require. For items, this is usually an item path, and for reagents, it's one or more reagent IDs.
If you set up all of those, you've got an entry ready to be added to your contract.
To see the differences between the available kinds of entry, the best place to look is in requisition_contracts.dm, located in code/modules/economy/requisition. Every type of entry (at the time of writing: item, stack, reagent and seed) is located here, and should have comments explaining what each available variable does.
If none of the entries have the functionality you want for your contract, you can even make your own. There are only two requirements for an entry to "connect" to a contract, described in the comments for the evaluation proc (rc_eval); this can be a little more complex if you don't know what you're doing, so don't be afraid to ask for help if you think you need custom functionality.
Putting a Team Together
Once you have your contract set up at a basic level and some entries ready to go, you'll need to add some generation code so the entries get added to the contract, and typically randomized when they go in.
The generation code can be fairly straightforward to set up; for most contracts, all you'll need to do is pick an entry, set how much stuff that entry should require, and then add it to the list (repeating a couple of times, conditionally). The typical way to do this is to use the following line of code, which we'll break down in excessive detail:
src.rc_entries += rc_buildentry(ENTRYPATH,NUMBER)
- "src" refers to the object that's the source of the current thing that's running (in this case, the contract).
- The period afterwards means we're looking for the thing after the period (the entry list) "inside of" the thing before the period (the contract).
- rc_entries is the contract's list of contract entries.
- += is an operator which adds the thing on the right to the thing on the left; if the thing on the left is a list (as is the case here), the thing on the right will be added as a new item in the list.
- rc_buildentry is a helper proc that simplifies the process of creating an entry. When you give it the path to a contract entry, and the number of units that entry requires, it gives you back a generated contract entry; the code to the left adds that entry to the contract's list of entries.
The bulk of the setup logic will just be randomizing which entries are picked, and how many units the entries require.
One additional thing worth mentioning is the use of ABSTRACT_TYPE. Defining a contract entry's type as abstract, i.e. ABSTRACT_TYPE(/datum/rc_entry/item/basictool), is very useful for setting up lots of entry options to easily pick from in your contract; you can set up several different sub-types (i.e. /datum/rc_entry/item/basictool/wrench with a name, cost and path) and then pick from them like this.
for(var/S in concrete_typesof(/datum/rc_entry/item/basictool)) if(prob(70)) src.rc_entries += rc_buildentry(S,rand(1,4))
Item reward datums (/datum/rc_itemreward) are set up in a fairly straightforward manner. You generate them and add them to your contract in much the same way as regular contract entries, but they are put in the item_rewarders list instead of rc_entries.
All you have to set up is their name and their build_reward() proc, the latter of which is simply something that creates the reward item and hands it over to the requisition system through "return". Looking at existing uses of the item reward datum is a good way to figure out how they work if this explanation isn't enough.
Contracts have two ways to appear to players; the requisition market, or special orders. Most of this guide up until now has been assuming you're making a market-style requisition; special orders (/datum/req_contract/special) are handled differently, and have a few unique components.
Whereas regular contracts show up in the QM console and are managed from there, special orders are instead sent to QM in the form of a physical requisition sheet; finished orders are sent with a special third-party requisition code, and the sheet has to be sent back with the goods, permanently losing your shipment if the order was incorrectly fulfilled.
To set up special orders, the most important element to set up is your requisition sheet. These are defined in code/modules/events/minor/special_order.dm (as that's where the special orders are sent from).
The "info" (text on the paper) includes flavor text, and should include a description of what the requisition requires; payout data and any item rewards are inserted on the end automatically. If you want to have a list of requirements automatically set up for you, type %ITEMS% on its own line; the setup will automatically replace this with a formatted requirements list.
The only other variable on the base special order contract is sendingCrate; this is the path to the kind of crate you want to use. It's only used if you're sending something along with the order, and you don't have to specify one (a default crate will be used if you don't).
|Contributing||Guide to Contributing to Wikistation · Goonstation Development Guide · Goonstation Contributor Guidelines · Spriting · Goonstation Spriting Guidelines · Coding · Goonstation Code Guide · Hosting a server · Mapping · Goonstation Map Submission Guidelines · Goonstation Audio Guidelines · Contributing to Requisitions|
|Culture & Art||Terminology · Storyline (Old Storyline) · Fan Videos · Fan Art|
|History & Happenings||Changelog · Pre-2016 Changelog · History of SS13|
|Tales & Humor||Sex and the Singularity · Maintenance Doggs · The Rapper · The Trial of Heisenbee · Albert and the Deep Blue Sea · The uWu Interrogation · HeadSurgeon · Tales of The Devil · IT'S ALIVE! It died. IT'S ALIVE! It died. IT'S ALIVE! · The floor is now explosions · My god, it's full of butt · The Crashwich · The Doom Peel · Jugglemancy|