# Conflicts:
#	icons/mob/clothing/suit.dmi
#	icons/obj/clothing/suits.dmi
This commit is contained in:
zerothebigboy
2021-03-23 13:25:13 -04:00
133 changed files with 5980 additions and 4579 deletions
@@ -125,6 +125,8 @@
/datum/antagonist/changeling/proc/remove_changeling_powers()
if(ishuman(owner.current) || ismonkey(owner.current))
reset_properties()
QDEL_NULL(cellular_emporium)
QDEL_NULL(emporium_action)
for(var/obj/effect/proc_holder/changeling/p in purchasedpowers)
if(p.always_keep)
continue
@@ -139,6 +141,7 @@
/datum/antagonist/changeling/proc/reset_powers()
if(purchasedpowers)
remove_changeling_powers()
create_actions()
//Repurchase free powers.
for(var/path in all_powers)
var/obj/effect/proc_holder/changeling/S = new path()
@@ -225,7 +228,8 @@
/datum/antagonist/changeling/proc/regenerate()
var/mob/living/carbon/the_ling = owner.current
if(istype(the_ling))
emporium_action.Grant(the_ling)
if(emporium_action)
emporium_action.Grant(the_ling)
if(the_ling.stat == DEAD)
chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), (chem_storage*0.5))
geneticdamage = max(LING_DEAD_GENETICDAMAGE_HEAL_CAP,geneticdamage-1)
@@ -11,6 +11,14 @@
//Revive from revival stasis
/obj/effect/proc_holder/changeling/revive/sting_action(mob/living/carbon/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!changeling)
return
if(changeling.hostile_absorbed)
to_chat(user, "<span class='notice'>We cannot muster up the strength to revive ourselves!</span>")
changeling.purchasedpowers -= src
src.action.Remove(user)
return
user.cure_fakedeath("changeling")
user.revive(full_heal = 1)
var/list/missing = user.get_missing_limbs()
@@ -27,7 +35,6 @@
user.regenerate_limbs(0, list(BODY_ZONE_HEAD))
user.regenerate_organs()
to_chat(user, "<span class='notice'>We have revived ourselves.</span>")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.purchasedpowers -= src
src.action.Remove(user)
return TRUE
@@ -202,8 +202,9 @@
filled = 1
release_pressure = ONE_ATMOSPHERE*2
/obj/machinery/portable_atmospherics/canister/Initialize(mapload, datum/gas_mixture/existing_mixture)
. = ..()
/obj/machinery/portable_atmospherics/canister/New(loc, datum/gas_mixture/existing_mixture)
..()
if(existing_mixture)
air_contents.copy_from(existing_mixture)
else
@@ -221,10 +222,8 @@
air_contents.set_temperature(starter_temp)
/obj/machinery/portable_atmospherics/canister/air/create_gas()
var/oh_two = /datum/gas/oxygen
var/dihydrogen = /datum/gas/nitrogen //how to piss of chemists
air_contents.set_moles(oh_two, (O2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
air_contents.set_moles(dihydrogen, (N2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
air_contents.set_moles(/datum/gas/oxygen, (O2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
air_contents.set_moles(/datum/gas/nitrogen, (N2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
/obj/machinery/portable_atmospherics/canister/update_icon_state()
if(stat & BROKEN)
@@ -0,0 +1,51 @@
/datum/blackmarket_item
var/name // Name for the item entry used in the uplink.
var/desc // Description for the item entry used in the uplink.
var/category // The category this item belongs to, should be already declared in the market that this item is accessible in.
var/list/markets = list(/datum/blackmarket_market/blackmarket) // "/datum/blackmarket_market"s that this item should be in, used by SSblackmarket on init.
var/price // Price for the item, if not set creates a price according to the *_min and *_max vars.
var/stock // How many of this type of item is available, if not set creates a price according to the *_min and *_max vars.
var/item // 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/price_min = 0 // Minimum price for the item if generated randomly.
var/price_max = 0 // Maximum price for the item if generated randomly.
var/stock_min = 1 // 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_max = 0 // Maximum amount that there should be of this item in the market if generated randomly.
var/availability_prob = 0 // Probability for this item to be available. Used by SSblackmarket on init.
/datum/blackmarket_item/New()
if(isnull(price))
price = rand(price_min, price_max)
if(isnull(stock))
stock = rand(stock_min, stock_max)
/datum/blackmarket_item/proc/spawn_item(loc) // Used for spawning the wanted item, override if you need to do something special with the item.
return new item(loc)
/datum/blackmarket_item/proc/buy(obj/item/blackmarket_uplink/uplink, mob/buyer, shipping_method) // Buys the item and makes SSblackmarket handle it.
// Sanity
if(!istype(uplink) || !istype(buyer))
return FALSE
if(!item || stock <= 0) // This shouldn't be able to happen unless there was some manipulation or admin fuckery.
return FALSE
var/datum/blackmarket_purchase/purchase = new(src, uplink, shipping_method) // Alright, the item has been purchased.
if(SSblackmarket.queue_item(purchase)) // SSblackmarket takes care of the shipping.
stock--
log_game("[key_name(buyer)] has succesfully purchased [name] using [shipping_method] for shipping.")
return TRUE
return FALSE
/datum/blackmarket_purchase // This exists because it is easier to keep track of all the vars this way.
var/datum/blackmarket_item/entry // The entry being purchased.
var/item // Instance of the item being sent.
var/obj/item/blackmarket_uplink/uplink // The uplink where this purchase was done from.
var/method // Shipping method used to buy this item.
/datum/blackmarket_purchase/New(_entry, _uplink, _method)
entry = _entry
if(!ispath(entry.item))
item = entry.item
uplink = _uplink
method = _method
@@ -0,0 +1,55 @@
/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
@@ -0,0 +1,58 @@
/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 = "Shoddy Stimulants"
desc = "Feel the energy inside each needle!"
item = /obj/item/reagent_containers/hypospray/medipen/stimpack
stock_max = 5
price_min = 50
price_max = 150
availability_prob = 90
@@ -0,0 +1,53 @@
/datum/blackmarket_item/misc
category = "Miscellaneous"
/datum/blackmarket_item/misc/cap_gun
name = "Cap Gun"
desc = "Prank your friends with this harmless gun! Harmlessness guranteed."
item = /obj/item/toy/gun
price_min = 50
price_max = 200
stock_max = 6
availability_prob = 80
/datum/blackmarket_item/misc/shoulder_holster
name = "Shoulder holster"
desc = "Yeehaw, hardboiled friends! This holster is the first step in your dream of becoming a detective and being allowed to shoot real guns!"
item = /obj/item/storage/belt/holster
price_min = 400
price_max = 800
stock_max = 8
availability_prob = 60
/datum/blackmarket_item/misc/holywater
name = "Flask of holy water"
desc = "Father Lootius' own brand of ready-made holy water."
item = /obj/item/reagent_containers/food/drinks/bottle/holywater
price_min = 400
price_max = 600
stock_max = 3
availability_prob = 40
/datum/blackmarket_item/misc/holywater/spawn_item(loc)
if (prob(6.66))
return new /obj/item/reagent_containers/glass/beaker/unholywater(loc)
return ..()
/datum/blackmarket_item/misc/strange_seed
name = "Strange Seeds"
desc = "An Exotic Variety of seed that can contain anything from glow to acid."
item = /obj/item/seeds/random
price_min = 320
price_max = 360
stock_min = 2
stock_max = 5
availability_prob = 50
/datum/blackmarket_item/misc/smugglers_satchel
name = "Smuggler's Satchel"
desc = "This easily hidden satchel can become a versatile tool to anybody with the desire to keep certain items out of sight and out of mind."
item = /obj/item/storage/backpack/satchel/flat
price_min = 750
price_max = 1000
stock_max = 2
availability_prob = 30
@@ -0,0 +1,74 @@
/datum/blackmarket_item/tool
category = "Tools"
/datum/blackmarket_item/tool/caravan_wrench
name = "Experimental Wrench"
desc = "The extra fast and handy wrench you always wanted!"
item = /obj/item/wrench/caravan
stock = 1
price_min = 400
price_max = 800
availability_prob = 20
/datum/blackmarket_item/tool/caravan_wirecutters
name = "Experimental Wirecutters"
desc = "The extra fast and handy wirecutters you always wanted!"
item = /obj/item/wirecutters/caravan
stock = 1
price_min = 400
price_max = 800
availability_prob = 20
/datum/blackmarket_item/tool/caravan_screwdriver
name = "Experimental Screwdriver"
desc = "The extra fast and handy screwdriver you always wanted!"
item = /obj/item/screwdriver/caravan
stock = 1
price_min = 400
price_max = 800
availability_prob = 20
/datum/blackmarket_item/tool/caravan_crowbar
name = "Experimental Crowbar"
desc = "The extra fast and handy crowbar you always wanted!"
item = /obj/item/crowbar/red/caravan
stock = 1
price_min = 400
price_max = 800
availability_prob = 20
/datum/blackmarket_item/tool/binoculars
name = "Binoculars"
desc = "Increase your sight by 150% with this handy tool!"
item = /obj/item/binoculars
stock = 1
price_min = 400
price_max = 960
availability_prob = 30
/datum/blackmarket_item/tool/riot_shield
name = "Riot Shield"
desc = "Protect yourself from an unexpected riot at your local police department!"
item = /obj/item/shield/riot
price_min = 450
price_max = 650
stock_max = 2
availability_prob = 50
/datum/blackmarket_item/tool/thermite_bottle
name = "Thermite Bottle"
desc = "30 units of Thermite to assist in creating a quick access point or get away!"
item = /obj/item/reagent_containers/glass/bottle/thermite
price_min = 500
price_max = 1500
stock_max = 3
availability_prob = 30
/datum/blackmarket_item/tool/science_goggles
name = "Science Goggles"
desc = "These glasses scan the contents of containers and projects their contents to the user in an easy-to-read format."
item = /obj/item/clothing/glasses/science
price_min = 150
price_max = 200
stock_max = 3
availability_prob = 50
@@ -0,0 +1,41 @@
/datum/blackmarket_item/weapon
category = "Weapons"
/datum/blackmarket_item/weapon/bear_trap
name = "Bear Trap"
desc = "Get the janitor back at his own game with this affordable prank kit."
item = /obj/item/restraints/legcuffs/beartrap
price_min = 300
price_max = 550
stock_max = 3
availability_prob = 40
/datum/blackmarket_item/weapon/shotgun_dart
name = "Shotgun Dart"
desc = "These handy darts can be filled up with any chemical and be shot with a shotgun! \
Prank your friends by shooting them with laughter! \
Not recommended for commercial use."
item = /obj/item/ammo_casing/shotgun/dart
price_min = 10
price_max = 50
stock_min = 5
stock_max = 30
availability_prob = 40
/datum/blackmarket_item/weapon/bone_spear
name = "Bone Spear"
desc = "Authentic tribal spear, made from real bones! A steal at any price, especially if you're a caveman."
item = /obj/item/spear/bonespear
price_min = 200
price_max = 300
stock_max = 3
availability_prob = 60
/datum/blackmarket_item/weapon/emp_grenade
name = "EMP Grenade"
desc = "Use this grenade for SHOCKING results!"
item = /obj/item/grenade/empgrenade
price_min = 100
price_max = 400
stock_max = 2
availability_prob = 50
@@ -0,0 +1,40 @@
/datum/blackmarket_market
var/name = "huh?" // Name for the market.
var/list/shipping // Available shipping methods and prices, just leave the shipping method out that you don't want to have.
// Automatic vars, do not touch these.
var/list/available_items = list() // Items available from this market, populated by SSblackmarket on initialization.
var/list/categories = list() // Item categories available from this market, only items which are in these categories can be gotten from this market.
/datum/blackmarket_market/proc/add_item(datum/blackmarket_item/item) // Adds item to the available items and add it's category if it is not in categories yet.
if(!prob(initial(item.availability_prob)))
return FALSE
if(ispath(item))
item = new item()
if(!(item.category in categories))
categories += item.category
available_items[item.category] = list()
available_items[item.category] += item
return TRUE
/datum/blackmarket_market/proc/purchase(item, category, method, obj/item/blackmarket_uplink/uplink, user) // Handles buying the item, this is mainly for future use and moving the code away from the uplink.
if(!istype(uplink) || !(method in shipping))
return FALSE
for(var/datum/blackmarket_item/I in available_items[category])
if(I.type != item)
continue
var/price = I.price + shipping[method]
if(uplink.money < price) // I can't get the price of the item and shipping in a clean way to the UI, so I have to do this.
to_chat("<span class='warning'>You don't have enough credits in [uplink] for [I] with [method] shipping.</span>")
return FALSE
if(I.buy(uplink, user, method))
uplink.money -= price
return TRUE
return FALSE
/datum/blackmarket_market/blackmarket
name = "Black Market"
shipping = list(SHIPPING_METHOD_LTSRBT =50,
SHIPPING_METHOD_LAUNCH =10,
SHIPPING_METHOD_TELEPORT=75)
@@ -0,0 +1,92 @@
/obj/item/circuitboard/machine/ltsrbt
name = "LTSRBT (Machine Board)"
icon_state = "bluespacearray"
build_path = /obj/machinery/ltsrbt
req_components = list(
/obj/item/stack/ore/bluespace_crystal = 2,
/obj/item/stock_parts/subspace/ansible = 1,
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stock_parts/scanning_module = 2)
def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial)
/obj/machinery/ltsrbt
name = "Long-To-Short-Range-Bluespace-Transciever"
desc = "The LTSRBT is a compact teleportation machine for recieving and sending items outside the station and inside the station.\nUsing teleportation frequencies stolen from NT it is near undetectable.\nEssential for any illegal market operations on NT stations.\n"
icon_state = "exonet_node"
circuit = /obj/item/circuitboard/machine/ltsrbt
density = TRUE
idle_power_usage = 200
var/power_efficiency = 1 // Divider for power_usage_per_teleport.
var/power_usage_per_teleport = 10000 // Power used per teleported which gets divided by power_efficiency.
var/recharge_time = 0 // The time it takes for the machine to recharge before being able to send or recieve items.
var/recharge_cooldown = 0 // Current recharge progress.
var/base_recharge_time = 100 // Base recharge time which is used to get recharge_time.
var/recieving // Current /datum/blackmarket_purchase being recieved.
var/transmitting // Current /datum/blackmarket_purchase being sent to the target uplink.
var/list/datum/blackmarket_purchase/queue = list() // Queue for purchases that the machine should recieve and send.
/obj/machinery/ltsrbt/Initialize()
. = ..()
SSblackmarket.telepads += src
/obj/machinery/ltsrbt/Destroy()
SSblackmarket.telepads -= src
if(SSblackmarket.telepads.len) // Bye bye orders.
for(var/datum/blackmarket_purchase/P in queue)
SSblackmarket.queue_item(P)
. = ..()
/obj/machinery/ltsrbt/RefreshParts()
recharge_time = base_recharge_time
for(var/obj/item/stock_parts/scanning_module/scan in component_parts) // On tier 4 recharge_time should be 20 and by default it is 80 as scanning modules should be tier 1.
recharge_time -= scan.rating * 10
recharge_cooldown = recharge_time
power_efficiency = 0
for(var/obj/item/stock_parts/micro_laser/laser in component_parts)
power_efficiency += laser.rating
if(!power_efficiency) // Shouldn't happen but you never know.
power_efficiency = 1
/obj/machinery/ltsrbt/proc/add_to_queue(datum/blackmarket_purchase/purchase) // Adds /datum/blackmarket_purchase to queue unless the machine is free, then it sets the purchase to be instantly recieved
if(!recharge_cooldown && !recieving && !transmitting)
recieving = purchase
return
queue += purchase
/obj/machinery/ltsrbt/process()
if(stat & NOPOWER)
return
if(recharge_cooldown)
recharge_cooldown--
return
var/turf/T = get_turf(src)
if(recieving)
var/datum/blackmarket_purchase/P = recieving
if(!P.item || ispath(P.item))
P.item = P.entry.spawn_item(T)
else
var/atom/movable/M = P.item
M.forceMove(T)
use_power(power_usage_per_teleport / power_efficiency)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(5, 1, get_turf(src))
sparks.attach(P.item)
sparks.start()
recieving = null
transmitting = P
recharge_cooldown = recharge_time
return
else if(transmitting)
var/datum/blackmarket_purchase/P = transmitting
if(!P.item)
QDEL_NULL(transmitting)
if(!(P.item in T.contents))
QDEL_NULL(transmitting)
return
do_teleport(P.item, get_turf(P.uplink))
use_power(power_usage_per_teleport / power_efficiency)
QDEL_NULL(transmitting)
recharge_cooldown = recharge_time
return
if(queue.len)
recieving = pick_n_take(queue)
@@ -0,0 +1,141 @@
/obj/item/blackmarket_uplink
name = "Black Market Uplink"
icon = 'icons/obj/blackmarket.dmi'
icon_state = "uplink"
// UI variables.
var/ui_x = 720
var/ui_y = 480
var/viewing_category
var/viewing_market
var/selected_item
var/buying
var/money = 0 // How much money is inserted into the uplink.
var/list/accessible_markets = list(/datum/blackmarket_market/blackmarket) // List of typepaths for "/datum/blackmarket_market"s that this uplink can access.
/obj/item/blackmarket_uplink/Initialize()
. = ..()
if(accessible_markets.len)
viewing_market = accessible_markets[1]
var/list/categories = SSblackmarket.markets[viewing_market].categories
if(categories && categories.len)
viewing_category = categories[1]
/obj/item/blackmarket_uplink/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/holochip) || istype(I, /obj/item/stack/spacecash) || istype(I, /obj/item/coin))
var/worth = I.get_item_credit_value()
if(!worth)
to_chat(user, "<span class='warning'>[I] doesn't seem to be worth anything!</span>")
money += worth
to_chat(user, "<span class='notice'>You slot [I] into [src] and it reports a total of [money] credits inserted.</span>")
qdel(I)
return
. = ..()
/obj/item/blackmarket_uplink/AltClick(mob/user)
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
var/amount_to_remove = FLOOR(input(user, "How much do you want to withdraw? Current Amount: [money]", "Withdraw Funds", 5) as num|null, 1)
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
if(!amount_to_remove || amount_to_remove < 0)
return
if(amount_to_remove > money)
to_chat(user, "<span class='warning'>There is only [money] credits in [src]</span>")
return
var/obj/item/holochip/holochip = new (user.drop_location(), amount_to_remove)
money -= amount_to_remove
holochip.name = "washed " + holochip.name
user.put_in_hands(holochip)
to_chat(user, "<span class='notice'>You withdraw [amount_to_remove] credits into a holochip.</span>")
/obj/item/blackmarket_uplink/ui_interact(mob/user, ui_key = "BlackMarketUplink", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/item/blackmarket_uplink/ui_data(mob/user)
var/list/data = list()
var/datum/blackmarket_market/market = viewing_market ? SSblackmarket.markets[viewing_market] : null
data["categories"] = market ? market.categories : null
data["delivery_methods"] = list()
if(market)
for(var/delivery in market.shipping)
data["delivery_methods"] += list(list("name" = delivery, "price" = market.shipping[delivery]))
data["money"] = money
data["buying"] = buying
data["items"] = list()
data["viewing_category"] = viewing_category
data["viewing_market"] = viewing_market
if(viewing_category && market)
if(market.available_items[viewing_category])
for(var/datum/blackmarket_item/I in market.available_items[viewing_category])
data["items"] += list(list(
"id" = I.type,
"name" = I.name,
"cost" = I.price,
"amount" = I.stock,
"desc" = I.desc || I.name
))
return data
/obj/item/blackmarket_uplink/ui_static_data(mob/user)
var/list/data = list()
data["delivery_method_description"] = SSblackmarket.shipping_method_descriptions
data["ltsrbt_built"] = SSblackmarket.telepads.len
data["markets"] = list()
for(var/M in accessible_markets)
var/datum/blackmarket_market/BM = SSblackmarket.markets[M]
data["markets"] += list(list(
"id" = M,
"name" = BM.name
))
return data
/obj/item/blackmarket_uplink/ui_act(action, params)
if(..())
return
switch(action)
if("set_category")
if(isnull(params["category"]))
return
if(isnull(viewing_market))
return
if(!(params["category"] in SSblackmarket.markets[viewing_market].categories))
return
viewing_category = params["category"]
. = TRUE
if("set_market")
if(isnull(params["market"]))
return
var/market = text2path(params["market"])
if(!(market in accessible_markets))
return
viewing_market = market
var/list/categories = SSblackmarket.markets[viewing_market].categories
if(categories && categories.len)
viewing_category = categories[1]
else
viewing_category = null
. = TRUE
if("select")
if(isnull(params["item"]))
return
var/item = text2path(params["item"])
selected_item = item
buying = TRUE
. = TRUE
if("cancel")
selected_item = null
buying = FALSE
. = TRUE
if("buy")
if(isnull(params["method"]))
return
if(isnull(selected_item))
buying = FALSE
return
var/datum/blackmarket_market/market = SSblackmarket.markets[viewing_market]
market.purchase(selected_item, viewing_category, params["method"], src, usr)
buying = FALSE
selected_item = null
+20 -8
View File
@@ -16,7 +16,7 @@
errors |= MANIFEST_ERROR_ITEM
/obj/item/paper/fluff/jobs/cargo/manifest/proc/is_approved()
return stamped && stamped.len && !is_denied()
return stamped?.len && !is_denied()
/obj/item/paper/fluff/jobs/cargo/manifest/proc/is_denied()
return stamped && ("stamp-deny" in stamped)
@@ -49,6 +49,7 @@
P.info += "<h2>[station_name()] Supply Requisition</h2>"
P.info += "<hr/>"
P.info += "Order #[id]<br/>"
P.info += "Time of Order: [STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]<br/>"
P.info += "Item: [pack.name]<br/>"
P.info += "Access Restrictions: [get_access_desc(pack.access)]<br/>"
P.info += "Requested by: [orderer]<br/>"
@@ -68,10 +69,10 @@
P.name = "shipping manifest - [packname?"#[id] ([pack.name])":"(Grouped Item Crate)"]"
P.info += "<h2>[command_name()] Shipping Manifest</h2>"
P.info += "<hr/>"
if(id && !(id == "Cargo"))
if(owner && !(owner == "Cargo"))
P.info += "Direct purchase from [owner]<br/>"
P.name += " - Purchased by [owner]"
P.info += "Order #[id]<br/>"
P.info += "Order[packname?"":"s"]: [id]<br/>"
P.info += "Destination: [station_name]<br/>"
if(packname)
P.info += "Item: [packname]<br/>"
@@ -82,8 +83,11 @@
var/obj/structure/closet/C = container
ignore_this += C.lockerelectronics
for(var/atom/movable/AM in container.contents - ignore_this)
if((P.errors & MANIFEST_ERROR_CONTENTS) && prob(50))
continue
if((P.errors & MANIFEST_ERROR_CONTENTS))
if(prob(50))
P.info += "<li>[AM.name]</li>"
else
continue
P.info += "<li>[AM.name]</li>"
P.info += "</ul>"
P.info += "<h4>Stamp below to confirm receipt of goods:</h4>"
@@ -94,7 +98,7 @@
/obj/structure/closet/crate/large,
/obj/structure/closet/secure_closet/goodies
))
if(blacklisted_error[container.type])
if(is_type_in_list(container, blacklisted_error))
P.errors &= ~MANIFEST_ERROR_ITEM
else
var/lost = max(round(container.contents.len / 10), 1)
@@ -108,15 +112,23 @@
var/obj/structure/closet/crate/C = container
C.manifest = P
C.update_icon()
else
// manifest goes in if it's not a crate
container.contents += P
return P
/datum/supply_order/proc/generate(atom/A)
var/account_holder
if(paying_account)
account_holder = paying_account.account_holder
else
account_holder = "Cargo"
var/obj/structure/closet/crate/C = pack.generate(A, paying_account)
generateManifest(C, paying_account, pack)
generateManifest(C, account_holder, pack)
return C
/datum/supply_order/proc/generateCombo(var/miscbox, var/misc_own, var/misc_contents)
/datum/supply_order/proc/generateCombo(miscbox, misc_own, misc_contents)
for (var/I in misc_contents)
new I(miscbox)
generateManifest(miscbox, misc_own, "")
+11
View File
@@ -434,6 +434,17 @@
/obj/item/stack/tile/noslip/thirty)
crate_name = "high-traction floor tiles crate"
/datum/supply_pack/misc/blackmarket_telepad
name = "Black Market LTSRBT"
desc = "Need a faster and better way of transporting your illegal goods from and to the station? Fear not, the Long-To-Short-Range-Bluespace-Transceiver (LTSRBT for short) is here to help. Contains a LTSRBT circuit, two bluespace crystals, and one ansible."
cost = 8000
contraband = TRUE
contains = list(/obj/item/circuitboard/machine/ltsrbt,
/obj/item/stack/ore/bluespace_crystal/artificial,
/obj/item/stack/ore/bluespace_crystal/artificial,
/obj/item/stock_parts/subspace/ansible)
crate_name = "crate"
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Lewd Supplies ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////
+9 -1
View File
@@ -67,7 +67,7 @@
/datum/supply_pack/vending/hydro
name = "Hydroponics Supply Crate"
desc = "Arnt you glad you dont have to do it the natural way? Contains a megaseed and nutrimax vending machine refill."
desc = "Aren't you glad you dont have to do it the natural way? Contains a megaseed and nutrimax vending machine refill."
cost = 5000
contains = list(/obj/item/vending_refill/hydroseeds,
/obj/item/vending_refill/hydronutrients)
@@ -82,6 +82,14 @@
contains = list(/obj/item/vending_refill/kink)
crate_name = "Kinkmate construction kit"
/datum/supply_pack/vending/barkbox
name = "Bark Box Supply Crate"
desc = "Running of out things to keep your pets happy?"
cost = 2000
contraband = TRUE
contains = list(/obj/item/vending_refill/barkbox)
crate_name = "bark box supply crate"
/datum/supply_pack/vending/medical
name = "Medical Vending Crate"
desc = "Contains refills for medical vending machines."
+37 -28
View File
@@ -130,26 +130,28 @@
/obj/structure/closet/supplypod/update_overlays()
. = ..()
if (style == STYLE_INVISIBLE)
if(style == STYLE_INVISIBLE)
return
if (rubble)
if(rubble)
. += rubble.getForeground(src)
if (style == STYLE_SEETHROUGH)
for (var/atom/A in contents)
if(style == STYLE_SEETHROUGH)
for(var/atom/A in contents)
var/mutable_appearance/itemIcon = new(A)
itemIcon.transform = matrix().Translate(-1 * SUPPLYPOD_X_OFFSET, 0)
. += itemIcon
for (var/t in turfs_in_cargo)//T is just a turf's type
for(var/t in turfs_in_cargo)//T is just a turf's type
var/turf/turf_type = t
var/mutable_appearance/itemIcon = mutable_appearance(initial(turf_type.icon), initial(turf_type.icon_state))
itemIcon.transform = matrix().Translate(-1 * SUPPLYPOD_X_OFFSET, 0)
. += itemIcon
return
if (opened) //We're opened means all we have to worry about is masking a decal if we have one
if (!decal) //We don't have a decal to mask
if(opened) //We're opened means all we have to worry about is masking a decal if we have one
if(!decal) //We don't have a decal to mask
return
if (!door) //We have a decal but no door, so let's just add the decal
if(!door) //We have a decal but no door, so let's just add the decal
. += decal
return
var/icon/masked_decal = new(icon, decal) //The decal we want to apply
@@ -159,23 +161,25 @@
door_masker.Blend("#000000", ICON_SUBTRACT)
masked_decal.Blend(door_masker, ICON_ADD)
. += masked_decal
else //If we're closed
if (!door) //We have no door, lets see if we have a decal. If not, theres nothing we need to do
if (decal)
. += decal
return
else if (GLOB.podstyles[style][POD_SHAPE] != POD_SHAPE_NORML) //If we're not a normal pod shape (aka, if we don't have fins), just add the door without masking
. += door
else
var/icon/masked_door = new(icon, door) //The door we want to apply
var/icon/fin_masker = new(icon, "mask_[fin_mask]") //The fin shape we want to 'cut out' of the door
fin_masker.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 1,1,1,0, 0,0,0,1)
fin_masker.SwapColor("#ffffffff", null)
fin_masker.Blend("#000000", ICON_SUBTRACT)
masked_door.Blend(fin_masker, ICON_ADD)
. += masked_door
if (decal)
return
//If we're closed
if(!door) //We have no door, lets see if we have a decal. If not, theres nothing we need to do
if(decal)
. += decal
return
else if (GLOB.podstyles[style][POD_SHAPE] != POD_SHAPE_NORML) //If we're not a normal pod shape (aka, if we don't have fins), just add the door without masking
. += door
else
var/icon/masked_door = new(icon, door) //The door we want to apply
var/icon/fin_masker = new(icon, "mask_[fin_mask]") //The fin shape we want to 'cut out' of the door
fin_masker.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 1,1,1,0, 0,0,0,1)
fin_masker.SwapColor("#ffffffff", null)
fin_masker.Blend("#000000", ICON_SUBTRACT)
masked_door.Blend(fin_masker, ICON_ADD)
. += masked_door
if(decal)
. += decal
/obj/structure/closet/supplypod/tool_interact(obj/item/W, mob/user)
if(bluespace) //We dont want to worry about interacting with bluespace pods, as they are due to delete themselves soon anyways.
@@ -192,7 +196,7 @@
/obj/structure/closet/supplypod/toggle(mob/living/user)
return
/obj/structure/closet/supplypod/open(mob/living/user, force = TRUE)
/obj/structure/closet/supplypod/open(mob/living/user, force = FALSE)
return
/obj/structure/closet/supplypod/proc/handleReturnAfterDeparting(atom/movable/holder = src)
@@ -550,9 +554,6 @@
var/obj/effect/pod_landingzone_effect/helper
var/list/smoke_effects = new /list(13)
/obj/effect/ex_act()
return
/obj/effect/pod_landingzone/Initialize(mapload, podParam, single_order = null, clientman)
. = ..()
if (ispath(podParam)) //We can pass either a path for a pod (as expressconsoles do), or a reference to an instantiated pod (as the centcom_podlauncher does)
@@ -647,4 +648,12 @@
desc = "This disk provides a firmware update to the Express Supply Console, granting the use of Nanotrasen's Bluespace Drop Pods to the supply department."
icon = 'icons/obj/module.dmi'
icon_state = "cargodisk"
// inhand_icon_state = "card-id"
w_class = WEIGHT_CLASS_SMALL
// let's not.
/obj/structure/closet/supplypod/handle_lock_addition()
return
/obj/structure/closet/supplypod/handle_lock_removal()
return
+12
View File
@@ -190,6 +190,12 @@
tagname = stripped_input(user, "Would you like to change the name on the tag?", "Name your new pet", "Spot", MAX_NAME_LEN)
name = "[initial(name)] - [tagname]"
/obj/item/clothing/neck/petcollar/ribbon
name = "ribbon pet collar"
icon_state = "ribboncollar"
poly_states = 2
poly_colors = list("#454545", "#292929")
/obj/item/clothing/neck/petcollar/leather
name = "leather pet collar"
icon_state = "leathercollar"
@@ -225,6 +231,12 @@
return
..()
/obj/item/clothing/neck/petcollar/locked/ribbon
name = "ribbon pet collar"
icon_state = "ribboncollar"
poly_states = 2
poly_colors = list("#454545", "#292929")
/obj/item/clothing/neck/petcollar/locked/leather
name = "leather pet collar"
icon_state = "leathercollar"
@@ -567,6 +567,26 @@
attack_verb = list("warned", "cautioned", "smashed")
armor = list("melee" = 5, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/clothing/suit/petharness
name = "pet harness"
desc = "For your pet! Or not! Has a little clip on the back."
icon_state = "petharness"
item_state = "petharness"
body_parts_covered = NONE
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
allowed = /obj/item/toy/fluff
/obj/item/clothing/suit/petharness/mesh
name = "mesh pet harness"
desc = "For your pet! Or not! Has some mesh to cover up your more sensitive bits and a little clip on the back."
icon_state = "petharness_mesh"
item_state = "petharness_mesh"
body_parts_covered = CHEST
/obj/item/clothing/suit/petharness/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, list("#0056D9", "#959595"), 2, _flags = POLYCHROMIC_ACTION)
// WINTER COATS
/obj/item/clothing/suit/hooded/wintercoat
+19 -3
View File
@@ -13,11 +13,27 @@
var/power = 2000
/datum/round_event/supermatter_surge/setup()
power = rand(200,4000)
if(prob(70))
power = rand(200,100000)
else
power = rand(200,200000)
/datum/round_event/supermatter_surge/announce()
if(power > 800 || prob(round(power/8)))
priority_announce("Class [round(power/500) + 1] supermatter surge detected. Intervention may be required.", "Anomaly Alert")
var/severity = ""
switch(power)
if(-INFINITY to 100000)
var/low_threat_perc = 100-round(100*((power-200)/(100000-200)))
if(prob(low_threat_perc))
if(prob(low_threat_perc))
severity = "low; the supermatter should return to normal operation shortly."
else
severity = "medium; the supermatter should return to normal operation, but check NT CIMS to ensure this."
else
severity = "high; if the supermatter's cooling is not fortified, coolant may need to be added."
if(100000 to INFINITY)
severity = "extreme; emergency action is likely to be required even if coolant loop is fine."
if(power > 20000 || prob(round(power/200)))
priority_announce("Supermatter surge detected. Estimated severity is [severity]", "Anomaly Alert")
/datum/round_event/supermatter_surge/start()
GLOB.main_supermatter_engine.matter_power += power
@@ -466,6 +466,17 @@
foodtype = GRAIN | SUGAR
dunkable = TRUE
/obj/item/reagent_containers/food/snacks/dogtreat
name = "dog treat"
desc = "It's a scooby-snack. Right?"
icon_state = "dogtreat"
bitesize = 1
bonus_reagents = list(/datum/reagent/consumable/nutriment = 1)
list_reagents = list(/datum/reagent/consumable/nutriment = 1)
filling_color = "#635444"
tastes = list("meat" = 1, "dough" = 1)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/donkpocket
name = "\improper Donk-pocket"
desc = "The food of choice for the seasoned traitor."
@@ -214,6 +214,17 @@
result = /obj/item/reagent_containers/food/snacks/cracker
subcategory = CAT_PASTRY
/datum/crafting_recipe/food/dogtreat
time = 15
name = "Dog Treat"
reqs = list(
/datum/reagent/consumable/sodiumchloride = 1,
/obj/item/reagent_containers/food/snacks/meat/cutlet = 1,
/obj/item/reagent_containers/food/snacks/pastrybase = 1,
)
result = /obj/item/reagent_containers/food/snacks/dogtreat
subcategory = CAT_PASTRY
/datum/crafting_recipe/food/fortunecookie
time = 15
name = "Fortune cookie"
@@ -1285,8 +1285,8 @@
if(isliving(target) && chaser_timer <= world.time) //living and chasers off cooldown? fire one!
chaser_timer = world.time + chaser_cooldown
var/obj/effect/temp_visual/hierophant/chaser/C = new(get_turf(user), user, target, chaser_speed, friendly_fire_check)
C.damage = 30
C.monster_damage_boost = FALSE
C.damage = 15
C.monster_damage_boost = TRUE
log_combat(user, target, "fired a chaser at", src)
else
INVOKE_ASYNC(src, .proc/cardinal_blasts, T, user) //otherwise, just do cardinal blast
@@ -1402,10 +1402,10 @@
new /obj/effect/temp_visual/hierophant/telegraph/teleport(source, user)
for(var/t in RANGE_TURFS(1, T))
var/obj/effect/temp_visual/hierophant/blast/B = new /obj/effect/temp_visual/hierophant/blast(t, user, TRUE) //blasts produced will not hurt allies
B.damage = 30
B.damage = 15
for(var/t in RANGE_TURFS(1, source))
var/obj/effect/temp_visual/hierophant/blast/B = new /obj/effect/temp_visual/hierophant/blast(t, user, TRUE) //but absolutely will hurt enemies
B.damage = 30
B.damage = 15
for(var/mob/living/L in range(1, source))
INVOKE_ASYNC(src, .proc/teleport_mob, source, L, T, user) //regardless, take all mobs near us along
sleep(6) //at this point the blasts detonate
@@ -1466,8 +1466,8 @@
if(!J)
return
var/obj/effect/temp_visual/hierophant/blast/B = new(J, user, friendly_fire_check)
B.damage = 30
B.monster_damage_boost = FALSE
B.damage = 15
B.monster_damage_boost = TRUE
previousturf = J
J = get_step(previousturf, dir)
@@ -1479,7 +1479,7 @@
sleep(2)
for(var/t in RANGE_TURFS(1, T))
var/obj/effect/temp_visual/hierophant/blast/B = new(t, user, friendly_fire_check)
B.damage = 15 //keeps monster damage boost due to lower damage
B.damage = 15 //keeps monster damage boost due to lower damage (now added to all damage due to reduction to 15, 30dmg 50AP isn't cool)
//Just some minor stuff
@@ -115,13 +115,13 @@
. = ..()
if(!.)
return
if(HAS_TRAIT(src, TRAIT_NOGUNS))
to_chat(src, "<span class='warning'>You can't bring yourself to use a ranged weapon!</span>")
return FALSE
if(G.trigger_guard == TRIGGER_GUARD_NORMAL)
if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS))
to_chat(src, "<span class='warning'>Your meaty finger is much too large for the trigger guard!</span>")
return FALSE
if(HAS_TRAIT(src, TRAIT_NOGUNS))
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
return FALSE
/mob/living/carbon/human/proc/get_bank_account()
RETURN_TYPE(/datum/bank_account)
@@ -37,11 +37,11 @@
to_chat(owner, "There's something stuck to your hand, stopping you from transforming!")
return
if(IsAvailable())
transforming = TRUE
UpdateButtonIcon()
var/mutcolor = owner.get_ability_property(INNATE_ABILITY_SLIME_BLOBFORM, PROPERTY_BLOBFORM_COLOR) || ("#" + H.dna.features["mcolor"])
if(!is_puddle)
if(CHECK_MOBILITY(H, MOBILITY_USE)) //if we can use items, we can turn into a puddle
transforming = TRUE
is_puddle = TRUE //so we know which transformation to use when its used
ADD_TRAIT(H, TRAIT_HUMAN_NO_RENDER, SLIMEPUDDLE_TRAIT)
owner.cut_overlays() //we dont show our normal sprite, we show a puddle sprite
@@ -3,7 +3,7 @@
id = SPECIES_VAMPIRE
default_color = "FFFFFF"
species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,DRINKSBLOOD,HAS_FLESH,HAS_BONE)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH)
inherent_traits = list(TRAIT_NOHUNGER,TRAIT_NOBREATH,TRAIT_NOMARROW)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
mutant_bodyparts = list("mcolor" = "FFFFFF", "tail_human" = "None", "ears" = "None", "deco_wings" = "None")
exotic_bloodtype = "U"
@@ -53,10 +53,11 @@
C.adjustOxyLoss(-4)
C.adjustCloneLoss(-4)
return
C.blood_volume -= 0.75 //Will take roughly 19.5 minutes to die from standard blood volume, roughly 83 minutes to die from max blood volume.
if(C.blood_volume <= (BLOOD_VOLUME_SURVIVE*C.blood_ratio))
to_chat(C, "<span class='danger'>You ran out of blood!</span>")
C.dust()
if(C.blood_volume > 0.5)
C.blood_volume -= 0.5 //Will take roughly 19.5 minutes to die from standard blood volume, roughly 83 minutes to die from max blood volume.
else
C.dust(FALSE, TRUE)
var/area/A = get_area(C)
if(istype(A, /area/chapel) && C.mind?.assigned_role != "Chaplain")
to_chat(C, "<span class='danger'>You don't belong here!</span>")
@@ -125,7 +126,7 @@
. = ..()
var/obj/item/organ/heart/vampire/darkheart = getorgan(/obj/item/organ/heart/vampire)
if(darkheart)
. += "<span class='notice'>Current blood level: [blood_volume]/[BLOOD_VOLUME_MAXIMUM].</span>"
. += "Current blood level: [blood_volume]/[BLOOD_VOLUME_MAXIMUM]."
/obj/item/organ/heart/vampire
+5 -4
View File
@@ -90,11 +90,11 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE)
var/ic_blocked = FALSE
/*
if(client && !forced && config.ic_filter_regex && findtext(message, config.ic_filter_regex))
if(client && !forced && CHAT_FILTER_CHECK(message))
//The filter doesn't act on the sanitized message, but the raw message.
ic_blocked = TRUE
*/
if(sanitize)
message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message || message == "")
@@ -103,6 +103,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(ic_blocked)
//The filter warning message shows the sanitized message though.
to_chat(src, "<span class='warning'>That message contained a word prohibited in IC chat! Consider reviewing the server rules.\n<span replaceRegex='show_filtered_ic_chat'>\"[message]\"</span></span>")
SSblackbox.record_feedback("tally", "ic_blocked_words", 1, lowertext(config.ic_filter_regex.match))
return
var/datum/saymode/saymode = SSradio.saymodes[talk_key]
@@ -333,7 +334,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/obj/item/bodypart/rightarm = get_bodypart(BODY_ZONE_R_ARM)
if(HAS_TRAIT(src, TRAIT_MUTE) && get_selected_language() != /datum/language/signlanguage)
return 0
if (get_selected_language() == /datum/language/signlanguage)
var/left_disabled = FALSE
var/right_disabled = FALSE
@@ -25,6 +25,7 @@
/obj/item/modular_computer/laptop/examine(mob/user)
. = ..()
. += "<span class='notice'>Drag it in your hand to pick it up.</span>"
if(screen_on)
. += "<span class='notice'>Alt-click to close it.</span>"
@@ -76,6 +77,9 @@
M.put_in_hand(src, H.held_index)
/obj/item/modular_computer/laptop/on_attack_hand(mob/user)
. = ..()
if(!.)
return
if(screen_on && isturf(loc))
return attack_self(user)
@@ -1,8 +1,9 @@
/datum/computer_file/program/budgetorders
filename = "orderapp"
filedesc = "Nanotrasen Internal Requisition Network (NIRN)"
filedesc = "NT IRN"
// category = PROGRAM_CATEGORY_SUPL
program_icon_state = "request"
extended_desc = "A request network that utilizes the Nanotrasen Ordering network to purchase supplies using a department budget account."
extended_desc = "Nanotrasen Internal Requisition Network interface for supply purchasing using a department budget account."
requires_ntnet = TRUE
transfer_access = ACCESS_HEADS
usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET
@@ -79,7 +80,6 @@
data["supplies"] = list()
for(var/pack in SSshuttle.supply_packs)
var/datum/supply_pack/P = SSshuttle.supply_packs[pack]
// todo: replace to P.access_view
if(!is_visible_pack(usr, P.access , null, P.contraband) || P.hidden)
continue
if(!data["supplies"][P.group])
@@ -105,7 +105,7 @@
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE
data["loan"] = !!SSshuttle.shuttle_loan
data["loan_dispatched"] = SSshuttle.shuttle_loan && SSshuttle.shuttle_loan.dispatched
data["can_send"] = FALSE //There is no situation where I want the app to be able to send the shuttle AWAY from the station, but conversely is fine.
data["can_send"] = FALSE //There is no situation where I want the app to be able to send the shuttle AWAY from the station, but conversely is fine.
data["can_approve_requests"] = can_approve_requests
data["app_cost"] = TRUE
var/message = "Remember to stamp and send back the supply manifests."
@@ -20,7 +20,8 @@
"Head of Security",
"Chief Engineer",
"Research Director",
"Chief Medical Officer")
"Chief Medical Officer",
"Quartermaster")
//The scaling factor of max total positions in relation to the total amount of people on board the station in %
var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players
@@ -43,7 +44,7 @@
/datum/computer_file/program/job_management/proc/can_close_job(datum/job/job)
if(!(job?.title in blacklisted))
if(job.total_positions > length(GLOB.player_list) * (max_relative_positions / 100))
if(job.total_positions > job.current_positions)
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
return TRUE
@@ -67,7 +68,7 @@
if(!j || !can_open_job(j))
return
if(opened_positions[edit_job_target] >= 0)
GLOB.time_last_changed_position = world.time / 10
GLOB.time_last_changed_position = world.time / 10 // global cd
j.total_positions++
opened_positions[edit_job_target]++
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
@@ -453,3 +453,8 @@
/obj/item/reagent_containers/glass/bottle/ichor/green
name = "green potion"
list_reagents = list(/datum/reagent/green_ichor = 1)
/obj/item/reagent_containers/glass/bottle/thermite
name = "thermite bottle"
list_reagents = list(/datum/reagent/thermite = 30)
@@ -9,7 +9,7 @@
build_type = IMPRINTER
materials = list(/datum/material/glass = 1000)
build_path = /obj/item/circuitboard/computer/cargo/express
category = list("Mining Designs")
category = list("Computer Boards")
departmental_flags = DEPARTMENTAL_FLAG_CARGO
/datum/design/bluespace_pod
@@ -19,7 +19,7 @@
build_type = PROTOLATHE
materials = list(/datum/material/glass = 1000)
build_path = /obj/item/disk/cargo/bluespace_pod
category = list("Mining Designs")
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_CARGO
/datum/design/drill
+63 -33
View File
@@ -25,7 +25,14 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
/obj/item/shared_storage,
/obj/structure/extraction_point,
/obj/machinery/syndicatebomb,
/obj/item/hilbertshotel
/obj/item/hilbertshotel,
/obj/machinery/launchpad,
/obj/machinery/disposal,
/obj/structure/disposalpipe,
/obj/item/hilbertshotel,
/obj/machinery/camera,
/obj/item/gps,
/obj/structure/checkoutmachine
)))
GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
@@ -33,6 +40,11 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
/mob/living/simple_animal/slaughter
)))
/// How many goody orders we can fit in a lockbox before we upgrade to a crate
#define GOODY_FREE_SHIPPING_MAX 5
/// How much to charge oversized goody orders
#define CRATE_TAX 700
/obj/docking_port/mobile/supply
name = "supply shuttle"
id = "supply"
@@ -58,6 +70,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
return check_blacklist(shuttle_areas, GLOB.blacklisted_cargo_types - GLOB.cargo_shuttle_leave_behind_typecache)
return ..()
// fuc off
/obj/docking_port/mobile/supply/enterTransit()
var/list/leave_behind = list()
for(var/i in check_blacklist(shuttle_areas, GLOB.cargo_shuttle_leave_behind_typecache))
@@ -98,12 +111,11 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
sell()
/obj/docking_port/mobile/supply/proc/buy()
if(!SSshuttle.shoppinglist.len)
return
var/list/obj/miscboxes = list() //miscboxes are combo boxes that contain all goody orders grouped
var/list/misc_order_num = list() //list of strings of order numbers, so that the manifest can show all orders in a box
var/list/misc_contents = list() //list of lists of items that each box will contain
if(!SSshuttle.shoppinglist.len)
return
var/list/empty_turfs = list()
for(var/place in shuttle_areas)
@@ -113,30 +125,39 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
continue
empty_turfs += T
var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/value = 0
var/purchases = 0
var/list/goodies_by_buyer = list() // if someone orders more than GOODY_FREE_SHIPPING_MAX goodies, we upcharge to a normal crate so they can't carry around 20 combat shotties
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
if(!empty_turfs.len)
break
var/price = SO.pack.cost
if(SO.applied_coupon)
price *= (1 - SO.applied_coupon.discount_pct_off)
var/datum/bank_account/D
if(SO.paying_account) //Someone paid out of pocket
D = SO.paying_account
var/list/current_buyer_orders = goodies_by_buyer[SO.paying_account] // so we can access the length a few lines down
if(!SO.pack.goody)
price *= 1.1 //TODO make this customizable by the quartermaster
// note this is before we increment, so this is the GOODY_FREE_SHIPPING_MAX + 1th goody to ship. also note we only increment off this step if they successfully pay the fee, so there's no way around it
else if(LAZYLEN(current_buyer_orders) == GOODY_FREE_SHIPPING_MAX)
price += CRATE_TAX
D.bank_card_talk("Goody order size exceeds free shipping limit: Assessing [CRATE_TAX] credit S&H fee.")
else
D = cargo_budget
D = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(D)
if(!D.adjust_money(-SO.pack.cost))
if(!D.adjust_money(-price))
if(SO.paying_account)
D.bank_card_talk("Cargo order #[SO.id] rejected due to lack of funds. Credits required: [price]")
continue
if(SO.paying_account)
if(SO.pack.goody)
LAZYADD(goodies_by_buyer[SO.paying_account], SO)
D.bank_card_talk("Cargo order #[SO.id] has shipped. [price] credits have been charged to your bank account.")
var/datum/bank_account/department/cargo = SSeconomy.get_dep_account(ACCOUNT_CAR)
cargo.adjust_money(price - SO.pack.cost) //Cargo gets the handling fee
@@ -145,30 +166,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
SSshuttle.orderhistory += SO
QDEL_NULL(SO.applied_coupon)
if(SO.pack.goody) //goody means it gets piled in the miscbox
if(SO.paying_account)
if(!miscboxes.len || !miscboxes[D.account_holder]) //if there's no miscbox for this person
miscboxes[D.account_holder] = new /obj/item/storage/lockbox/order(pick_n_take(empty_turfs))
var/obj/item/storage/lockbox/order/our_box = miscboxes[D.account_holder]
our_box.buyer_account = SO.paying_account
miscboxes[D.account_holder].name = "small items case - purchased by [D.account_holder]"
misc_contents[D.account_holder] = list()
for (var/item in SO.pack.contains)
misc_contents[D.account_holder] += item
misc_order_num[D.account_holder] = "[misc_order_num[D.account_holder]]#[SO.id] "
else //No private payment, so we just stuff it all into a generic crate
if(!miscboxes.len || !miscboxes["Cargo"])
miscboxes["Cargo"] = new /obj/structure/closet/secure_closet/goodies(pick_n_take(empty_turfs))
miscboxes["Cargo"].name = "small items closet"
misc_contents["Cargo"] = list()
miscboxes["Cargo"].req_access = list()
for (var/item in SO.pack.contains)
misc_contents["Cargo"] += item
//new item(miscboxes["Cargo"])
if(SO.pack.access)
miscboxes["Cargo"].req_access += SO.pack.access
misc_order_num["Cargo"] = "[misc_order_num["Cargo"]]#[SO.id] "
else
if(!SO.pack.goody) //we handle goody crates below
SO.generate(pick_n_take(empty_turfs))
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
@@ -177,16 +175,43 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)], paid by [D.account_holder] has shipped.")
purchases++
// we handle packing all the goodies last, since the type of crate we use depends on how many goodies they ordered. If it's more than GOODY_FREE_SHIPPING_MAX
// then we send it in a crate (including the CRATE_TAX cost), otherwise send it in a free shipping case
for(var/D in goodies_by_buyer)
var/list/buying_account_orders = goodies_by_buyer[D]
var/datum/bank_account/buying_account = D
var/buyer = buying_account.account_holder
if(buying_account_orders.len > GOODY_FREE_SHIPPING_MAX) // no free shipping, send a crate
var/obj/structure/closet/crate/secure/owned/our_crate = new /obj/structure/closet/crate/secure/owned(pick_n_take(empty_turfs))
our_crate.buyer_account = buying_account
our_crate.name = "goody crate - purchased by [buyer]"
miscboxes[buyer] = our_crate
else //free shipping in a case
miscboxes[buyer] = new /obj/item/storage/lockbox/order(pick_n_take(empty_turfs))
var/obj/item/storage/lockbox/order/our_case = miscboxes[buyer]
our_case.buyer_account = buying_account
miscboxes[buyer].name = "goody case - purchased by [buyer]"
misc_contents[buyer] = list()
for(var/O in buying_account_orders)
var/datum/supply_order/our_order = O
for (var/item in our_order.pack.contains)
misc_contents[buyer] += item
misc_order_num[buyer] = "[misc_order_num[buyer]]#[our_order.id] "
for(var/I in miscboxes)
var/datum/supply_order/SO = new/datum/supply_order()
SO.id = misc_order_num[I]
SO.generateCombo(miscboxes[I], I, misc_contents[I])
qdel(SO)
var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR)
investigate_log("[purchases] orders in this shipment, worth [value] credits. [cargo_budget.account_balance] credits left.", INVESTIGATE_CARGO)
/obj/docking_port/mobile/supply/proc/sell()
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/presale_points = D.account_balance
var/gain = 0
if(!GLOB.exports_list.len) // No exports list? Generate it!
@@ -204,6 +229,8 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
continue
if(bounty_ship_item_and_contents(AM, dry_run = FALSE))
matched_bounty = TRUE
// ignore mech checks because the mech is ONLY for bounty
continue
if(!AM.anchored || istype(AM, /obj/mecha))
export_item_and_contents(AM, export_categories , dry_run = FALSE, external_report = ex)
@@ -230,4 +257,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
msg = copytext_char(msg, 1, MAX_MESSAGE_LEN)
SSshuttle.centcom_message = msg
investigate_log("Shuttle contents sold for [gain] credits. Contents: [ex.exported_atoms || "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
investigate_log("Shuttle contents sold for [D.account_balance - presale_points] credits. Contents: [ex.exported_atoms ? ex.exported_atoms.Join(",") + "." : "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO)
#undef GOODY_FREE_SHIPPING_MAX
#undef CRATE_TAX
+36
View File
@@ -0,0 +1,36 @@
/obj/machinery/vending/barkbox
name = "Bark Box"
desc = "For all your pet needs!"
icon_state = "barkbox"
product_slogans = "Whuff!;Bark!;Give me a treat!"
products = list(
/obj/item/storage/fancy/treat_box = 8,
/obj/item/clothing/neck/petcollar = 5,
/obj/item/clothing/neck/petcollar/ribbon = 5,
/obj/item/clothing/neck/petcollar/leather = 5,
/obj/item/clothing/suit/petharness = 4,
/obj/item/clothing/suit/petharness/mesh = 4,
/obj/item/toy/fluff/tennis_poly = 4,
/obj/item/toy/fluff/tennis_poly/tri = 2,
/obj/item/toy/fluff/bone_poly = 4,
/obj/item/toy/fluff/frisbee_poly = 4
)
contraband = list(
/obj/item/clothing/neck/petcollar/locked = 2,
/obj/item/clothing/neck/petcollar/locked/ribbon = 2,
/obj/item/clothing/neck/petcollar/locked/leather = 2,
/obj/item/key/collar = 2,
/obj/item/dildo/knotted = 3
)
premium = list(
/obj/item/toy/fluff/tennis_poly/tri/squeak = 1,
/obj/item/toy/fluff/bone_poly/squeak = 1
)
refill_canister = /obj/item/vending_refill/barkbox
default_price = PRICE_CHEAP
extra_price = PRICE_BELOW_NORMAL
payment_department = NO_FREEBIES
/obj/item/vending_refill/barkbox
machine_name = "Bark Box"
icon_state = "refill_barkbox"