Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 5fada85

Browse files
committed
Long-To-Short-Range-Bluespace-Transceiver? Never heard of it.
1 parent 06831a7 commit 5fada85

File tree

14 files changed

+708
-3
lines changed

14 files changed

+708
-3
lines changed

code/__DEFINES/blackmarket.dm

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
// Shipping methods
3+
4+
// Picks a random area to teleport the item to and gives you a minute to get there before it is sent.
5+
#define SHIPPING_METHOD_TELEPORT "Teleport"
6+
// Throws the item from somewhere at the station.
7+
#define SHIPPING_METHOD_LAUNCH "Launch"
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
SUBSYSTEM_DEF(blackmarket)
2+
name = "Blackmarket"
3+
flags = SS_BACKGROUND
4+
init_order = INIT_ORDER_DEFAULT
5+
6+
/// Descriptions for each shipping methods.
7+
var/shipping_method_descriptions = list(
8+
SHIPPING_METHOD_LAUNCH="Launches the item at the station from space, cheap but you might not recieve your item at all.",
9+
SHIPPING_METHOD_TELEPORT="Teleports the item in a random area in the station, you get 60 seconds to get there first though."
10+
)
11+
12+
/// List of all existing markets.
13+
var/list/datum/blackmarket_market/markets = list()
14+
/// List of existing ltsrbts.
15+
var/list/obj/machinery/ltsrbt/telepads = list()
16+
/// Currently queued purchases.
17+
var/list/queued_purchases = list()
18+
19+
/datum/controller/subsystem/blackmarket/Initialize(timeofday)
20+
for(var/market in subtypesof(/datum/blackmarket_market))
21+
markets[market] += new market
22+
23+
for(var/item in subtypesof(/datum/blackmarket_item))
24+
var/datum/blackmarket_item/I = new item()
25+
if(!I.item)
26+
continue
27+
28+
for(var/M in I.markets)
29+
if(!markets[M])
30+
stack_trace("SSblackmarket: Item [I] available in market that does not exist.")
31+
continue
32+
markets[M].add_item(item)
33+
qdel(I)
34+
. = ..()
35+
36+
/datum/controller/subsystem/blackmarket/fire(resumed)
37+
while(length(queued_purchases))
38+
var/datum/blackmarket_purchase/purchase = queued_purchases[1]
39+
queued_purchases.Cut(1,2)
40+
41+
// Uh oh, uplink is gone. We will just keep the money and you will not get your order.
42+
if(!purchase.uplink || QDELETED(purchase.uplink))
43+
queued_purchases -= purchase
44+
qdel(purchase)
45+
continue
46+
47+
switch(purchase.method)
48+
// Get random area, throw it somewhere there.
49+
if(SHIPPING_METHOD_TELEPORT)
50+
var/turf/targetturf = get_safe_random_station_turf()
51+
// This shouldn't happen.
52+
if (!targetturf)
53+
continue
54+
55+
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."))
56+
57+
// do_teleport does not want to teleport items from nullspace, so it just forceMoves and does sparks.
58+
addtimer(CALLBACK(src, /datum/controller/subsystem/blackmarket/proc/fake_teleport, purchase.entry.spawn_item(), targetturf), 60 SECONDS)
59+
queued_purchases -= purchase
60+
qdel(purchase)
61+
// Get the current location of the uplink if it exists, then throws the item from space at the station from a random direction.
62+
if(SHIPPING_METHOD_LAUNCH)
63+
var/startSide = pick(GLOB.cardinals)
64+
var/turf/T = get_turf(purchase.uplink)
65+
var/pickedloc = spaceDebrisStartLoc(startSide, T.z)
66+
67+
var/atom/movable/item = purchase.entry.spawn_item(pickedloc)
68+
item.throw_at(purchase.uplink, 3, 3, spin = FALSE)
69+
70+
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>"))
71+
72+
queued_purchases -= purchase
73+
qdel(purchase)
74+
75+
if(MC_TICK_CHECK)
76+
break
77+
78+
/// Used to make a teleportation effect as do_teleport does not like moving items from nullspace.
79+
/datum/controller/subsystem/blackmarket/proc/fake_teleport(atom/movable/item, turf/target)
80+
item.forceMove(target)
81+
var/datum/effect_system/spark_spread/sparks = new
82+
sparks.set_up(5, 1, target)
83+
sparks.attach(item)
84+
sparks.start()
85+
86+
/// Used to add /datum/blackmarket_purchase to queued_purchases var. Returns TRUE when queued.
87+
/datum/controller/subsystem/blackmarket/proc/queue_item(datum/blackmarket_purchase/P)
88+
queued_purchases += P
89+
return TRUE
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/datum/blackmarket_item
2+
/// Name for the item entry used in the uplink.
3+
var/name
4+
/// Description for the item entry used in the uplink.
5+
var/desc
6+
/// The category this item belongs to, should be already declared in the market that this item is accessible in.
7+
var/category
8+
/// "/datum/blackmarket_market"s that this item should be in, used by SSblackmarket on init.
9+
var/list/markets = list(/datum/blackmarket_market/blackmarket)
10+
11+
/// Price for the item, if not set creates a price according to the *_min and *_max vars.
12+
var/price
13+
/// How many of this type of item is available, if not set creates a price according to the *_min and *_max vars.
14+
var/stock
15+
16+
/// 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.
17+
var/item
18+
19+
/// Minimum price for the item if generated randomly.
20+
var/price_min = 0
21+
/// Maximum price for the item if generated randomly.
22+
var/price_max = 0
23+
/// 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.
24+
var/stock_min = 1
25+
/// Maximum amount that there should be of this item in the market if generated randomly.
26+
var/stock_max = 0
27+
/// Probability for this item to be available. Used by SSblackmarket on init.
28+
var/availability_prob = 0
29+
30+
/datum/blackmarket_item/New()
31+
if(isnull(price))
32+
price = rand(price_min, price_max)
33+
if(isnull(stock))
34+
stock = rand(stock_min, stock_max)
35+
36+
/// Used for spawning the wanted item, override if you need to do something special with the item.
37+
/datum/blackmarket_item/proc/spawn_item(loc)
38+
return new item(loc)
39+
40+
/// Buys the item and makes SSblackmarket handle it.
41+
/datum/blackmarket_item/proc/buy(obj/item/blackmarket_uplink/uplink, mob/buyer, shipping_method)
42+
// Sanity
43+
if(!istype(uplink) || !istype(buyer))
44+
return FALSE
45+
46+
// This shouldn't be able to happen unless there was some manipulation or admin fuckery.
47+
if(!item || stock <= 0)
48+
return FALSE
49+
50+
// Alright, the item has been purchased.
51+
var/datum/blackmarket_purchase/purchase = new(src, uplink, shipping_method)
52+
53+
// SSblackmarket takes care of the shipping.
54+
if(SSblackmarket.queue_item(purchase))
55+
stock--
56+
log_game("[ADMIN_LOOKUPFLW(buyer)] has successfully purchased [name] using [shipping_method] for shipping.")
57+
return TRUE
58+
return FALSE
59+
60+
// This exists because it is easier to keep track of all the vars this way.
61+
/datum/blackmarket_purchase
62+
/// The entry being purchased.
63+
var/datum/blackmarket_item/entry
64+
/// Instance of the item being sent.
65+
var/item
66+
/// The uplink where this purchase was done from.
67+
var/obj/item/blackmarket_uplink/uplink
68+
/// Shipping method used to buy this item.
69+
var/method
70+
71+
/datum/blackmarket_purchase/New(_entry, _uplink, _method)
72+
entry = _entry
73+
if(!ispath(entry.item))
74+
item = entry.item
75+
uplink = _uplink
76+
method = _method
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/datum/blackmarket_market
2+
/// Name for the market.
3+
var/name = "huh?"
4+
5+
/// Available shipping methods and prices, just leave the shipping method out that you don't want to have.
6+
var/list/shipping
7+
8+
9+
// Automatic vars, do not touch these.
10+
/// Items available from this market, populated by SSblackmarket on initialization.
11+
var/list/available_items = list()
12+
/// Item categories available from this market, only items which are in these categories can be gotten from this market.
13+
var/list/categories = list()
14+
15+
/// Adds item to the available items and add it's category if it is not in categories yet.
16+
/datum/blackmarket_market/proc/add_item(datum/blackmarket_item/item)
17+
if(!prob(initial(item.availability_prob)))
18+
return FALSE
19+
20+
if(ispath(item))
21+
item = new item()
22+
23+
if(!(item.category in categories))
24+
categories += item.category
25+
available_items[item.category] = list()
26+
27+
available_items[item.category] += item
28+
return TRUE
29+
30+
/// Handles buying the item, this is mainly for future use and moving the code away from the uplink.
31+
/datum/blackmarket_market/proc/purchase(item, category, method, obj/item/blackmarket_uplink/uplink, user)
32+
if(!istype(uplink) || !(method in shipping))
33+
return FALSE
34+
35+
for(var/datum/blackmarket_item/I in available_items[category])
36+
if(I.type != item)
37+
continue
38+
var/price = I.price + shipping[method]
39+
// I can't get the price of the item and shipping in a clean way to the UI, so I have to do this.
40+
if(uplink.money < price)
41+
to_chat(span_warning("You don't have enough credits in [uplink] for [I] with [method] shipping."))
42+
return FALSE
43+
44+
if(I.buy(uplink, user, method))
45+
uplink.money -= price
46+
return TRUE
47+
return FALSE
48+
49+
/datum/blackmarket_market/blackmarket
50+
name = "Black Market"
51+
shipping = list(SHIPPING_METHOD_LAUNCH =10,
52+
SHIPPING_METHOD_TELEPORT=75)
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/obj/item/blackmarket_uplink
2+
name = "Black Market Uplink"
3+
icon = 'icons/obj/blackmarket.dmi'
4+
icon_state = "uplink"
5+
6+
// UI variables.
7+
var/ui_x = 720
8+
var/ui_y = 480
9+
var/viewing_category
10+
var/viewing_market
11+
var/selected_item
12+
var/buying
13+
14+
/// How much money is inserted into the uplink.
15+
var/money = 0
16+
/// List of typepaths for "/datum/blackmarket_market"s that this uplink can access.
17+
var/list/accessible_markets = list(/datum/blackmarket_market/blackmarket)
18+
19+
/obj/item/blackmarket_uplink/Initialize()
20+
. = ..()
21+
if(accessible_markets.len)
22+
viewing_market = accessible_markets[1]
23+
var/list/categories = SSblackmarket.markets[viewing_market].categories
24+
if(categories && categories.len)
25+
viewing_category = categories[1]
26+
27+
/obj/item/blackmarket_uplink/attackby(obj/item/I, mob/user, params)
28+
if(istype(I, /obj/item/holochip) || istype(I, /obj/item/stack/spacecash) || istype(I, /obj/item/coin))
29+
var/worth = I.get_item_credit_value()
30+
if(!worth)
31+
to_chat(user, span_warning("[I] doesn't seem to be worth anything!"))
32+
money += worth
33+
to_chat(user, span_notice("You slot [I] into [src] and it reports a total of [money] credits inserted."))
34+
qdel(I)
35+
return
36+
. = ..()
37+
38+
/obj/item/blackmarket_uplink/AltClick(mob/user)
39+
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
40+
return
41+
42+
var/amount_to_remove = FLOOR(input(user, "How much do you want to withdraw? Current Amount: [money]", "Withdraw Funds", 5) as num|null, 1)
43+
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
44+
return
45+
46+
if(!amount_to_remove || amount_to_remove < 0)
47+
return
48+
if(amount_to_remove > money)
49+
to_chat(user, span_warning("There is only [money] credits in [src]"))
50+
return
51+
52+
var/obj/item/holochip/holochip = new (user.drop_location(), amount_to_remove)
53+
money -= amount_to_remove
54+
holochip.name = "washed " + holochip.name
55+
user.put_in_hands(holochip)
56+
to_chat(user, span_notice("You withdraw [amount_to_remove] credits into a holochip."))
57+
58+
/obj/item/blackmarket_uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
59+
ui = SStgui.try_update_ui(user, src, ui)
60+
if(!ui)
61+
ui = new(user, src, "BlackMarketUplink", "Black Market Uplink")
62+
ui.open()
63+
ui.set_autoupdate(TRUE)
64+
65+
/obj/item/blackmarket_uplink/ui_data(mob/user)
66+
var/list/data = list()
67+
var/datum/blackmarket_market/market = viewing_market ? SSblackmarket.markets[viewing_market] : null
68+
data["categories"] = market ? market.categories : null
69+
data["delivery_methods"] = list()
70+
if(market)
71+
for(var/delivery in market.shipping)
72+
data["delivery_methods"] += list(list("name" = delivery, "price" = market.shipping[delivery]))
73+
data["money"] = money
74+
data["buying"] = buying
75+
data["items"] = list()
76+
data["viewing_category"] = viewing_category
77+
data["viewing_market"] = viewing_market
78+
if(viewing_category && market)
79+
if(market.available_items[viewing_category])
80+
for(var/datum/blackmarket_item/I in market.available_items[viewing_category])
81+
data["items"] += list(list(
82+
"id" = I.type,
83+
"name" = I.name,
84+
"cost" = I.price,
85+
"amount" = I.stock,
86+
"desc" = I.desc || I.name
87+
))
88+
return data
89+
90+
/obj/item/blackmarket_uplink/ui_static_data(mob/user)
91+
var/list/data = list()
92+
data["delivery_method_description"] = SSblackmarket.shipping_method_descriptions
93+
data["markets"] = list()
94+
for(var/M in accessible_markets)
95+
var/datum/blackmarket_market/BM = SSblackmarket.markets[M]
96+
data["markets"] += list(list(
97+
"id" = M,
98+
"name" = BM.name
99+
))
100+
return data
101+
102+
/obj/item/blackmarket_uplink/ui_act(action, params)
103+
if(..())
104+
return
105+
switch(action)
106+
if("set_category")
107+
if(isnull(params["category"]))
108+
return
109+
if(isnull(viewing_market))
110+
return
111+
if(!(params["category"] in SSblackmarket.markets[viewing_market].categories))
112+
return
113+
viewing_category = params["category"]
114+
. = TRUE
115+
if("set_market")
116+
if(isnull(params["market"]))
117+
return
118+
var/market = text2path(params["market"])
119+
if(!(market in accessible_markets))
120+
return
121+
122+
viewing_market = market
123+
124+
var/list/categories = SSblackmarket.markets[viewing_market].categories
125+
if(categories && categories.len)
126+
viewing_category = categories[1]
127+
else
128+
viewing_category = null
129+
. = TRUE
130+
if("select")
131+
if(isnull(params["item"]))
132+
return
133+
var/item = text2path(params["item"])
134+
selected_item = item
135+
buying = TRUE
136+
. = TRUE
137+
if("cancel")
138+
selected_item = null
139+
buying = FALSE
140+
. = TRUE
141+
if("buy")
142+
if(isnull(params["method"]))
143+
return
144+
if(isnull(selected_item))
145+
buying = FALSE
146+
return
147+
var/datum/blackmarket_market/market = SSblackmarket.markets[viewing_market]
148+
market.purchase(selected_item, viewing_category, params["method"], src, usr)
149+
150+
buying = FALSE
151+
selected_item = null
152+
153+
/datum/crafting_recipe/blackmarket_uplink
154+
name = "Black Market Uplink"
155+
result = /obj/item/blackmarket_uplink
156+
time = 30
157+
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER, TOOL_MULTITOOL)
158+
reqs = list(
159+
/obj/item/stock_parts/subspace/amplifier = 1,
160+
/obj/item/stack/cable_coil = 15,
161+
/obj/item/radio = 1,
162+
/obj/item/analyzer = 1
163+
)
164+
category = CAT_MISC

0 commit comments

Comments
 (0)