Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions code/__DEFINES/blackmarket.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

// Shipping methods

// The BEST way of shipping items: accurate, "undetectable"
#define SHIPPING_METHOD_LTSRBT "LTSRBT"
// Picks a random area to teleport the item to and gives you a minute to get there before it is sent.
#define SHIPPING_METHOD_TELEPORT "Teleport"
// Throws the item from somewhere at the station.
#define SHIPPING_METHOD_LAUNCH "Launch"
3 changes: 2 additions & 1 deletion code/_globalvars/lists/maintenance_loot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,8 @@ GLOBAL_LIST_INIT(maintenance_loot_makeshift,list(
/obj/item/stack/spacecash/c200 = W_RARE,
/obj/item/stack/spacecash/c50 = W_UNCOMMON,
/obj/item/stack/spacecash/c500 = W_MYTHICAL,
/obj/item/stock_parts/cell/potato = W_UNCOMMON
/obj/item/stock_parts/cell/potato = W_UNCOMMON,
/obj/item/blackmarket_uplink = W_UNCOMMON
))

//Has minor mechanical usage; stuff you'd usually only find in a lathe, through crafting, or through a vendor.
Expand Down
116 changes: 116 additions & 0 deletions code/controllers/subsystem/blackmarket.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
SUBSYSTEM_DEF(blackmarket)
name = "Blackmarket"
flags = SS_BACKGROUND
init_order = INIT_ORDER_DEFAULT

/// Descriptions for each shipping methods.
var/shipping_method_descriptions = list(
SHIPPING_METHOD_LAUNCH="Launches the item at the station from space, cheap but you might not recieve your item at all.",
SHIPPING_METHOD_LTSRBT="Long-To-Short-Range-Bluespace-Transceiver, a machine that recieves items outside the station and then teleports them to the location of the uplink.",
SHIPPING_METHOD_TELEPORT="Teleports the item in a random area in the station, you get 60 seconds to get there first though."
)

/// List of all existing markets.
var/list/datum/blackmarket_market/markets = list()
/// List of existing ltsrbts.
var/list/obj/machinery/ltsrbt/telepads = list()
/// Currently queued purchases.
var/list/queued_purchases = list()

/datum/controller/subsystem/blackmarket/Initialize(timeofday)
for(var/market in subtypesof(/datum/blackmarket_market))
markets[market] += new market

for(var/item in subtypesof(/datum/blackmarket_item))
var/datum/blackmarket_item/I = new item()
if(!I.item)
continue

for(var/M in I.markets)
if(!markets[M])
stack_trace("SSblackmarket: Item [I] available in market that does not exist.")
continue
markets[M].add_item(item)
qdel(I)
. = ..()
return SS_INIT_SUCCESS

/datum/controller/subsystem/blackmarket/fire(resumed)
while(length(queued_purchases))
var/datum/blackmarket_purchase/purchase = queued_purchases[1]
queued_purchases.Cut(1,2)

// Uh oh, uplink is gone. We will just keep the money and you will not get your order.
if(!purchase.uplink || QDELETED(purchase.uplink))
queued_purchases -= purchase
qdel(purchase)
continue

switch(purchase.method)
// Find a ltsrbt pad and make it handle the shipping.
if(SHIPPING_METHOD_LTSRBT)
if(!telepads.len)
continue
// Prioritize pads that don't have a cooldown active.
var/free_pad_found = FALSE
for(var/obj/machinery/ltsrbt/pad in telepads)
if(pad.recharge_cooldown)
continue
pad.add_to_queue(purchase)
queued_purchases -= purchase
free_pad_found = TRUE
break

if(free_pad_found)
continue

var/obj/machinery/ltsrbt/pad = pick(telepads)

to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting that the order is being processed by [pad]."))

queued_purchases -= purchase
pad.add_to_queue(purchase)
// Get random area, throw it somewhere there.
if(SHIPPING_METHOD_TELEPORT)
var/turf/targetturf = get_safe_random_station_turf()
// This shouldn't happen.
if (!targetturf)
continue

to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("<span class='notice'>[purchase.uplink] flashes a message noting that the order is being teleported to [get_area(targetturf)] in 60 seconds."))

// do_teleport does not want to teleport items from nullspace, so it just forceMoves and does sparks.
addtimer(CALLBACK(src, /datum/controller/subsystem/blackmarket/proc/fake_teleport, purchase.entry.spawn_item(), targetturf), 60 SECONDS)
queued_purchases -= purchase
qdel(purchase)
// Get the current location of the uplink if it exists, then throws the item from space at the station from a random direction.
if(SHIPPING_METHOD_LAUNCH)
var/startSide = pick(GLOB.cardinals)
var/turf/T = get_turf(purchase.uplink)
var/pickedloc = spaceDebrisStartLoc(startSide, T.z)

var/atom/movable/item = purchase.entry.spawn_item(pickedloc)
item.throw_at(purchase.uplink, 3, 3, spin = FALSE)

to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting the order is being launched at the station from [dir2text(startSide)].</span>"))

queued_purchases -= purchase
qdel(purchase)

if(MC_TICK_CHECK)
break

/// Used to make a teleportation effect as do_teleport does not like moving items from nullspace.
/datum/controller/subsystem/blackmarket/proc/fake_teleport(atom/movable/item, turf/target)
item.forceMove(target)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(5, 1, target)
sparks.attach(item)
sparks.start()

/// Used to add /datum/blackmarket_purchase to queued_purchases var. Returns TRUE when queued.
/datum/controller/subsystem/blackmarket/proc/queue_item(datum/blackmarket_purchase/P)
if(P.method == SHIPPING_METHOD_LTSRBT && !telepads.len)
return FALSE
queued_purchases += P
return TRUE
76 changes: 76 additions & 0 deletions code/modules/cargo/blackmarket/blackmarket_item.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/datum/blackmarket_item
/// Name for the item entry used in the uplink.
var/name
/// Description for the item entry used in the uplink.
var/desc
/// The category this item belongs to, should be already declared in the market that this item is accessible in.
var/category
/// "/datum/blackmarket_market"s that this item should be in, used by SSblackmarket on init.
var/list/markets = list(/datum/blackmarket_market/blackmarket)

/// Price for the item, if not set creates a price according to the *_min and *_max vars.
var/price
/// How many of this type of item is available, if not set creates a price according to the *_min and *_max vars.
var/stock

/// Path to or the item itself what this entry is for, this should be set even if you override spawn_item to spawn your item.
var/item

/// Minimum price for the item if generated randomly.
var/price_min = 0
/// Maximum price for the item if generated randomly.
var/price_max = 0
/// Minimum amount that there should be of this item in the market if generated randomly. This defaults to 1 as most items will have it as 1.
var/stock_min = 1
/// Maximum amount that there should be of this item in the market if generated randomly.
var/stock_max = 0
/// Probability for this item to be available. Used by SSblackmarket on init.
var/availability_prob = 0

/datum/blackmarket_item/New()
if(isnull(price))
price = rand(price_min, price_max)
if(isnull(stock))
stock = rand(stock_min, stock_max)

/// Used for spawning the wanted item, override if you need to do something special with the item.
/datum/blackmarket_item/proc/spawn_item(loc)
return new item(loc)

/// Buys the item and makes SSblackmarket handle it.
/datum/blackmarket_item/proc/buy(obj/item/blackmarket_uplink/uplink, mob/buyer, shipping_method)
// Sanity
if(!istype(uplink) || !istype(buyer))
return FALSE

// This shouldn't be able to happen unless there was some manipulation or admin fuckery.
if(!item || stock <= 0)
return FALSE

// Alright, the item has been purchased.
var/datum/blackmarket_purchase/purchase = new(src, uplink, shipping_method)

// SSblackmarket takes care of the shipping.
if(SSblackmarket.queue_item(purchase))
stock--
log_game("[ADMIN_LOOKUPFLW(buyer)] has successfully purchased [name] using [shipping_method] for shipping.")
return TRUE
return FALSE

// This exists because it is easier to keep track of all the vars this way.
/datum/blackmarket_purchase
/// The entry being purchased.
var/datum/blackmarket_item/entry
/// Instance of the item being sent.
var/item
/// The uplink where this purchase was done from.
var/obj/item/blackmarket_uplink/uplink
/// Shipping method used to buy this item.
var/method

/datum/blackmarket_purchase/New(_entry, _uplink, _method)
entry = _entry
if(!ispath(entry.item))
item = entry.item
uplink = _uplink
method = _method
59 changes: 59 additions & 0 deletions code/modules/cargo/blackmarket/blackmarket_items/clothing.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/datum/blackmarket_item/clothing
category = "Clothing"

/datum/blackmarket_item/clothing/ninja_mask
name = "Space Ninja Mask"
desc = "Apart from being acid, lava, fireproof and being hard to take off someone it does nothing special on it's own."
item = /obj/item/clothing/mask/gas/space_ninja

price_min = 200
price_max = 500
stock_max = 3
availability_prob = 40

/datum/blackmarket_item/clothing/durathread_vest
name = "Durathread Vest"
desc = "Dont let them tell you this stuff is \"Like asbestos\" or \"Pulled from the market for safety concerns\". It could be the difference between a robusting and a retaliation."
item = /obj/item/clothing/suit/armor/vest/durathread

price_min = 200
price_max = 400
stock_max = 4
availability_prob = 50

/datum/blackmarket_item/clothing/durathread_helmet
name = "Durathread Helmet"
desc = "Customers ask why it's called a helmet when it's just made from armoured fabric and I always say the same thing: No refunds."
item = /obj/item/clothing/head/helmet/durathread

price_min = 100
price_max = 200
stock_max = 4
availability_prob = 50

/datum/blackmarket_item/clothing/full_spacesuit_set
name = "Nanotrasen Branded Spacesuit Box"
desc = "A few boxes of \"Old Style\" space suits fell off the back of a space truck."
item = /obj/item/storage/box
price_min = 1500
price_max = 4000
stock_max = 3
availability_prob = 30

/datum/blackmarket_item/clothing/full_spacesuit_set/spawn_item(loc)
var/obj/item/storage/box/B = ..()
B.name = "Spacesuit Box"
B.desc = "It has a NT logo on it."
new /obj/item/clothing/suit/space(B)
new /obj/item/clothing/head/helmet/space(B)
return B

/datum/blackmarket_item/clothing/chameleon_hat
name = "Chameleon Hat"
desc = "Pick any hat you want with this Handy device. Not Quality Tested."
item = /obj/item/clothing/head/chameleon/broken

price_min = 100
price_max = 200
stock_max = 2
availability_prob = 70
62 changes: 62 additions & 0 deletions code/modules/cargo/blackmarket/blackmarket_items/consumables.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/datum/blackmarket_item/consumable
category = "Consumables"

/datum/blackmarket_item/consumable/clown_tears
name = "Bowl of Clown's Tears"
desc = "Guaranteed fresh from Weepy Boggins Tragic Kitchen"
item = /obj/item/reagent_containers/food/snacks/soup/clownstears
stock = 1

price_min = 520
price_max = 600
availability_prob = 10

/datum/blackmarket_item/consumable/donk_pocket_box
name = "Box of Donk Pockets"
desc = "A well packaged box containing the favourite snack of every spacefarer."
item = /obj/item/storage/box/donkpockets

stock_min = 2
stock_max = 5
price_min = 325
price_max = 400
availability_prob = 80

/datum/blackmarket_item/consumable/suspicious_pills
name = "Bottle of Suspicious Pills"
desc = "A random cocktail of luxury drugs that are sure to put a smile on your face!"
item = /obj/item/storage/pill_bottle

stock_min = 2
stock_max = 3
price_min = 400
price_max = 700
availability_prob = 50

/datum/blackmarket_item/consumable/suspicious_pills/spawn_item(loc)
var/pillbottle = pick(list(/obj/item/storage/pill_bottle/zoom,
/obj/item/storage/pill_bottle/happy,
/obj/item/storage/pill_bottle/lsd,
/obj/item/storage/pill_bottle/aranesp,
/obj/item/storage/pill_bottle/stimulant))
return new pillbottle(loc)

/datum/blackmarket_item/consumable/floor_pill
name = "Strange Pill"
desc = "The Russian Roulette of the Maintenance Tunnels."
item = /obj/item/reagent_containers/pill/floorpill

stock_min = 5
stock_max = 35
price_min = 10
price_max = 60
availability_prob = 50

/datum/blackmarket_item/consumable/pumpup
name = "Maintenance Pump-Up"
desc = "Resist any Baton stun with this handy device!"
item = /obj/item/reagent_containers/autoinjector/medipen/pumpup
stock_max = 3
price_min = 50
price_max = 150
availability_prob = 90
Loading
Loading