From d9fffdd07b0e31dc3b2b30dddfe0f0aff76312a3 Mon Sep 17 00:00:00 2001 From: Atermonera Date: Thu, 22 Apr 2021 15:56:56 -0700 Subject: [PATCH 01/15] Moves material stacks to modules/materials --- code/__defines/materials.dm | 63 + code/__defines/misc.dm | 59 - code/game/machinery/vending.dm | 720 -------- .../game/objects/items/stacks/sheets/glass.dm | 102 -- .../objects/items/stacks/sheets/leather.dm | 286 ---- code/modules/{mining => economy}/coins.dm | 0 code/modules/{mining => economy}/mint.dm | 0 code/modules/{mining => economy}/money_bag.dm | 194 +-- code/modules/economy/vending.dm | 1445 +++++++++++++++++ .../economy}/vending_machines.dm | 0 .../materials}/fifty_spawner.dm | 0 code/modules/materials/material_recipes.dm | 3 + .../modules/materials/materials/_materials.dm | 284 ++++ .../materials/materials/alien_alloy.dm | 36 + code/modules/materials/materials/cult.dm | 23 + code/modules/materials/materials/gems.dm | 154 ++ code/modules/materials/materials/glass.dm | 143 ++ .../materials/materials/holographic.dm | 17 + .../materials/materials/metals/hull.dm | 53 + .../materials/materials/metals/metals.dm | 199 +++ .../materials/materials/metals/plasteel.dm | 27 + .../materials/materials/metals/steel.dm | 86 + .../materials/organic/animal_products.dm | 28 + .../materials/materials/organic/cloth.dm | 121 ++ .../materials/materials/organic/leather.dm | 37 + .../materials/materials/organic/resin.dm | 45 + .../materials/materials/organic/wood.dm | 83 + code/modules/materials/materials/plastic.dm | 88 + code/modules/materials/materials/snow.dm | 56 + code/modules/materials/materials/stone.dm | 35 + .../materials/materials/supermatter.dm | 23 + code/modules/materials/sheets/_sheets.dm | 89 + code/modules/materials/sheets/gems.dm | 66 + code/modules/materials/sheets/glass.dm | 33 + code/modules/materials/sheets/metals/hull.dm | 18 + code/modules/materials/sheets/metals/metal.dm | 140 ++ .../materials/sheets/metals}/rods.dm | 216 +-- .../sheets/organic/animal_products.dm | 31 + .../modules/materials/sheets/organic/resin.dm | 8 + .../materials/sheets/organic/tanning/hide.dm | 90 + .../sheets/organic/tanning/hide_hairless.dm | 48 + .../sheets/organic/tanning/leather_wet.dm | 51 + .../sheets/organic/tanning/tanning_rack.dm | 70 + .../materials/sheets/organic/textiles.dm | 23 + code/modules/materials/sheets/organic/wood.dm | 55 + code/modules/materials/sheets/plastic.dm | 15 + code/modules/materials/sheets/snow.dm | 16 + code/modules/materials/sheets/stone.dm | 15 + code/modules/materials/sheets/supermatter.dm | 55 + .../machine_input_output_plates.dm | 36 +- .../{ => machinery}/machine_processing.dm | 0 .../{ => machinery}/machine_stacking.dm | 0 .../{ => machinery}/machine_unloading.dm | 0 vorestation.dme | 92 +- 54 files changed, 4180 insertions(+), 1397 deletions(-) create mode 100644 code/__defines/materials.dm delete mode 100644 code/game/machinery/vending.dm delete mode 100644 code/game/objects/items/stacks/sheets/glass.dm delete mode 100644 code/game/objects/items/stacks/sheets/leather.dm rename code/modules/{mining => economy}/coins.dm (100%) rename code/modules/{mining => economy}/mint.dm (100%) rename code/modules/{mining => economy}/money_bag.dm (95%) create mode 100644 code/modules/economy/vending.dm rename code/{game/machinery => modules/economy}/vending_machines.dm (100%) rename code/{game/objects/items/stacks => modules/materials}/fifty_spawner.dm (100%) create mode 100644 code/modules/materials/materials/_materials.dm create mode 100644 code/modules/materials/materials/alien_alloy.dm create mode 100644 code/modules/materials/materials/cult.dm create mode 100644 code/modules/materials/materials/gems.dm create mode 100644 code/modules/materials/materials/glass.dm create mode 100644 code/modules/materials/materials/holographic.dm create mode 100644 code/modules/materials/materials/metals/hull.dm create mode 100644 code/modules/materials/materials/metals/metals.dm create mode 100644 code/modules/materials/materials/metals/plasteel.dm create mode 100644 code/modules/materials/materials/metals/steel.dm create mode 100644 code/modules/materials/materials/organic/animal_products.dm create mode 100644 code/modules/materials/materials/organic/cloth.dm create mode 100644 code/modules/materials/materials/organic/leather.dm create mode 100644 code/modules/materials/materials/organic/resin.dm create mode 100644 code/modules/materials/materials/organic/wood.dm create mode 100644 code/modules/materials/materials/plastic.dm create mode 100644 code/modules/materials/materials/snow.dm create mode 100644 code/modules/materials/materials/stone.dm create mode 100644 code/modules/materials/materials/supermatter.dm create mode 100644 code/modules/materials/sheets/_sheets.dm create mode 100644 code/modules/materials/sheets/gems.dm create mode 100644 code/modules/materials/sheets/glass.dm create mode 100644 code/modules/materials/sheets/metals/hull.dm create mode 100644 code/modules/materials/sheets/metals/metal.dm rename code/{game/objects/items/stacks => modules/materials/sheets/metals}/rods.dm (96%) create mode 100644 code/modules/materials/sheets/organic/animal_products.dm create mode 100644 code/modules/materials/sheets/organic/resin.dm create mode 100644 code/modules/materials/sheets/organic/tanning/hide.dm create mode 100644 code/modules/materials/sheets/organic/tanning/hide_hairless.dm create mode 100644 code/modules/materials/sheets/organic/tanning/leather_wet.dm create mode 100644 code/modules/materials/sheets/organic/tanning/tanning_rack.dm create mode 100644 code/modules/materials/sheets/organic/textiles.dm create mode 100644 code/modules/materials/sheets/organic/wood.dm create mode 100644 code/modules/materials/sheets/plastic.dm create mode 100644 code/modules/materials/sheets/snow.dm create mode 100644 code/modules/materials/sheets/stone.dm create mode 100644 code/modules/materials/sheets/supermatter.dm rename code/modules/mining/{ => machinery}/machine_input_output_plates.dm (90%) rename code/modules/mining/{ => machinery}/machine_processing.dm (100%) rename code/modules/mining/{ => machinery}/machine_stacking.dm (100%) rename code/modules/mining/{ => machinery}/machine_unloading.dm (100%) diff --git a/code/__defines/materials.dm b/code/__defines/materials.dm new file mode 100644 index 00000000000..499c974b475 --- /dev/null +++ b/code/__defines/materials.dm @@ -0,0 +1,63 @@ +#define DEFAULT_TABLE_MATERIAL "plastic" +#define DEFAULT_WALL_MATERIAL "steel" + +#define MAT_IRON "iron" +#define MAT_MARBLE "marble" +#define MAT_STEEL "steel" +#define MAT_PLASTIC "plastic" +#define MAT_GLASS "glass" +#define MAT_SILVER "silver" +#define MAT_GOLD "gold" +#define MAT_URANIUM "uranium" +#define MAT_TITANIUM "titanium" +#define MAT_PHORON "phoron" +#define MAT_DIAMOND "diamond" +#define MAT_SNOW "snow" +#define MAT_SNOWBRICK "packed snow" +#define MAT_WOOD "wood" +#define MAT_LOG "log" +#define MAT_SIFWOOD "alien wood" +#define MAT_SIFLOG "alien log" +#define MAT_STEELHULL "steel hull" +#define MAT_PLASTEEL "plasteel" +#define MAT_PLASTEELHULL "plasteel hull" +#define MAT_DURASTEEL "durasteel" +#define MAT_DURASTEELHULL "durasteel hull" +#define MAT_TITANIUMHULL "titanium hull" +#define MAT_VERDANTIUM "verdantium" +#define MAT_MORPHIUM "morphium" +#define MAT_MORPHIUMHULL "morphium hull" +#define MAT_VALHOLLIDE "valhollide" +#define MAT_LEAD "lead" +#define MAT_SUPERMATTER "supermatter" +#define MAT_METALHYDROGEN "mhydrogen" +#define MAT_OSMIUM "osmium" +#define MAT_GRAPHITE "graphite" +#define MAT_LEATHER "leather" +#define MAT_CHITIN "chitin" +#define MAT_CLOTH "cloth" +#define MAT_SYNCLOTH "syncloth" +#define MAT_COPPER "copper" +#define MAT_QUARTZ "quartz" +#define MAT_TIN "tin" +#define MAT_VOPAL "void opal" +#define MAT_ALUMINIUM "aluminium" +#define MAT_BRONZE "bronze" +#define MAT_PAINITE "painite" +#define MAT_BOROSILICATE "borosilicate glass" +#define MAT_SANDSTONE "sandstone" + +#define SHARD_SHARD "shard" +#define SHARD_SHRAPNEL "shrapnel" +#define SHARD_STONE_PIECE "piece" +#define SHARD_SPLINTER "splinters" +#define SHARD_NONE "" + +#define MATERIAL_UNMELTABLE 0x1 +#define MATERIAL_BRITTLE 0x2 +#define MATERIAL_PADDING 0x4 + +#define DEFAULT_TABLE_MATERIAL "plastic" +#define DEFAULT_WALL_MATERIAL "steel" + +#define TABLE_BRITTLE_MATERIAL_MULTIPLIER 4 // Amount table damage is multiplied by if it is made of a brittle material (e.g. glass) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index e9e7126dbe6..e8dae65409e 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -121,65 +121,6 @@ #define WALL_CAN_OPEN 1 #define WALL_OPENING 2 -#define DEFAULT_TABLE_MATERIAL "plastic" -#define DEFAULT_WALL_MATERIAL "steel" - -#define MAT_IRON "iron" -#define MAT_MARBLE "marble" -#define MAT_STEEL "steel" -#define MAT_PLASTIC "plastic" -#define MAT_GLASS "glass" -#define MAT_SILVER "silver" -#define MAT_GOLD "gold" -#define MAT_URANIUM "uranium" //Did it -#define MAT_TITANIUM "titanium" -#define MAT_PHORON "phoron" -#define MAT_DIAMOND "diamond" -#define MAT_SNOW "snow" -#define MAT_WOOD "wood" -#define MAT_LOG "log" -#define MAT_SIFWOOD "alien wood" -#define MAT_SIFLOG "alien log" -#define MAT_STEELHULL "steel hull" -#define MAT_PLASTEEL "plasteel" -#define MAT_PLASTEELHULL "plasteel hull" -#define MAT_DURASTEEL "durasteel" -#define MAT_DURASTEELHULL "durasteel hull" -#define MAT_TITANIUMHULL "titanium hull" -#define MAT_VERDANTIUM "verdantium" -#define MAT_MORPHIUM "morphium" -#define MAT_MORPHIUMHULL "morphium hull" -#define MAT_VALHOLLIDE "valhollide" -#define MAT_LEAD "lead" -#define MAT_SUPERMATTER "supermatter" -#define MAT_METALHYDROGEN "mhydrogen" -#define MAT_OSMIUM "osmium" -#define MAT_GRAPHITE "graphite" -#define MAT_LEATHER "leather" -#define MAT_CHITIN "chitin" -#define MAT_CLOTH "cloth" -#define MAT_SYNCLOTH "syncloth" -#define MAT_COPPER "copper" -#define MAT_QUARTZ "quartz" -#define MAT_TIN "tin" -#define MAT_VOPAL "void opal" -#define MAT_ALUMINIUM "aluminium" -#define MAT_BRONZE "bronze" -#define MAT_PAINITE "painite" -#define MAT_BOROSILICATE "borosilicate glass" - -#define SHARD_SHARD "shard" -#define SHARD_SHRAPNEL "shrapnel" -#define SHARD_STONE_PIECE "piece" -#define SHARD_SPLINTER "splinters" -#define SHARD_NONE "" - -#define MATERIAL_UNMELTABLE 0x1 -#define MATERIAL_BRITTLE 0x2 -#define MATERIAL_PADDING 0x4 - -#define TABLE_BRITTLE_MATERIAL_MULTIPLIER 4 // Amount table damage is multiplied by if it is made of a brittle material (e.g. glass) - #define BOMBCAP_DVSTN_RADIUS (max_explosion_range/4) #define BOMBCAP_HEAVY_RADIUS (max_explosion_range/2) #define BOMBCAP_LIGHT_RADIUS max_explosion_range diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm deleted file mode 100644 index 58107d9d0b4..00000000000 --- a/code/game/machinery/vending.dm +++ /dev/null @@ -1,720 +0,0 @@ -/// -/// A vending machine -/// - -// -// ALL THE VENDING MACHINES ARE IN vending_machines.dm now! -// - -/obj/machinery/vending - name = "Vendomat" - desc = "A generic vending machine." - icon = 'icons/obj/vending.dmi' - icon_state = "generic" - anchored = 1 - density = 1 - clicksound = "button" - - // Power - use_power = USE_POWER_IDLE - idle_power_usage = 10 - var/vend_power_usage = 150 //actuators and stuff - - // Vending-related - var/active = 1 //No sales pitches if off! - var/vend_ready = 1 //Are we ready to vend?? Is it time?? - var/vend_delay = 10 //How long does it take to vend? - var/categories = CAT_NORMAL // Bitmask of cats we're currently showing - var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now - var/vending_sound = "machines/vending/vending_drop.ogg" - - /* - Variables used to initialize the product list - These are used for initialization only, and so are optional if - product_records is specified - */ - var/list/products = list() // For each, use the following pattern: - var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2) - var/list/premium = list() // No specified amount = only one in stock - var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price. - - // List of vending_product items available. - var/list/product_records = list() - - - // Variables used to initialize advertising - var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons - var/product_ads = "" //String of small ad messages in the vending screen - - var/list/ads_list = list() - - // Stuff relating vocalizations - var/list/slogan_list = list() - var/shut_up = 1 //Stop spouting those godawful pitches! - var/vend_reply //Thank you for shopping! - var/last_reply = 0 - var/last_slogan = 0 //When did we last pitch? - var/slogan_delay = 6000 //How long until we can pitch again? - - // Things that can go wrong - emagged = 0 //Ignores if somebody doesn't have card access to that machine. - var/seconds_electrified = 0 //Shock customers like an airlock. - var/shoot_inventory = 0 //Fire items at customers! We're broken! - - var/scan_id = 1 - var/obj/item/weapon/coin/coin - var/datum/wires/vending/wires = null - - var/list/log = list() - var/req_log_access = access_cargo //default access for checking logs is cargo - var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs - var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals. - - -/obj/machinery/vending/Initialize() - . = ..() - wires = new(src) - if(product_slogans) - slogan_list += splittext(product_slogans, ";") - - // So not all machines speak at the exact same time. - // The first time this machine says something will be at slogantime + this random value, - // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. - last_slogan = world.time + rand(0, slogan_delay) - - if(product_ads) - ads_list += splittext(product_ads, ";") - - build_inventory() - power_change() - -GLOBAL_LIST_EMPTY(vending_products) -/** - * Build produdct_records from the products lists - * - * products, contraband, premium, and prices allow specifying - * products that the vending machine is to carry without manually populating - * product_records. - */ -/obj/machinery/vending/proc/build_inventory() - var/list/all_products = list( - list(products, CAT_NORMAL), - list(contraband, CAT_HIDDEN), - list(premium, CAT_COIN)) - - for(var/current_list in all_products) - var/category = current_list[2] - - for(var/entry in current_list[1]) - var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry) - - product.price = (entry in prices) ? prices[entry] : 0 - product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1 - product.category = category - - product_records.Add(product) - GLOB.vending_products[entry] = 1 - -/obj/machinery/vending/Destroy() - qdel(wires) - wires = null - qdel(coin) - coin = null - for(var/datum/stored_item/vending_product/R in product_records) - qdel(R) - product_records = null - return ..() - -/obj/machinery/vending/ex_act(severity) - switch(severity) - if(1.0) - qdel(src) - return - if(2.0) - if(prob(50)) - qdel(src) - return - if(3.0) - if(prob(25)) - spawn(0) - malfunction() - return - return - else - return - -/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user) - if(!emagged) - emagged = 1 - to_chat(user, "You short out \the [src]'s product lock.") - return 1 - -/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob) - var/obj/item/weapon/card/id/I = W.GetID() - - if(I || istype(W, /obj/item/weapon/spacecash)) - attack_hand(user) - return - else if(W.is_screwdriver()) - panel_open = !panel_open - to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") - playsound(src, W.usesound, 50, 1) - if(panel_open) - wires.Interact(user) - add_overlay("[initial(icon_state)]-panel") - else - cut_overlay("[initial(icon_state)]-panel") - - SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI - return - else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter()) - if(panel_open) - attack_hand(user) - return - else if(istype(W, /obj/item/weapon/coin) && premium.len > 0) - user.drop_item() - W.forceMove(src) - coin = W - categories |= CAT_COIN - to_chat(user, "You insert \the [W] into \the [src].") - SStgui.update_uis(src) - return - else if(W.is_wrench()) - playsound(src, W.usesound, 100, 1) - if(anchored) - user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") - else - user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") - - if(do_after(user, 20 * W.toolspeed)) - if(!src) return - to_chat(user, "You [anchored? "un" : ""]secured \the [src]!") - anchored = !anchored - return - else - - for(var/datum/stored_item/vending_product/R in product_records) - if(istype(W, R.item_path) && (W.name == R.item_name)) - stock(W, R, user) - return - ..() - -/** - * Receive payment with cashmoney. - * - * usr is the mob who gets the change. - */ -/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user) - if(currently_vending.price > cashmoney.worth) - - // This is not a status display message, since it's something the character - // themselves is meant to see BEFORE putting the money in - to_chat(usr, "[bicon(cashmoney)] That is not enough money.") - return 0 - - if(istype(cashmoney, /obj/item/weapon/spacecash)) - - visible_message("\The [usr] inserts some cash into \the [src].") - cashmoney.worth -= currently_vending.price - - if(cashmoney.worth <= 0) - usr.drop_from_inventory(cashmoney) - qdel(cashmoney) - else - cashmoney.update_icon() - - // Vending machines have no idea who paid with cash - credit_purchase("(cash)") - return 1 - -/** - * Scan a chargecard and deduct payment from it. - * - * Takes payment for whatever is the currently_vending item. Returns 1 if - * successful, 0 if failed. - */ -/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet) - visible_message("\The [usr] swipes \the [wallet] through \the [src].") - playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) - if(currently_vending.price > wallet.worth) - to_chat(usr, "Insufficient funds on chargecard.") - return 0 - else - wallet.worth -= currently_vending.price - credit_purchase("[wallet.owner_name] (chargecard)") - return 1 - -/** - * Scan a card and attempt to transfer payment from associated account. - * - * Takes payment for whatever is the currently_vending item. Returns 1 if - * successful, 0 if failed - */ -/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M) - visible_message("[M] swipes a card through [src].") - playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) - - var/datum/money_account/customer_account = get_account(I.associated_account_number) - if(!customer_account) - to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.") - return FALSE - - if(customer_account.suspended) - to_chat(M, "Unable to access account: account suspended.") - return FALSE - - // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is - // empty at high security levels - if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) - var/attempt_pin = input("Enter pin code", "Vendor transaction") as num - customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) - - if(!customer_account) - to_chat(M, "Unable to access account: incorrect credentials.") - return FALSE - - if(currently_vending.price > customer_account.money) - to_chat(M, "Insufficient funds in account.") - return FALSE - - // Okay to move the money at this point - - // debit money from the purchaser's account - customer_account.money -= currently_vending.price - - // create entry in the purchaser's account log - var/datum/transaction/T = new() - T.target_name = "[vendor_account.owner_name] (via [name])" - T.purpose = "Purchase of [currently_vending.item_name]" - if(currently_vending.price > 0) - T.amount = "([currently_vending.price])" - else - T.amount = "[currently_vending.price]" - T.source_terminal = name - T.date = current_date_string - T.time = stationtime2text() - customer_account.transaction_log.Add(T) - - // Give the vendor the money. We use the account owner name, which means - // that purchases made with stolen/borrowed card will look like the card - // owner made them - credit_purchase(customer_account.owner_name) - return 1 - -/** - * Add money for current purchase to the vendor account. - * - * Called after the money has already been taken from the customer. - */ -/obj/machinery/vending/proc/credit_purchase(var/target as text) - vendor_account.money += currently_vending.price - - var/datum/transaction/T = new() - T.target_name = target - T.purpose = "Purchase of [currently_vending.item_name]" - T.amount = "[currently_vending.price]" - T.source_terminal = name - T.date = current_date_string - T.time = stationtime2text() - vendor_account.transaction_log.Add(T) - -/obj/machinery/vending/attack_ghost(mob/user) - return attack_hand(user) - -/obj/machinery/vending/attack_ai(mob/user as mob) - return attack_hand(user) - -/obj/machinery/vending/attack_hand(mob/user as mob) - if(stat & (BROKEN|NOPOWER)) - return - - if(seconds_electrified != 0) - if(shock(user, 100)) - return - - wires.Interact(user) - tgui_interact(user) - -/obj/machinery/vending/ui_assets(mob/user) - return list( - get_asset_datum(/datum/asset/spritesheet/vending), - ) - -/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "Vending", name) - ui.open() - -/obj/machinery/vending/tgui_data(mob/user) - var/list/data = list() - var/list/listed_products = list() - - data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE - for(var/key = 1 to product_records.len) - var/datum/stored_item/vending_product/I = product_records[key] - - if(!(I.category & categories)) - continue - - listed_products.Add(list(list( - "key" = key, - "name" = I.item_name, - "price" = I.price, - "color" = I.display_color, - "isatom" = ispath(I.item_path, /atom), - "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"), - "amount" = I.get_amount() - ))) - - data["products"] = listed_products - - if(coin) - data["coin"] = coin.name - else - data["coin"] = FALSE - - if(currently_vending) - data["actively_vending"] = currently_vending.item_name - else - data["actively_vending"] = null - - if(panel_open) - data["panel"] = 1 - data["speaker"] = shut_up ? 0 : 1 - else - data["panel"] = 0 - - var/mob/living/carbon/human/H - var/obj/item/weapon/card/id/C - - data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash."; - data["userMoney"] = 0 - data["user"] = null - if(ishuman(user)) - H = user - C = H.GetIdCard() - var/obj/item/weapon/spacecash/S = H.get_active_hand() - if(istype(S)) - data["userMoney"] = S.worth - data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]₮." - else if(istype(C)) - var/datum/money_account/A = get_account(C.associated_account_number) - if(istype(A)) - data["user"] = list() - data["user"]["name"] = A.owner_name - data["userMoney"] = A.money - data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job" - else - data["guestNotice"] = "Unlinked ID detected. Present cash to pay."; - - return data - -/obj/machinery/vending/tgui_act(action, params) - if(stat & (BROKEN|NOPOWER)) - return - if(usr.stat || usr.restrained()) - return - if(..()) - return TRUE - - . = TRUE - switch(action) - if("remove_coin") - if(issilicon(usr)) - return FALSE - - if(!coin) - to_chat(usr, "There is no coin in this machine.") - return - - coin.forceMove(src.loc) - if(!usr.get_active_hand()) - usr.put_in_hands(coin) - - to_chat(usr, "You remove \the [coin] from \the [src].") - coin = null - categories &= ~CAT_COIN - return TRUE - if("vend") - if(!vend_ready) - to_chat(usr, "[src] is busy!") - return - if(!allowed(usr) && !emagged && scan_id) - to_chat(usr, "Access denied.") //Unless emagged of course - flick("[icon_state]-deny",src) - playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) - return - if(panel_open) - to_chat(usr, "[src] cannot dispense products while its service panel is open!") - return - - var/key = text2num(params["vend"]) - var/datum/stored_item/vending_product/R = product_records[key] - - // This should not happen unless the request from NanoUI was bad - if(!(R.category & categories)) - return - - if(!can_buy(R, usr)) - return - if(R.price <= 0) - vend(R, usr) - add_fingerprint(usr) - return TRUE - - if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something. - to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.") - return - if(!ishuman(usr)) - return - - - vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved. - - var/mob/living/carbon/human/H = usr - var/obj/item/weapon/card/id/C = H.GetIdCard() - - if(!vendor_account || vendor_account.suspended) - to_chat(usr, "Vendor account offline. Unable to process transaction.") - flick("[icon_state]-deny",src) - vend_ready = TRUE - return - - currently_vending = R - - var/paid = FALSE - - if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash)) - var/obj/item/weapon/spacecash/cash = usr.get_active_hand() - paid = pay_with_cash(cash, usr) - else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet)) - var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand() - paid = pay_with_ewallet(wallet) - else if(istype(C, /obj/item/weapon/card)) - paid = pay_with_card(C, usr) - /*else if(usr.can_advanced_admin_interact()) - to_chat(usr, "Vending object due to admin interaction.") - paid = TRUE*/ - else - to_chat(usr, "Payment failure: you have no ID or other method of payment.") - vend_ready = TRUE - flick("[icon_state]-deny",src) - return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update. - if(paid) - vend(currently_vending, usr) // vend will handle vend_ready - . = TRUE - else - to_chat(usr, "Payment failure: unable to process payment.") - vend_ready = TRUE - - if("togglevoice") - if(!panel_open) - return FALSE - shut_up = !shut_up - -/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user) - if(!allowed(user) && !emagged && scan_id) - to_chat(user, "Access denied.") //Unless emagged of course - flick("[icon_state]-deny",src) - playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) - return FALSE - return TRUE - -/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user) - if(!can_buy(R, user)) - return - - if(!R.amount) - to_chat(user, "[src] has ran out of that product.") - vend_ready = TRUE - return - - vend_ready = FALSE //One thing at a time!! - SStgui.update_uis(src) - - if(R.category & CAT_COIN) - if(!coin) - to_chat(user, "You need to insert a coin to get this item.") - return - if(coin.string_attached) - if(prob(50)) - to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.") - else - to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.") - qdel(coin) - coin = null - categories &= ~CAT_COIN - else - qdel(coin) - coin = null - categories &= ~CAT_COIN - - if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply) - spawn(0) - speak(vend_reply) - last_reply = world.time - - use_power(vend_power_usage) //actuators and stuff - flick("[icon_state]-vend",src) - addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay) - -/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user) - R.get_product(get_turf(src)) - if(has_logs) - do_logging(R, user, 1) - if(prob(1)) - sleep(3) - if(R.get_product(get_turf(src))) - visible_message("\The [src] clunks as it vends an additional item.") - playsound(src, "sound/[vending_sound]", 100, 1, 1) - - vend_ready = 1 - currently_vending = null - SStgui.update_uis(src) - GLOB.items_sold_shift_roundstat++ - -/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0) - if(user.GetIdCard()) - var/obj/item/weapon/card/id/tempid = user.GetIdCard() - var/list/list_item = list() - if(vending) - list_item += "vend" - else - list_item += "stock" - list_item += tempid.registered_name - list_item += stationtime2text() - list_item += R.item_name - log[++log.len] = list_item - -/obj/machinery/vending/proc/show_log(mob/user as mob) - if(user.GetIdCard()) - var/obj/item/weapon/card/id/tempid = user.GetIdCard() - if(req_log_access in tempid.GetAccess()) - var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500) - var/dat = "" - dat += "
[name] Vending Log
" - dat += "
Welcome [user.name]!

" - dat += "Below are the recent vending logs for your vending machine.
" - for(var/i in log) - dat += json_encode(i) - dat += ";
" - popup.set_content(dat) - popup.open() - else - to_chat(user,"You do not have the required access to view the vending logs for this machine.") - - -/obj/machinery/vending/verb/rotate_clockwise() - set name = "Rotate Vending Machine Clockwise" - set category = "Object" - set src in oview(1) - - if (src.can_rotate == 0) - to_chat(usr, "\The [src] cannot be rotated.") - return 0 - - if (src.anchored || usr:stat) - to_chat(usr, "It is bolted down!") - return 0 - src.set_dir(turn(src.dir, 270)) - return 1 - -/obj/machinery/vending/verb/check_logs() - set name = "Check Vending Logs" - set category = "Object" - set src in oview(1) - - show_log(usr) - -/** - * Add item to the machine - * - * Checks if item is vendable in this machine should be performed before - * calling. W is the item being inserted, R is the associated vending_product entry. - */ -/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user) - if(!user.unEquip(W)) - return - - to_chat(user, "You insert \the [W] in the product receptor.") - R.add_product(W) - if(has_logs) - do_logging(R, user) - - SStgui.update_uis(src) - -/obj/machinery/vending/process() - if(stat & (BROKEN|NOPOWER)) - return - - if(!active) - return - - if(seconds_electrified > 0) - seconds_electrified-- - - //Pitch to the people! Really sell it! - if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5)) - var/slogan = pick(slogan_list) - speak(slogan) - last_slogan = world.time - - if(shoot_inventory && prob(2)) - throw_item() - - return - -/obj/machinery/vending/proc/speak(var/message) - if(stat & NOPOWER) - return - - if(!message) - return - - for(var/mob/O in hearers(src, null)) - O.show_message("\The [src] beeps, \"[message]\"",2) - return - -/obj/machinery/vending/power_change() - ..() - if(stat & BROKEN) - icon_state = "[initial(icon_state)]-broken" - else - if(!(stat & NOPOWER)) - icon_state = initial(icon_state) - else - spawn(rand(0, 15)) - icon_state = "[initial(icon_state)]-off" - -//Oh no we're malfunctioning! Dump out some product and break. -/obj/machinery/vending/proc/malfunction() - for(var/datum/stored_item/vending_product/R in product_records) - while(R.get_amount()>0) - R.get_product(loc) - break - - stat |= BROKEN - icon_state = "[initial(icon_state)]-broken" - return - -//Somebody cut an important wire and now we're following a new definition of "pitch." -/obj/machinery/vending/proc/throw_item() - var/obj/throw_item = null - var/mob/living/target = locate() in view(7,src) - if(!target) - return 0 - - for(var/datum/stored_item/vending_product/R in product_records) - throw_item = R.get_product(loc) - if(!throw_item) - continue - break - if(!throw_item) - return 0 - spawn(0) - throw_item.throw_at(target, 16, 3, src) - visible_message("\The [src] launches \a [throw_item] at \the [target]!") - return 1 - -//Actual machines are in vending_machines.dm diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm deleted file mode 100644 index c2535ec3eb8..00000000000 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ /dev/null @@ -1,102 +0,0 @@ -/* Glass stack types - * Contains: - * Glass sheets - * Reinforced glass sheets - * Phoron Glass Sheets - * Reinforced Phoron Glass Sheets (AKA Holy fuck strong windows) - * Glass shards - TODO: Move this into code/game/object/item/weapons - */ - -/* - * Glass sheets - */ -/obj/item/stack/material/glass - name = "glass" - singular_name = "glass sheet" - icon_state = "sheet-glass" - var/is_reinforced = 0 - default_type = "glass" - drop_sound = 'sound/items/drop/glass.ogg' - pickup_sound = 'sound/items/pickup/glass.ogg' - -/obj/item/stack/material/glass/attack_self(mob/user as mob) - construct_window(user) - -/obj/item/stack/material/glass/attackby(obj/item/W, mob/user) - ..() - if(!is_reinforced) - if(istype(W,/obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/CC = W - if (get_amount() < 1 || CC.get_amount() < 5) - to_chat(user, "You need five lengths of coil and one sheet of glass to make wired glass.") - return - - CC.use(5) - use(1) - to_chat(user, "You attach wire to the [name].") - new /obj/item/stack/light_w(user.loc) - else if(istype(W, /obj/item/stack/rods)) - var/obj/item/stack/rods/V = W - if (V.get_amount() < 1 || get_amount() < 1) - to_chat(user, "You need one rod and one sheet of glass to make reinforced glass.") - return - - var/obj/item/stack/material/glass/reinforced/RG = new (user.loc) - RG.add_fingerprint(user) - RG.add_to_stacks(user) - var/obj/item/stack/material/glass/G = src - src = null - var/replace = (user.get_inactive_hand()==G) - V.use(1) - G.use(1) - if (!G && replace) - user.put_in_hands(RG) - - - - -/* - * Reinforced glass sheets - */ -/obj/item/stack/material/glass/reinforced - name = "reinforced glass" - singular_name = "reinforced glass sheet" - icon_state = "sheet-rglass" - default_type = "reinforced glass" - is_reinforced = 1 - -/* - * Phoron Glass sheets - */ -/obj/item/stack/material/glass/phoronglass - name = "phoron glass" - singular_name = "phoron glass sheet" - icon_state = "sheet-phoronglass" - default_type = "phoron glass" - -/obj/item/stack/material/glass/phoronglass/attackby(obj/item/W, mob/user) - ..() - if( istype(W, /obj/item/stack/rods) ) - var/obj/item/stack/rods/V = W - var/obj/item/stack/material/glass/phoronrglass/RG = new (user.loc) - RG.add_fingerprint(user) - RG.add_to_stacks(user) - V.use(1) - var/obj/item/stack/material/glass/G = src - src = null - var/replace = (user.get_inactive_hand()==G) - G.use(1) - if (!G && !RG && replace) - user.put_in_hands(RG) - else - return ..() - -/* - * Reinforced phoron glass sheets - */ -/obj/item/stack/material/glass/phoronrglass - name = "reinforced phoron glass" - singular_name = "reinforced phoron glass sheet" - icon_state = "sheet-phoronrglass" - default_type = "reinforced phoron glass" - is_reinforced = 1 diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm deleted file mode 100644 index c48f57e693a..00000000000 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ /dev/null @@ -1,286 +0,0 @@ -/obj/item/stack/animalhide - name = "hide" - desc = "The hide of some creature." - description_info = "Use something sharp, like a knife, to scrape the hairs/feathers/etc off this hide to prepare it for tanning." - icon_state = "sheet-hide" - drop_sound = 'sound/items/drop/cloth.ogg' - pickup_sound = 'sound/items/pickup/cloth.ogg' - amount = 1 - max_amount = 20 - stacktype = "hide" - no_variants = TRUE -// This needs to be very clearly documented for players. Whether it should stay in the main description is up for debate. -/obj/item/stack/animalhide/examine(var/mob/user) - . = ..() - . += description_info - -/obj/item/stack/animalhide/human - name = "skin" - desc = "The by-product of sapient farming." - singular_name = "skin piece" - icon_state = "sheet-hide" - no_variants = FALSE - drop_sound = 'sound/items/drop/leather.ogg' - pickup_sound = 'sound/items/pickup/leather.ogg' - stacktype = "hide-human" - -/obj/item/stack/animalhide/corgi - name = "corgi hide" - desc = "The by-product of corgi farming." - singular_name = "corgi hide piece" - icon_state = "sheet-corgi" - stacktype = "hide-corgi" - -/obj/item/stack/animalhide/cat - name = "cat hide" - desc = "The by-product of cat farming." - singular_name = "cat hide piece" - icon_state = "sheet-cat" - stacktype = "hide-cat" - -/obj/item/stack/animalhide/monkey - name = "monkey hide" - desc = "The by-product of monkey farming." - singular_name = "monkey hide piece" - icon_state = "sheet-monkey" - stacktype = "hide-monkey" - -/obj/item/stack/animalhide/lizard - name = "lizard skin" - desc = "Sssssss..." - singular_name = "lizard skin piece" - icon_state = "sheet-lizard" - stacktype = "hide-lizard" - -/obj/item/stack/animalhide/xeno - name = "alien hide" - desc = "The skin of a terrible creature." - singular_name = "alien hide piece" - icon_state = "sheet-xeno" - stacktype = "hide-xeno" - -//don't see anywhere else to put these, maybe together they could be used to make the xenos suit? -/obj/item/stack/xenochitin - name = "alien chitin" - desc = "A piece of the hide of a terrible creature." - singular_name = "alien chitin piece" - icon = 'icons/mob/alien.dmi' - icon_state = "chitin" - stacktype = "hide-chitin" - -/obj/item/xenos_claw - name = "alien claw" - desc = "The claw of a terrible creature." - icon = 'icons/mob/alien.dmi' - icon_state = "claw" - -/obj/item/weed_extract - name = "weed extract" - desc = "A piece of slimy, purplish weed." - icon = 'icons/mob/alien.dmi' - icon_state = "weed_extract" - -//Step one - dehairing. -/obj/item/stack/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob) - if(has_edge(W) || is_sharp(W)) - //visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message) - user.visible_message("\The [user] starts cutting hair off \the [src]", "You start cutting the hair off \the [src]", "You hear the sound of a knife rubbing against flesh") - var/scraped = 0 - while(amount > 0 && do_after(user, 2.5 SECONDS)) // 2.5s per hide - //Try locating an exisitng stack on the tile and add to there if possible - var/obj/item/stack/hairlesshide/H = null - for(var/obj/item/stack/hairlesshide/HS in user.loc) // Could be scraping something inside a locker, hence the .loc, not get_turf - if(HS.amount < HS.max_amount) - H = HS - break - - // Either we found a valid stack, in which case increment amount, - // Or we need to make a new stack - if(istype(H)) - H.amount++ - else - H = new /obj/item/stack/hairlesshide(user.loc) - - // Increment the amount - src.use(1) - scraped++ - - if(scraped) - to_chat(user, SPAN_NOTICE("You scrape the hair off [scraped] hide\s.")) - else - ..() - - -//Step two - washing..... it's actually in washing machine code, and ere. - -/obj/item/stack/hairlesshide - name = "hairless hide" - desc = "This hide was stripped of it's hair, but still needs tanning." - description_info = "Get it wet to continue tanning this into leather.
\ - You could set it in a river, wash it with a sink, or just splash water on it with a bucket." - singular_name = "hairless hide piece" - icon_state = "sheet-hairlesshide" - no_variants = FALSE - max_amount = 20 - stacktype = "hairlesshide" - -/obj/item/stack/hairlesshide/examine(var/mob/user) - . = ..() - . += description_info - -/obj/item/stack/hairlesshide/water_act(var/wateramount) - . = ..() - wateramount = min(amount, round(wateramount)) - for(var/i in 1 to wateramount) - var/obj/item/stack/wetleather/H = null - for(var/obj/item/stack/wetleather/HS in get_turf(src)) // Doesn't have a user, can't just use their loc - if(HS.amount < HS.max_amount) - H = HS - break - - // Either we found a valid stack, in which case increment amount, - // Or we need to make a new stack - if(istype(H)) - H.amount++ - else - H = new /obj/item/stack/wetleather(get_turf(src)) - - // Increment the amount - src.use(1) - -/obj/item/stack/hairlesshide/proc/rapidcure(var/stacknum = 1) - stacknum = min(stacknum, amount) - - while(stacknum) - var/obj/item/stack/wetleather/I = new /obj/item/stack/wetleather(get_turf(src)) - - if(istype(I)) - I.dry() - - use(1) - stacknum -= 1 - -//Step three - drying -/obj/item/stack/wetleather - name = "wet leather" - desc = "This leather has been cleaned but still needs to be dried." - description_info = "To finish tanning the leather, you need to dry it. \ - You could place it under a fire, \ - put it in a drying rack, \ - or build a tanning rack from steel or wooden boards." - singular_name = "wet leather piece" - icon_state = "sheet-wetleather" - var/wetness = 30 //Reduced when exposed to high temperautres - var/drying_threshold_temperature = 500 //Kelvin to start drying - no_variants = FALSE - max_amount = 20 - stacktype = "wetleather" - - var/dry_type = /obj/item/stack/material/leather - -/obj/item/stack/wetleather/examine(var/mob/user) - . = ..() - . += description_info - . += "\The [src] is [get_dryness_text()]." - -/obj/item/stack/wetleather/proc/get_dryness_text() - if(wetness > 20) - return "wet" - if(wetness > 10) - return "damp" - if(wetness) - return "almost dry" - return "dry" - -/obj/item/stack/wetleather/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) - ..() - if(exposed_temperature >= drying_threshold_temperature) - wetness-- - if(wetness == 0) - dry() - -/obj/item/stack/wetleather/proc/dry() - var/obj/item/stack/material/leather/L = new(src.loc) - L.amount = amount - use(amount) - return L - -/obj/item/stack/wetleather/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified) - . = ..() - if(.) // If it transfers any, do a weighted average of the wetness - var/obj/item/stack/wetleather/W = S - var/oldamt = W.amount - . - W.wetness = round(((oldamt * W.wetness) + (. * wetness)) / W.amount) - - - -/obj/structure/tanning_rack - name = "tanning rack" - desc = "A rack used to stretch leather out and hold it taut during the tanning process." - icon = 'icons/obj/kitchen.dmi' - icon_state = "spike" - - var/obj/item/stack/wetleather/drying = null - -/obj/structure/tanning_rack/Initialize() - . = ..() - START_PROCESSING(SSobj, src) // SSObj fires ~every 2s , starting from wetness 30 takes ~1m - -/obj/structure/tanning_rack/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - -/obj/structure/tanning_rack/process() - if(drying && drying.wetness) - drying.wetness = max(drying.wetness - 1, 0) - if(!drying.wetness) - visible_message("The [drying] is dry!") - update_icon() - -/obj/structure/tanning_rack/examine(var/mob/user) - . = ..() - if(drying) - . += "\The [drying] is [drying.get_dryness_text()]." - -/obj/structure/tanning_rack/update_icon() - overlays.Cut() - if(drying) - var/image/I - if(drying.wetness) - I = image(icon, "leather_wet") - else - I = image(icon, "leather_dry") - add_overlay(I) - -/obj/structure/tanning_rack/attackby(var/atom/A, var/mob/user) - if(istype(A, /obj/item/stack/wetleather)) - if(!drying) // If not drying anything, start drying the thing - if(user.unEquip(A, target = src)) - drying = A - else // Drying something, add if possible - var/obj/item/stack/wetleather/W = A - W.transfer_to(drying, W.amount, TRUE) - update_icon() - return TRUE - return ..() - -/obj/structure/tanning_rack/attack_hand(var/mob/user) - if(drying) - var/obj/item/stack/S = drying - if(!drying.wetness) // If it's dry, make a stack of dry leather and prepare to put that in their hands - var/obj/item/stack/material/leather/L = new(src) - L.amount = drying.amount - drying.use(drying.amount) - S = L - - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(!H.put_in_any_hand_if_possible(S)) - S.forceMove(get_turf(src)) - else - S.forceMove(get_turf(src)) - drying = null - update_icon() - -/obj/structure/tanning_rack/attack_robot(var/mob/user) - attack_hand(user) // That has checks to \ No newline at end of file diff --git a/code/modules/mining/coins.dm b/code/modules/economy/coins.dm similarity index 100% rename from code/modules/mining/coins.dm rename to code/modules/economy/coins.dm diff --git a/code/modules/mining/mint.dm b/code/modules/economy/mint.dm similarity index 100% rename from code/modules/mining/mint.dm rename to code/modules/economy/mint.dm diff --git a/code/modules/mining/money_bag.dm b/code/modules/economy/money_bag.dm similarity index 95% rename from code/modules/mining/money_bag.dm rename to code/modules/economy/money_bag.dm index fd1cb561b0e..3e85d62e460 100644 --- a/code/modules/mining/money_bag.dm +++ b/code/modules/economy/money_bag.dm @@ -1,98 +1,98 @@ -/*****************************Money bag********************************/ - -/obj/item/weapon/moneybag - icon = 'icons/obj/storage.dmi' - name = "Money bag" - icon_state = "moneybag" - force = 10.0 - throwforce = 2.0 - w_class = ITEMSIZE_LARGE - -/obj/item/weapon/moneybag/attack_hand(user as mob) - var/amt_gold = 0 - var/amt_silver = 0 - var/amt_diamond = 0 - var/amt_iron = 0 - var/amt_phoron = 0 - var/amt_uranium = 0 - - for (var/obj/item/weapon/coin/C in contents) - if (istype(C,/obj/item/weapon/coin/diamond)) - amt_diamond++; - if (istype(C,/obj/item/weapon/coin/phoron)) - amt_phoron++; - if (istype(C,/obj/item/weapon/coin/iron)) - amt_iron++; - if (istype(C,/obj/item/weapon/coin/silver)) - amt_silver++; - if (istype(C,/obj/item/weapon/coin/gold)) - amt_gold++; - if (istype(C,/obj/item/weapon/coin/uranium)) - amt_uranium++; - - var/dat = text("The contents of the moneybag reveal...
") - if (amt_gold) - dat += text("Gold coins: [amt_gold] Remove one
") - if (amt_silver) - dat += text("Silver coins: [amt_silver] Remove one
") - if (amt_iron) - dat += text("Metal coins: [amt_iron] Remove one
") - if (amt_diamond) - dat += text("Diamond coins: [amt_diamond] Remove one
") - if (amt_phoron) - dat += text("Phoron coins: [amt_phoron] Remove one
") - if (amt_uranium) - dat += text("Uranium coins: [amt_uranium] Remove one
") - user << browse("[dat]", "window=moneybag") - -/obj/item/weapon/moneybag/attackby(obj/item/weapon/W as obj, mob/user as mob) - ..() - if (istype(W, /obj/item/weapon/coin)) - var/obj/item/weapon/coin/C = W - to_chat(user, "You add the [C.name] into the bag.") - usr.drop_item() - contents += C - if (istype(W, /obj/item/weapon/moneybag)) - var/obj/item/weapon/moneybag/C = W - for (var/obj/O in C.contents) - contents += O; - to_chat(user, "You empty the [C.name] into the bag.") - return - -/obj/item/weapon/moneybag/Topic(href, href_list) - if(..()) - return 1 - usr.set_machine(src) - src.add_fingerprint(usr) - if(href_list["remove"]) - var/obj/item/weapon/coin/COIN - switch(href_list["remove"]) - if("gold") - COIN = locate(/obj/item/weapon/coin/gold,src.contents) - if("silver") - COIN = locate(/obj/item/weapon/coin/silver,src.contents) - if("iron") - COIN = locate(/obj/item/weapon/coin/iron,src.contents) - if("diamond") - COIN = locate(/obj/item/weapon/coin/diamond,src.contents) - if("phoron") - COIN = locate(/obj/item/weapon/coin/phoron,src.contents) - if("uranium") - COIN = locate(/obj/item/weapon/coin/uranium,src.contents) - if(!COIN) - return - COIN.loc = src.loc - return - - - -/obj/item/weapon/moneybag/vault - -/obj/item/weapon/moneybag/vault/New() - ..() - new /obj/item/weapon/coin/silver(src) - new /obj/item/weapon/coin/silver(src) - new /obj/item/weapon/coin/silver(src) - new /obj/item/weapon/coin/silver(src) - new /obj/item/weapon/coin/gold(src) +/*****************************Money bag********************************/ + +/obj/item/weapon/moneybag + icon = 'icons/obj/storage.dmi' + name = "Money bag" + icon_state = "moneybag" + force = 10.0 + throwforce = 2.0 + w_class = ITEMSIZE_LARGE + +/obj/item/weapon/moneybag/attack_hand(user as mob) + var/amt_gold = 0 + var/amt_silver = 0 + var/amt_diamond = 0 + var/amt_iron = 0 + var/amt_phoron = 0 + var/amt_uranium = 0 + + for (var/obj/item/weapon/coin/C in contents) + if (istype(C,/obj/item/weapon/coin/diamond)) + amt_diamond++; + if (istype(C,/obj/item/weapon/coin/phoron)) + amt_phoron++; + if (istype(C,/obj/item/weapon/coin/iron)) + amt_iron++; + if (istype(C,/obj/item/weapon/coin/silver)) + amt_silver++; + if (istype(C,/obj/item/weapon/coin/gold)) + amt_gold++; + if (istype(C,/obj/item/weapon/coin/uranium)) + amt_uranium++; + + var/dat = text("The contents of the moneybag reveal...
") + if (amt_gold) + dat += text("Gold coins: [amt_gold] Remove one
") + if (amt_silver) + dat += text("Silver coins: [amt_silver] Remove one
") + if (amt_iron) + dat += text("Metal coins: [amt_iron] Remove one
") + if (amt_diamond) + dat += text("Diamond coins: [amt_diamond] Remove one
") + if (amt_phoron) + dat += text("Phoron coins: [amt_phoron] Remove one
") + if (amt_uranium) + dat += text("Uranium coins: [amt_uranium] Remove one
") + user << browse("[dat]", "window=moneybag") + +/obj/item/weapon/moneybag/attackby(obj/item/weapon/W as obj, mob/user as mob) + ..() + if (istype(W, /obj/item/weapon/coin)) + var/obj/item/weapon/coin/C = W + to_chat(user, "You add the [C.name] into the bag.") + usr.drop_item() + contents += C + if (istype(W, /obj/item/weapon/moneybag)) + var/obj/item/weapon/moneybag/C = W + for (var/obj/O in C.contents) + contents += O; + to_chat(user, "You empty the [C.name] into the bag.") + return + +/obj/item/weapon/moneybag/Topic(href, href_list) + if(..()) + return 1 + usr.set_machine(src) + src.add_fingerprint(usr) + if(href_list["remove"]) + var/obj/item/weapon/coin/COIN + switch(href_list["remove"]) + if("gold") + COIN = locate(/obj/item/weapon/coin/gold,src.contents) + if("silver") + COIN = locate(/obj/item/weapon/coin/silver,src.contents) + if("iron") + COIN = locate(/obj/item/weapon/coin/iron,src.contents) + if("diamond") + COIN = locate(/obj/item/weapon/coin/diamond,src.contents) + if("phoron") + COIN = locate(/obj/item/weapon/coin/phoron,src.contents) + if("uranium") + COIN = locate(/obj/item/weapon/coin/uranium,src.contents) + if(!COIN) + return + COIN.loc = src.loc + return + + + +/obj/item/weapon/moneybag/vault + +/obj/item/weapon/moneybag/vault/New() + ..() + new /obj/item/weapon/coin/silver(src) + new /obj/item/weapon/coin/silver(src) + new /obj/item/weapon/coin/silver(src) + new /obj/item/weapon/coin/silver(src) + new /obj/item/weapon/coin/gold(src) new /obj/item/weapon/coin/gold(src) \ No newline at end of file diff --git a/code/modules/economy/vending.dm b/code/modules/economy/vending.dm new file mode 100644 index 00000000000..f48afa07797 --- /dev/null +++ b/code/modules/economy/vending.dm @@ -0,0 +1,1445 @@ +<<<<<<< HEAD:code/game/machinery/vending.dm +/// +/// A vending machine +/// + +// +// ALL THE VENDING MACHINES ARE IN vending_machines.dm now! +// + +/obj/machinery/vending + name = "Vendomat" + desc = "A generic vending machine." + icon = 'icons/obj/vending.dmi' + icon_state = "generic" + anchored = 1 + density = 1 + clicksound = "button" + + // Power + use_power = USE_POWER_IDLE + idle_power_usage = 10 + var/vend_power_usage = 150 //actuators and stuff + + // Vending-related + var/active = 1 //No sales pitches if off! + var/vend_ready = 1 //Are we ready to vend?? Is it time?? + var/vend_delay = 10 //How long does it take to vend? + var/categories = CAT_NORMAL // Bitmask of cats we're currently showing + var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now + var/vending_sound = "machines/vending/vending_drop.ogg" + + /* + Variables used to initialize the product list + These are used for initialization only, and so are optional if + product_records is specified + */ + var/list/products = list() // For each, use the following pattern: + var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2) + var/list/premium = list() // No specified amount = only one in stock + var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price. + + // List of vending_product items available. + var/list/product_records = list() + + + // Variables used to initialize advertising + var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons + var/product_ads = "" //String of small ad messages in the vending screen + + var/list/ads_list = list() + + // Stuff relating vocalizations + var/list/slogan_list = list() + var/shut_up = 1 //Stop spouting those godawful pitches! + var/vend_reply //Thank you for shopping! + var/last_reply = 0 + var/last_slogan = 0 //When did we last pitch? + var/slogan_delay = 6000 //How long until we can pitch again? + + // Things that can go wrong + emagged = 0 //Ignores if somebody doesn't have card access to that machine. + var/seconds_electrified = 0 //Shock customers like an airlock. + var/shoot_inventory = 0 //Fire items at customers! We're broken! + + var/scan_id = 1 + var/obj/item/weapon/coin/coin + var/datum/wires/vending/wires = null + + var/list/log = list() + var/req_log_access = access_cargo //default access for checking logs is cargo + var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs + var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals. + + +/obj/machinery/vending/Initialize() + . = ..() + wires = new(src) + if(product_slogans) + slogan_list += splittext(product_slogans, ";") + + // So not all machines speak at the exact same time. + // The first time this machine says something will be at slogantime + this random value, + // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. + last_slogan = world.time + rand(0, slogan_delay) + + if(product_ads) + ads_list += splittext(product_ads, ";") + + build_inventory() + power_change() + +GLOBAL_LIST_EMPTY(vending_products) +/** + * Build produdct_records from the products lists + * + * products, contraband, premium, and prices allow specifying + * products that the vending machine is to carry without manually populating + * product_records. + */ +/obj/machinery/vending/proc/build_inventory() + var/list/all_products = list( + list(products, CAT_NORMAL), + list(contraband, CAT_HIDDEN), + list(premium, CAT_COIN)) + + for(var/current_list in all_products) + var/category = current_list[2] + + for(var/entry in current_list[1]) + var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry) + + product.price = (entry in prices) ? prices[entry] : 0 + product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1 + product.category = category + + product_records.Add(product) + GLOB.vending_products[entry] = 1 + +/obj/machinery/vending/Destroy() + qdel(wires) + wires = null + qdel(coin) + coin = null + for(var/datum/stored_item/vending_product/R in product_records) + qdel(R) + product_records = null + return ..() + +/obj/machinery/vending/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if(prob(50)) + qdel(src) + return + if(3.0) + if(prob(25)) + spawn(0) + malfunction() + return + return + else + return + +/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + emagged = 1 + to_chat(user, "You short out \the [src]'s product lock.") + return 1 + +/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob) + var/obj/item/weapon/card/id/I = W.GetID() + + if(I || istype(W, /obj/item/weapon/spacecash)) + attack_hand(user) + return + else if(W.is_screwdriver()) + panel_open = !panel_open + to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") + playsound(src, W.usesound, 50, 1) + if(panel_open) + wires.Interact(user) + add_overlay("[initial(icon_state)]-panel") + else + cut_overlay("[initial(icon_state)]-panel") + + SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI + return + else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter()) + if(panel_open) + attack_hand(user) + return + else if(istype(W, /obj/item/weapon/coin) && premium.len > 0) + user.drop_item() + W.forceMove(src) + coin = W + categories |= CAT_COIN + to_chat(user, "You insert \the [W] into \the [src].") + SStgui.update_uis(src) + return + else if(W.is_wrench()) + playsound(src, W.usesound, 100, 1) + if(anchored) + user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") + else + user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") + + if(do_after(user, 20 * W.toolspeed)) + if(!src) return + to_chat(user, "You [anchored? "un" : ""]secured \the [src]!") + anchored = !anchored + return + else + + for(var/datum/stored_item/vending_product/R in product_records) + if(istype(W, R.item_path) && (W.name == R.item_name)) + stock(W, R, user) + return + ..() + +/** + * Receive payment with cashmoney. + * + * usr is the mob who gets the change. + */ +/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user) + if(currently_vending.price > cashmoney.worth) + + // This is not a status display message, since it's something the character + // themselves is meant to see BEFORE putting the money in + to_chat(usr, "[bicon(cashmoney)] That is not enough money.") + return 0 + + if(istype(cashmoney, /obj/item/weapon/spacecash)) + + visible_message("\The [usr] inserts some cash into \the [src].") + cashmoney.worth -= currently_vending.price + + if(cashmoney.worth <= 0) + usr.drop_from_inventory(cashmoney) + qdel(cashmoney) + else + cashmoney.update_icon() + + // Vending machines have no idea who paid with cash + credit_purchase("(cash)") + return 1 + +/** + * Scan a chargecard and deduct payment from it. + * + * Takes payment for whatever is the currently_vending item. Returns 1 if + * successful, 0 if failed. + */ +/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet) + visible_message("\The [usr] swipes \the [wallet] through \the [src].") + playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) + if(currently_vending.price > wallet.worth) + to_chat(usr, "Insufficient funds on chargecard.") + return 0 + else + wallet.worth -= currently_vending.price + credit_purchase("[wallet.owner_name] (chargecard)") + return 1 + +/** + * Scan a card and attempt to transfer payment from associated account. + * + * Takes payment for whatever is the currently_vending item. Returns 1 if + * successful, 0 if failed + */ +/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M) + visible_message("[M] swipes a card through [src].") + playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) + + var/datum/money_account/customer_account = get_account(I.associated_account_number) + if(!customer_account) + to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.") + return FALSE + + if(customer_account.suspended) + to_chat(M, "Unable to access account: account suspended.") + return FALSE + + // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is + // empty at high security levels + if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) + var/attempt_pin = input("Enter pin code", "Vendor transaction") as num + customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) + + if(!customer_account) + to_chat(M, "Unable to access account: incorrect credentials.") + return FALSE + + if(currently_vending.price > customer_account.money) + to_chat(M, "Insufficient funds in account.") + return FALSE + + // Okay to move the money at this point + + // debit money from the purchaser's account + customer_account.money -= currently_vending.price + + // create entry in the purchaser's account log + var/datum/transaction/T = new() + T.target_name = "[vendor_account.owner_name] (via [name])" + T.purpose = "Purchase of [currently_vending.item_name]" + if(currently_vending.price > 0) + T.amount = "([currently_vending.price])" + else + T.amount = "[currently_vending.price]" + T.source_terminal = name + T.date = current_date_string + T.time = stationtime2text() + customer_account.transaction_log.Add(T) + + // Give the vendor the money. We use the account owner name, which means + // that purchases made with stolen/borrowed card will look like the card + // owner made them + credit_purchase(customer_account.owner_name) + return 1 + +/** + * Add money for current purchase to the vendor account. + * + * Called after the money has already been taken from the customer. + */ +/obj/machinery/vending/proc/credit_purchase(var/target as text) + vendor_account.money += currently_vending.price + + var/datum/transaction/T = new() + T.target_name = target + T.purpose = "Purchase of [currently_vending.item_name]" + T.amount = "[currently_vending.price]" + T.source_terminal = name + T.date = current_date_string + T.time = stationtime2text() + vendor_account.transaction_log.Add(T) + +/obj/machinery/vending/attack_ghost(mob/user) + return attack_hand(user) + +/obj/machinery/vending/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/vending/attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + + if(seconds_electrified != 0) + if(shock(user, 100)) + return + + wires.Interact(user) + tgui_interact(user) + +/obj/machinery/vending/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/vending), + ) + +/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Vending", name) + ui.open() + +/obj/machinery/vending/tgui_data(mob/user) + var/list/data = list() + var/list/listed_products = list() + + data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE + for(var/key = 1 to product_records.len) + var/datum/stored_item/vending_product/I = product_records[key] + + if(!(I.category & categories)) + continue + + listed_products.Add(list(list( + "key" = key, + "name" = I.item_name, + "price" = I.price, + "color" = I.display_color, + "isatom" = ispath(I.item_path, /atom), + "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"), + "amount" = I.get_amount() + ))) + + data["products"] = listed_products + + if(coin) + data["coin"] = coin.name + else + data["coin"] = FALSE + + if(currently_vending) + data["actively_vending"] = currently_vending.item_name + else + data["actively_vending"] = null + + if(panel_open) + data["panel"] = 1 + data["speaker"] = shut_up ? 0 : 1 + else + data["panel"] = 0 + + var/mob/living/carbon/human/H + var/obj/item/weapon/card/id/C + + data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash."; + data["userMoney"] = 0 + data["user"] = null + if(ishuman(user)) + H = user + C = H.GetIdCard() + var/obj/item/weapon/spacecash/S = H.get_active_hand() + if(istype(S)) + data["userMoney"] = S.worth + data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]₮." + else if(istype(C)) + var/datum/money_account/A = get_account(C.associated_account_number) + if(istype(A)) + data["user"] = list() + data["user"]["name"] = A.owner_name + data["userMoney"] = A.money + data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job" + else + data["guestNotice"] = "Unlinked ID detected. Present cash to pay."; + + return data + +/obj/machinery/vending/tgui_act(action, params) + if(stat & (BROKEN|NOPOWER)) + return + if(usr.stat || usr.restrained()) + return + if(..()) + return TRUE + + . = TRUE + switch(action) + if("remove_coin") + if(issilicon(usr)) + return FALSE + + if(!coin) + to_chat(usr, "There is no coin in this machine.") + return + + coin.forceMove(src.loc) + if(!usr.get_active_hand()) + usr.put_in_hands(coin) + + to_chat(usr, "You remove \the [coin] from \the [src].") + coin = null + categories &= ~CAT_COIN + return TRUE + if("vend") + if(!vend_ready) + to_chat(usr, "[src] is busy!") + return + if(!allowed(usr) && !emagged && scan_id) + to_chat(usr, "Access denied.") //Unless emagged of course + flick("[icon_state]-deny",src) + playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) + return + if(panel_open) + to_chat(usr, "[src] cannot dispense products while its service panel is open!") + return + + var/key = text2num(params["vend"]) + var/datum/stored_item/vending_product/R = product_records[key] + + // This should not happen unless the request from NanoUI was bad + if(!(R.category & categories)) + return + + if(!can_buy(R, usr)) + return + if(R.price <= 0) + vend(R, usr) + add_fingerprint(usr) + return TRUE + + if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something. + to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.") + return + if(!ishuman(usr)) + return + + + vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved. + + var/mob/living/carbon/human/H = usr + var/obj/item/weapon/card/id/C = H.GetIdCard() + + if(!vendor_account || vendor_account.suspended) + to_chat(usr, "Vendor account offline. Unable to process transaction.") + flick("[icon_state]-deny",src) + vend_ready = TRUE + return + + currently_vending = R + + var/paid = FALSE + + if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash)) + var/obj/item/weapon/spacecash/cash = usr.get_active_hand() + paid = pay_with_cash(cash, usr) + else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet)) + var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand() + paid = pay_with_ewallet(wallet) + else if(istype(C, /obj/item/weapon/card)) + paid = pay_with_card(C, usr) + /*else if(usr.can_advanced_admin_interact()) + to_chat(usr, "Vending object due to admin interaction.") + paid = TRUE*/ + else + to_chat(usr, "Payment failure: you have no ID or other method of payment.") + vend_ready = TRUE + flick("[icon_state]-deny",src) + return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update. + if(paid) + vend(currently_vending, usr) // vend will handle vend_ready + . = TRUE + else + to_chat(usr, "Payment failure: unable to process payment.") + vend_ready = TRUE + + if("togglevoice") + if(!panel_open) + return FALSE + shut_up = !shut_up + +/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user) + if(!allowed(user) && !emagged && scan_id) + to_chat(user, "Access denied.") //Unless emagged of course + flick("[icon_state]-deny",src) + playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) + return FALSE + return TRUE + +/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user) + if(!can_buy(R, user)) + return + + if(!R.amount) + to_chat(user, "[src] has ran out of that product.") + vend_ready = TRUE + return + + vend_ready = FALSE //One thing at a time!! + SStgui.update_uis(src) + + if(R.category & CAT_COIN) + if(!coin) + to_chat(user, "You need to insert a coin to get this item.") + return + if(coin.string_attached) + if(prob(50)) + to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.") + else + to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.") + qdel(coin) + coin = null + categories &= ~CAT_COIN + else + qdel(coin) + coin = null + categories &= ~CAT_COIN + + if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply) + spawn(0) + speak(vend_reply) + last_reply = world.time + + use_power(vend_power_usage) //actuators and stuff + flick("[icon_state]-vend",src) + addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay) + +/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user) + R.get_product(get_turf(src)) + if(has_logs) + do_logging(R, user, 1) + if(prob(1)) + sleep(3) + if(R.get_product(get_turf(src))) + visible_message("\The [src] clunks as it vends an additional item.") + playsound(src, "sound/[vending_sound]", 100, 1, 1) + + vend_ready = 1 + currently_vending = null + SStgui.update_uis(src) + GLOB.items_sold_shift_roundstat++ + +/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0) + if(user.GetIdCard()) + var/obj/item/weapon/card/id/tempid = user.GetIdCard() + var/list/list_item = list() + if(vending) + list_item += "vend" + else + list_item += "stock" + list_item += tempid.registered_name + list_item += stationtime2text() + list_item += R.item_name + log[++log.len] = list_item + +/obj/machinery/vending/proc/show_log(mob/user as mob) + if(user.GetIdCard()) + var/obj/item/weapon/card/id/tempid = user.GetIdCard() + if(req_log_access in tempid.GetAccess()) + var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500) + var/dat = "" + dat += "
[name] Vending Log
" + dat += "
Welcome [user.name]!

" + dat += "Below are the recent vending logs for your vending machine.
" + for(var/i in log) + dat += json_encode(i) + dat += ";
" + popup.set_content(dat) + popup.open() + else + to_chat(user,"You do not have the required access to view the vending logs for this machine.") + + +/obj/machinery/vending/verb/rotate_clockwise() + set name = "Rotate Vending Machine Clockwise" + set category = "Object" + set src in oview(1) + + if (src.can_rotate == 0) + to_chat(usr, "\The [src] cannot be rotated.") + return 0 + + if (src.anchored || usr:stat) + to_chat(usr, "It is bolted down!") + return 0 + src.set_dir(turn(src.dir, 270)) + return 1 + +/obj/machinery/vending/verb/check_logs() + set name = "Check Vending Logs" + set category = "Object" + set src in oview(1) + + show_log(usr) + +/** + * Add item to the machine + * + * Checks if item is vendable in this machine should be performed before + * calling. W is the item being inserted, R is the associated vending_product entry. + */ +/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user) + if(!user.unEquip(W)) + return + + to_chat(user, "You insert \the [W] in the product receptor.") + R.add_product(W) + if(has_logs) + do_logging(R, user) + + SStgui.update_uis(src) + +/obj/machinery/vending/process() + if(stat & (BROKEN|NOPOWER)) + return + + if(!active) + return + + if(seconds_electrified > 0) + seconds_electrified-- + + //Pitch to the people! Really sell it! + if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5)) + var/slogan = pick(slogan_list) + speak(slogan) + last_slogan = world.time + + if(shoot_inventory && prob(2)) + throw_item() + + return + +/obj/machinery/vending/proc/speak(var/message) + if(stat & NOPOWER) + return + + if(!message) + return + + for(var/mob/O in hearers(src, null)) + O.show_message("\The [src] beeps, \"[message]\"",2) + return + +/obj/machinery/vending/power_change() + ..() + if(stat & BROKEN) + icon_state = "[initial(icon_state)]-broken" + else + if(!(stat & NOPOWER)) + icon_state = initial(icon_state) + else + spawn(rand(0, 15)) + icon_state = "[initial(icon_state)]-off" + +//Oh no we're malfunctioning! Dump out some product and break. +/obj/machinery/vending/proc/malfunction() + for(var/datum/stored_item/vending_product/R in product_records) + while(R.get_amount()>0) + R.get_product(loc) + break + + stat |= BROKEN + icon_state = "[initial(icon_state)]-broken" + return + +//Somebody cut an important wire and now we're following a new definition of "pitch." +/obj/machinery/vending/proc/throw_item() + var/obj/throw_item = null + var/mob/living/target = locate() in view(7,src) + if(!target) + return 0 + + for(var/datum/stored_item/vending_product/R in product_records) + throw_item = R.get_product(loc) + if(!throw_item) + continue + break + if(!throw_item) + return 0 + spawn(0) + throw_item.throw_at(target, 16, 3, src) + visible_message("\The [src] launches \a [throw_item] at \the [target]!") + return 1 + +//Actual machines are in vending_machines.dm +======= +/// +/// A vending machine +/// + +// +// ALL THE VENDING MACHINES ARE IN vending_machines.dm now! +// + +/obj/machinery/vending + name = "Vendomat" + desc = "A generic vending machine." + icon = 'icons/obj/vending.dmi' + icon_state = "generic" + anchored = 1 + density = 1 + clicksound = "button" + + // Power + use_power = USE_POWER_IDLE + idle_power_usage = 10 + var/vend_power_usage = 150 //actuators and stuff + + // Vending-related + var/active = 1 //No sales pitches if off! + var/vend_ready = 1 //Are we ready to vend?? Is it time?? + var/vend_delay = 10 //How long does it take to vend? + var/categories = CAT_NORMAL // Bitmask of cats we're currently showing + var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now + var/vending_sound = "machines/vending/vending_drop.ogg" + + /* + Variables used to initialize the product list + These are used for initialization only, and so are optional if + product_records is specified + */ + var/list/products = list() // For each, use the following pattern: + var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2) + var/list/premium = list() // No specified amount = only one in stock + var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price. + + // List of vending_product items available. + var/list/product_records = list() + + + // Variables used to initialize advertising + var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons + var/product_ads = "" //String of small ad messages in the vending screen + + var/list/ads_list = list() + + // Stuff relating vocalizations + var/list/slogan_list = list() + var/shut_up = 1 //Stop spouting those godawful pitches! + var/vend_reply //Thank you for shopping! + var/last_reply = 0 + var/last_slogan = 0 //When did we last pitch? + var/slogan_delay = 6000 //How long until we can pitch again? + + // Things that can go wrong + emagged = 0 //Ignores if somebody doesn't have card access to that machine. + var/seconds_electrified = 0 //Shock customers like an airlock. + var/shoot_inventory = 0 //Fire items at customers! We're broken! + + var/scan_id = 1 + var/obj/item/weapon/coin/coin + var/datum/wires/vending/wires = null + + var/list/log = list() + var/req_log_access = access_cargo //default access for checking logs is cargo + var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs + var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals. + + +/obj/machinery/vending/Initialize() + . = ..() + wires = new(src) + if(product_slogans) + slogan_list += splittext(product_slogans, ";") + + // So not all machines speak at the exact same time. + // The first time this machine says something will be at slogantime + this random value, + // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. + last_slogan = world.time + rand(0, slogan_delay) + + if(product_ads) + ads_list += splittext(product_ads, ";") + + build_inventory() + power_change() + +GLOBAL_LIST_EMPTY(vending_products) +/** + * Build produdct_records from the products lists + * + * products, contraband, premium, and prices allow specifying + * products that the vending machine is to carry without manually populating + * product_records. + */ +/obj/machinery/vending/proc/build_inventory() + var/list/all_products = list( + list(products, CAT_NORMAL), + list(contraband, CAT_HIDDEN), + list(premium, CAT_COIN)) + + for(var/current_list in all_products) + var/category = current_list[2] + + for(var/entry in current_list[1]) + var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry) + + product.price = (entry in prices) ? prices[entry] : 0 + product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1 + product.category = category + + product_records.Add(product) + GLOB.vending_products[entry] = 1 + +/obj/machinery/vending/Destroy() + qdel(wires) + wires = null + qdel(coin) + coin = null + for(var/datum/stored_item/vending_product/R in product_records) + qdel(R) + product_records = null + return ..() + +/obj/machinery/vending/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if(prob(50)) + qdel(src) + return + if(3.0) + if(prob(25)) + spawn(0) + malfunction() + return + return + else + return + +/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user) + if(!emagged) + emagged = 1 + to_chat(user, "You short out \the [src]'s product lock.") + return 1 + +/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob) + var/obj/item/weapon/card/id/I = W.GetID() + + if(I || istype(W, /obj/item/weapon/spacecash)) + attack_hand(user) + return + else if(W.is_screwdriver()) + panel_open = !panel_open + to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") + playsound(src, W.usesound, 50, 1) + if(panel_open) + wires.Interact(user) + add_overlay("[initial(icon_state)]-panel") + else + cut_overlay("[initial(icon_state)]-panel") + + SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI + return + else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter()) + if(panel_open) + attack_hand(user) + return + else if(istype(W, /obj/item/weapon/coin) && premium.len > 0) + user.drop_item() + W.forceMove(src) + coin = W + categories |= CAT_COIN + to_chat(user, "You insert \the [W] into \the [src].") + SStgui.update_uis(src) + return + else if(W.is_wrench()) + playsound(src, W.usesound, 100, 1) + if(anchored) + user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") + else + user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") + + if(do_after(user, 20 * W.toolspeed)) + if(!src) return + to_chat(user, "You [anchored? "un" : ""]secured \the [src]!") + anchored = !anchored + return + else + + for(var/datum/stored_item/vending_product/R in product_records) + if(istype(W, R.item_path) && (W.name == R.item_name)) + stock(W, R, user) + return + ..() + +/** + * Receive payment with cashmoney. + * + * usr is the mob who gets the change. + */ +/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user) + if(currently_vending.price > cashmoney.worth) + + // This is not a status display message, since it's something the character + // themselves is meant to see BEFORE putting the money in + to_chat(usr, "[bicon(cashmoney)] That is not enough money.") + return 0 + + if(istype(cashmoney, /obj/item/weapon/spacecash)) + + visible_message("\The [usr] inserts some cash into \the [src].") + cashmoney.worth -= currently_vending.price + + if(cashmoney.worth <= 0) + usr.drop_from_inventory(cashmoney) + qdel(cashmoney) + else + cashmoney.update_icon() + + // Vending machines have no idea who paid with cash + credit_purchase("(cash)") + return 1 + +/** + * Scan a chargecard and deduct payment from it. + * + * Takes payment for whatever is the currently_vending item. Returns 1 if + * successful, 0 if failed. + */ +/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet) + visible_message("\The [usr] swipes \the [wallet] through \the [src].") + playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) + if(currently_vending.price > wallet.worth) + to_chat(usr, "Insufficient funds on chargecard.") + return 0 + else + wallet.worth -= currently_vending.price + credit_purchase("[wallet.owner_name] (chargecard)") + return 1 + +/** + * Scan a card and attempt to transfer payment from associated account. + * + * Takes payment for whatever is the currently_vending item. Returns 1 if + * successful, 0 if failed + */ +/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M) + visible_message("[M] swipes a card through [src].") + playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) + + var/datum/money_account/customer_account = get_account(I.associated_account_number) + if(!customer_account) + to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.") + return FALSE + + if(customer_account.suspended) + to_chat(M, "Unable to access account: account suspended.") + return FALSE + + // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is + // empty at high security levels + if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) + var/attempt_pin = input("Enter pin code", "Vendor transaction") as num + customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) + + if(!customer_account) + to_chat(M, "Unable to access account: incorrect credentials.") + return FALSE + + if(currently_vending.price > customer_account.money) + to_chat(M, "Insufficient funds in account.") + return FALSE + + // Okay to move the money at this point + + // debit money from the purchaser's account + customer_account.money -= currently_vending.price + + // create entry in the purchaser's account log + var/datum/transaction/T = new() + T.target_name = "[vendor_account.owner_name] (via [name])" + T.purpose = "Purchase of [currently_vending.item_name]" + if(currently_vending.price > 0) + T.amount = "([currently_vending.price])" + else + T.amount = "[currently_vending.price]" + T.source_terminal = name + T.date = current_date_string + T.time = stationtime2text() + customer_account.transaction_log.Add(T) + + // Give the vendor the money. We use the account owner name, which means + // that purchases made with stolen/borrowed card will look like the card + // owner made them + credit_purchase(customer_account.owner_name) + return 1 + +/** + * Add money for current purchase to the vendor account. + * + * Called after the money has already been taken from the customer. + */ +/obj/machinery/vending/proc/credit_purchase(var/target as text) + vendor_account.money += currently_vending.price + + var/datum/transaction/T = new() + T.target_name = target + T.purpose = "Purchase of [currently_vending.item_name]" + T.amount = "[currently_vending.price]" + T.source_terminal = name + T.date = current_date_string + T.time = stationtime2text() + vendor_account.transaction_log.Add(T) + +/obj/machinery/vending/attack_ghost(mob/user) + return attack_hand(user) + +/obj/machinery/vending/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/vending/attack_hand(mob/user as mob) + if(stat & (BROKEN|NOPOWER)) + return + + if(seconds_electrified != 0) + if(shock(user, 100)) + return + + wires.Interact(user) + tgui_interact(user) + +/obj/machinery/vending/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/vending), + ) + +/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Vending", name) + ui.open() + +/obj/machinery/vending/tgui_data(mob/user) + var/list/data = list() + var/list/listed_products = list() + + data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE + for(var/key = 1 to product_records.len) + var/datum/stored_item/vending_product/I = product_records[key] + + if(!(I.category & categories)) + continue + + listed_products.Add(list(list( + "key" = key, + "name" = I.item_name, + "price" = I.price, + "color" = I.display_color, + "isatom" = ispath(I.item_path, /atom), + "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"), + "amount" = I.get_amount() + ))) + + data["products"] = listed_products + + if(coin) + data["coin"] = coin.name + else + data["coin"] = FALSE + + if(currently_vending) + data["actively_vending"] = currently_vending.item_name + else + data["actively_vending"] = null + + if(panel_open) + data["panel"] = 1 + data["speaker"] = shut_up ? 0 : 1 + else + data["panel"] = 0 + + var/mob/living/carbon/human/H + var/obj/item/weapon/card/id/C + + data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash."; + data["userMoney"] = 0 + data["user"] = null + if(ishuman(user)) + H = user + C = H.GetIdCard() + var/obj/item/weapon/spacecash/S = H.get_active_hand() + if(istype(S)) + data["userMoney"] = S.worth + data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]₮." + else if(istype(C)) + var/datum/money_account/A = get_account(C.associated_account_number) + if(istype(A)) + data["user"] = list() + data["user"]["name"] = A.owner_name + data["userMoney"] = A.money + data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job" + else + data["guestNotice"] = "Unlinked ID detected. Present cash to pay."; + + return data + +/obj/machinery/vending/tgui_act(action, params) + if(stat & (BROKEN|NOPOWER)) + return + if(usr.stat || usr.restrained()) + return + if(..()) + return TRUE + + . = TRUE + switch(action) + if("remove_coin") + if(issilicon(usr)) + return FALSE + + if(!coin) + to_chat(usr, "There is no coin in this machine.") + return + + coin.forceMove(src.loc) + if(!usr.get_active_hand()) + usr.put_in_hands(coin) + + to_chat(usr, "You remove \the [coin] from \the [src].") + coin = null + categories &= ~CAT_COIN + return TRUE + if("vend") + if(!vend_ready) + to_chat(usr, "[src] is busy!") + return + if(!allowed(usr) && !emagged && scan_id) + to_chat(usr, "Access denied.") //Unless emagged of course + flick("[icon_state]-deny",src) + playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) + return + if(panel_open) + to_chat(usr, "[src] cannot dispense products while its service panel is open!") + return + + var/key = text2num(params["vend"]) + var/datum/stored_item/vending_product/R = product_records[key] + + // This should not happen unless the request from NanoUI was bad + if(!(R.category & categories)) + return + + if(!can_buy(R, usr)) + return + + if(R.price <= 0) + vend(R, usr) + add_fingerprint(usr) + return TRUE + + if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something. + to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.") + return + if(!ishuman(usr)) + return + + vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved. + + var/mob/living/carbon/human/H = usr + var/obj/item/weapon/card/id/C = H.GetIdCard() + + if(!vendor_account || vendor_account.suspended) + to_chat(usr, "Vendor account offline. Unable to process transaction.") + flick("[icon_state]-deny",src) + vend_ready = TRUE + return + + currently_vending = R + + var/paid = FALSE + + if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash)) + var/obj/item/weapon/spacecash/cash = usr.get_active_hand() + paid = pay_with_cash(cash, usr) + else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet)) + var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand() + paid = pay_with_ewallet(wallet) + else if(istype(C, /obj/item/weapon/card)) + paid = pay_with_card(C, usr) + /*else if(usr.can_advanced_admin_interact()) + to_chat(usr, "Vending object due to admin interaction.") + paid = TRUE*/ + else + to_chat(usr, "Payment failure: you have no ID or other method of payment.") + vend_ready = TRUE + flick("[icon_state]-deny",src) + return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update. + if(paid) + vend(currently_vending, usr) // vend will handle vend_ready + . = TRUE + else + to_chat(usr, "Payment failure: unable to process payment.") + vend_ready = TRUE + + if("togglevoice") + if(!panel_open) + return FALSE + shut_up = !shut_up + +/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user) + if(!allowed(user) && !emagged && scan_id) + to_chat(user, "Access denied.") //Unless emagged of course + flick("[icon_state]-deny",src) + playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) + return FALSE + return TRUE + +/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user) + if(!can_buy(R, user)) + return + + if(!R.amount) + to_chat(user, "[src] has ran out of that product.") + vend_ready = TRUE + return + + vend_ready = FALSE //One thing at a time!! + SStgui.update_uis(src) + + if(R.category & CAT_COIN) + if(!coin) + to_chat(user, "You need to insert a coin to get this item.") + return + if(coin.string_attached) + if(prob(50)) + to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.") + else + to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.") + qdel(coin) + coin = null + categories &= ~CAT_COIN + else + qdel(coin) + coin = null + categories &= ~CAT_COIN + + if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply) + spawn(0) + speak(vend_reply) + last_reply = world.time + + use_power(vend_power_usage) //actuators and stuff + flick("[icon_state]-vend",src) + addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay) + +/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user) + R.get_product(get_turf(src)) + if(has_logs) + do_logging(R, user, 1) + if(prob(1)) + sleep(3) + if(R.get_product(get_turf(src))) + visible_message("\The [src] clunks as it vends an additional item.") + playsound(src, "sound/[vending_sound]", 100, 1, 1) + + GLOB.items_sold_shift_roundstat++ + + vend_ready = 1 + currently_vending = null + SStgui.update_uis(src) + + +/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0) + if(user.GetIdCard()) + var/obj/item/weapon/card/id/tempid = user.GetIdCard() + var/list/list_item = list() + if(vending) + list_item += "vend" + else + list_item += "stock" + list_item += tempid.registered_name + list_item += stationtime2text() + list_item += R.item_name + log[++log.len] = list_item + +/obj/machinery/vending/proc/show_log(mob/user as mob) + if(user.GetIdCard()) + var/obj/item/weapon/card/id/tempid = user.GetIdCard() + if(req_log_access in tempid.GetAccess()) + var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500) + var/dat = "" + dat += "
[name] Vending Log
" + dat += "
Welcome [user.name]!

" + dat += "Below are the recent vending logs for your vending machine.
" + for(var/i in log) + dat += json_encode(i) + dat += ";
" + popup.set_content(dat) + popup.open() + else + to_chat(user,"You do not have the required access to view the vending logs for this machine.") + + +/obj/machinery/vending/verb/rotate_clockwise() + set name = "Rotate Vending Machine Clockwise" + set category = "Object" + set src in oview(1) + + if (src.can_rotate == 0) + to_chat(usr, "\The [src] cannot be rotated.") + return 0 + + if (src.anchored || usr:stat) + to_chat(usr, "It is bolted down!") + return 0 + src.set_dir(turn(src.dir, 270)) + return 1 + +/obj/machinery/vending/verb/check_logs() + set name = "Check Vending Logs" + set category = "Object" + set src in oview(1) + + show_log(usr) + +/** + * Add item to the machine + * + * Checks if item is vendable in this machine should be performed before + * calling. W is the item being inserted, R is the associated vending_product entry. + */ +/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user) + if(!user.unEquip(W)) + return + + to_chat(user, "You insert \the [W] in the product receptor.") + R.add_product(W) + if(has_logs) + do_logging(R, user) + + SStgui.update_uis(src) + +/obj/machinery/vending/process() + if(stat & (BROKEN|NOPOWER)) + return + + if(!active) + return + + if(seconds_electrified > 0) + seconds_electrified-- + + //Pitch to the people! Really sell it! + if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5)) + var/slogan = pick(slogan_list) + speak(slogan) + last_slogan = world.time + + if(shoot_inventory && prob(2)) + throw_item() + + return + +/obj/machinery/vending/proc/speak(var/message) + if(stat & NOPOWER) + return + + if(!message) + return + + for(var/mob/O in hearers(src, null)) + O.show_message("\The [src] beeps, \"[message]\"",2) + return + +/obj/machinery/vending/power_change() + ..() + if(stat & BROKEN) + icon_state = "[initial(icon_state)]-broken" + else + if(!(stat & NOPOWER)) + icon_state = initial(icon_state) + else + spawn(rand(0, 15)) + icon_state = "[initial(icon_state)]-off" + +//Oh no we're malfunctioning! Dump out some product and break. +/obj/machinery/vending/proc/malfunction() + for(var/datum/stored_item/vending_product/R in product_records) + while(R.get_amount()>0) + R.get_product(loc) + break + + stat |= BROKEN + icon_state = "[initial(icon_state)]-broken" + return + +//Somebody cut an important wire and now we're following a new definition of "pitch." +/obj/machinery/vending/proc/throw_item() + var/obj/throw_item = null + var/mob/living/target = locate() in view(7,src) + if(!target) + return 0 + + for(var/datum/stored_item/vending_product/R in product_records) + throw_item = R.get_product(loc) + if(!throw_item) + continue + break + if(!throw_item) + return 0 + spawn(0) + throw_item.throw_at(target, 16, 3, src) + visible_message("\The [src] launches \a [throw_item] at \the [target]!") + return 1 + +//Actual machines are in vending_machines.dm +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:code/modules/economy/vending.dm diff --git a/code/game/machinery/vending_machines.dm b/code/modules/economy/vending_machines.dm similarity index 100% rename from code/game/machinery/vending_machines.dm rename to code/modules/economy/vending_machines.dm diff --git a/code/game/objects/items/stacks/fifty_spawner.dm b/code/modules/materials/fifty_spawner.dm similarity index 100% rename from code/game/objects/items/stacks/fifty_spawner.dm rename to code/modules/materials/fifty_spawner.dm diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm index c1239b234c9..a6befbbea4c 100644 --- a/code/modules/materials/material_recipes.dm +++ b/code/modules/materials/material_recipes.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /datum/material/proc/get_recipes() if(!recipes) generate_recipes() @@ -276,3 +277,5 @@ recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") recipes += new/datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") +======= +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor diff --git a/code/modules/materials/materials/_materials.dm b/code/modules/materials/materials/_materials.dm new file mode 100644 index 00000000000..1b6cabffd96 --- /dev/null +++ b/code/modules/materials/materials/_materials.dm @@ -0,0 +1,284 @@ +/* + MATERIAL DATUMS + This data is used by various parts of the game for basic physical properties and behaviors + of the metals/materials used for constructing many objects. Each var is commented and should be pretty + self-explanatory but the various object types may have their own documentation. ~Z + + PATHS THAT USE DATUMS + turf/simulated/wall + obj/item/weapon/material + obj/structure/barricade + obj/item/stack/material + obj/structure/table + + VALID ICONS + WALLS + stone + metal + solid + resin + ONLY WALLS + cult + hull + curvy + jaggy + brick + REINFORCEMENT + reinf_over + reinf_mesh + reinf_cult + reinf_metal + DOORS + stone + metal + resin + wood +*/ + +// Assoc list containing all material datums indexed by name. +var/list/name_to_material + +//Returns the material the object is made of, if applicable. +//Will we ever need to return more than one value here? Or should we just return the "dominant" material. +/obj/proc/get_material() + return null + +//mostly for convenience +/obj/proc/get_material_name() + var/datum/material/material = get_material() + if(material) + return material.name + +// Builds the datum list above. +/proc/populate_material_list(force_remake=0) + if(name_to_material && !force_remake) return // Already set up! + name_to_material = list() + for(var/type in subtypesof(/datum/material)) + var/datum/material/new_mineral = new type + if(!new_mineral.name) + continue + name_to_material[lowertext(new_mineral.name)] = new_mineral + return 1 + +// Safety proc to make sure the material list exists before trying to grab from it. +/proc/get_material_by_name(name) + if(!name_to_material) + populate_material_list() + return name_to_material[name] + +/proc/material_display_name(name) + var/datum/material/material = get_material_by_name(name) + if(material) + return material.display_name + return null + +// Material definition and procs follow. +/datum/material + var/name // Unique name for use in indexing the list. + var/display_name // Prettier name for display. + var/use_name + var/flags = 0 // Various status modifiers. + var/sheet_singular_name = "sheet" + var/sheet_plural_name = "sheets" + var/is_fusion_fuel + + // Shards/tables/structures + var/shard_type = SHARD_SHRAPNEL // Path of debris object. + var/shard_icon // Related to above. + var/shard_can_repair = 1 // Can shards be turned into sheets with a welder? + var/list/recipes // Holder for all recipes usable with a sheet of this material. + var/destruction_desc = "breaks apart" // Fancy string for barricades/tables/objects exploding. + + // Icons + var/icon_colour // Colour applied to products of this material. + var/icon_base = "metal" // Wall and table base icon tag. See header. + var/door_icon_base = "metal" // Door base icon tag. See header. + var/icon_reinf = "reinf_metal" // Overlay used + var/list/stack_origin_tech = list(TECH_MATERIAL = 1) // Research level for stacks. + var/pass_stack_colors = FALSE // Will stacks made from this material pass their colors onto objects? + + // Attributes + var/cut_delay = 0 // Delay in ticks when cutting through this wall. + var/radioactivity // Radiation var. Used in wall and object processing to irradiate surroundings. + var/ignition_point // K, point at which the material catches on fire. + var/melting_point = 1800 // K, walls will take damage if they're next to a fire hotter than this + var/integrity = 150 // General-use HP value for products. + var/protectiveness = 10 // How well this material works as armor. Higher numbers are better, diminishing returns applies. + var/opacity = 1 // Is the material transparent? 0.5< makes transparent walls/doors. + var/reflectivity = 0 // How reflective to light is the material? Currently used for laser reflection and defense. + var/explosion_resistance = 5 // Only used by walls currently. + var/negation = 0 // Objects that respect this will randomly absorb impacts with this var as the percent chance. + var/spatial_instability = 0 // Objects that have trouble staying in the same physical space by sheer laws of nature have this. Percent for respecting items to cause teleportation. + var/conductive = 1 // Objects without this var add NOCONDUCT to flags on spawn. + var/conductivity = null // How conductive the material is. Iron acts as the baseline, at 10. + var/list/composite_material // If set, object matter var will be a list containing these values. + var/luminescence + var/radiation_resistance = 0 // Radiation resistance, which is added on top of a material's weight for blocking radiation. Needed to make lead special without superrobust weapons. + var/supply_conversion_value // Supply points per sheet that this material sells for. + + // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods. + var/created_window + var/created_fulltile_window + var/rod_product + var/wire_product + var/list/window_options = list() + + // Damage values. + var/hardness = 60 // Prob of wall destruction by hulk, used for edge damage in weapons. Also used for bullet protection in armor. + var/weight = 20 // Determines blunt damage/throwforce for weapons. + + // Noise when someone is faceplanted onto a table made of this material. + var/tableslam_noise = 'sound/weapons/tablehit1.ogg' + // Noise made when a simple door made of this material opens or closes. + var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg' + // Path to resulting stacktype. Todo remove need for this. + var/stack_type + // Wallrot crumble message. + var/rotting_touch_message = "crumbles under your touch" + +// Placeholders for light tiles and rglass. +/datum/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) + if(!rod_product) + to_chat(user, "You cannot make anything out of \the [target_stack]") + return + if(used_stack.get_amount() < 1 || target_stack.get_amount() < 1) + to_chat(user, "You need one rod and one sheet of [display_name] to make anything useful.") + return + used_stack.use(1) + target_stack.use(1) + var/obj/item/stack/S = new rod_product(get_turf(user)) + S.add_fingerprint(user) + S.add_to_stacks(user) + +/datum/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) + if(!wire_product) + to_chat(user, "You cannot make anything out of \the [target_stack]") + return + if(used_stack.get_amount() < 5 || target_stack.get_amount() < 1) + to_chat(user, "You need five wires and one sheet of [display_name] to make anything useful.") + return + + used_stack.use(5) + target_stack.use(1) + to_chat(user, "You attach wire to the [name].") + var/obj/item/product = new wire_product(get_turf(user)) + user.put_in_hands(product) + +// Make sure we have a display name and shard icon even if they aren't explicitly set. +/datum/material/New() + ..() + if(!display_name) + display_name = name + if(!use_name) + use_name = display_name + if(!shard_icon) + shard_icon = shard_type + +// This is a placeholder for proper integration of windows/windoors into the system. +/datum/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) + return 0 + +// Weapons handle applying a divisor for this value locally. +/datum/material/proc/get_blunt_damage() + return weight //todo + +// Return the matter comprising this material. +/datum/material/proc/get_matter() + var/list/temp_matter = list() + if(islist(composite_material)) + for(var/material_string in composite_material) + temp_matter[material_string] = composite_material[material_string] + else if(SHEET_MATERIAL_AMOUNT) + temp_matter[name] = SHEET_MATERIAL_AMOUNT + return temp_matter + +// As above. +/datum/material/proc/get_edge_damage() + return hardness //todo + +// Snowflakey, only checked for alien doors at the moment. +/datum/material/proc/can_open_material_door(var/mob/living/user) + return 1 + +// Currently used for weapons and objects made of uranium to irradiate things. +/datum/material/proc/products_need_process() + return (radioactivity>0) //todo + +// Used by walls when qdel()ing to avoid neighbor merging. +/datum/material/placeholder + name = "placeholder" + +// Places a girder object when a wall is dismantled, also applies reinforced material. +/datum/material/proc/place_dismantled_girder(var/turf/target, var/datum/material/reinf_material, var/datum/material/girder_material) + var/obj/structure/girder/G = new(target) + if(reinf_material) + G.reinf_material = reinf_material + G.reinforce_girder() + if(girder_material) + if(istype(girder_material, /datum/material)) + girder_material = girder_material.name + G.set_material(girder_material) + + +// General wall debris product placement. +// Not particularly necessary aside from snowflakey cult girders. +/datum/material/proc/place_dismantled_product(var/turf/target) + place_sheet(target) + +// Debris product. Used ALL THE TIME. +/datum/material/proc/place_sheet(var/turf/target) + if(stack_type) + return new stack_type(target) + +// As above. +/datum/material/proc/place_shard(var/turf/target) + if(shard_type) + return new /obj/item/weapon/material/shard(target, src.name) + +// Used by walls and weapons to determine if they break or not. +/datum/material/proc/is_brittle() + return !!(flags & MATERIAL_BRITTLE) + +/datum/material/proc/combustion_effect(var/turf/T, var/temperature) + return + +// Used by walls to do on-touch things, after checking for crumbling and open-ability. +/datum/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) + return + +/datum/material/proc/get_recipes() + if(!recipes) + generate_recipes() + return recipes + +/datum/material/proc/generate_recipes() + // If is_brittle() returns true, these are only good for a single strike. + recipes = list( + new /datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] armor plate insert", /obj/item/weapon/material/armor_plating/insert, 2, time = 40, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) + ) + + if(integrity>=50) + recipes += list( + new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) + ) + + if(hardness>50) + recipes += list( + new /datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] defense wire", /obj/item/weapon/material/barbedwire, 10, time = 1 MINUTE, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) + ) \ No newline at end of file diff --git a/code/modules/materials/materials/alien_alloy.dm b/code/modules/materials/materials/alien_alloy.dm new file mode 100644 index 00000000000..741f0275b75 --- /dev/null +++ b/code/modules/materials/materials/alien_alloy.dm @@ -0,0 +1,36 @@ +// Adminspawn only, do not let anyone get this. +/datum/material/alienalloy + name = "alienalloy" + display_name = "durable alloy" + stack_type = null + flags = MATERIAL_UNMELTABLE + icon_colour = "#6C7364" + integrity = 1200 + melting_point = 6000 // Hull plating. + explosion_resistance = 200 // Hull plating. + hardness = 500 + weight = 500 + protectiveness = 80 // 80% + +/datum/material/alienalloy/elevatorium + name = "elevatorium" + display_name = "elevator panelling" + icon_colour = "#666666" + +/datum/material/alienalloy/dungeonium + name = "dungeonium" + display_name = "ultra-durable" + icon_base = "dungeon" + icon_colour = "#FFFFFF" + +/datum/material/alienalloy/bedrock + name = "bedrock" + display_name = "impassable rock" + icon_base = "rock" + icon_colour = "#FFFFFF" + +/datum/material/alienalloy/alium + name = "alium" + display_name = "alien" + icon_base = "alien" + icon_colour = "#FFFFFF" \ No newline at end of file diff --git a/code/modules/materials/materials/cult.dm b/code/modules/materials/materials/cult.dm new file mode 100644 index 00000000000..7d8d4be9f2f --- /dev/null +++ b/code/modules/materials/materials/cult.dm @@ -0,0 +1,23 @@ +/datum/material/cult + name = "cult" + display_name = "disturbing stone" + icon_base = "cult" + icon_colour = "#402821" + icon_reinf = "reinf_cult" + shard_type = SHARD_STONE_PIECE + sheet_singular_name = "brick" + sheet_plural_name = "bricks" + conductive = 0 + +/datum/material/cult/place_dismantled_girder(var/turf/target) + new /obj/structure/girder/cult(target, "cult") + +/datum/material/cult/place_dismantled_product(var/turf/target) + new /obj/effect/decal/cleanable/blood(target) + +/datum/material/cult/reinf + name = "cult2" + display_name = "human remains" + +/datum/material/cult/reinf/place_dismantled_product(var/turf/target) + new /obj/effect/decal/remains/human(target) \ No newline at end of file diff --git a/code/modules/materials/materials/gems.dm b/code/modules/materials/materials/gems.dm new file mode 100644 index 00000000000..9ec22a86b13 --- /dev/null +++ b/code/modules/materials/materials/gems.dm @@ -0,0 +1,154 @@ +/datum/material/phoron + name = "phoron" + stack_type = /obj/item/stack/material/phoron + ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE + icon_base = "stone" + icon_colour = "#FC2BC5" + shard_type = SHARD_SHARD + hardness = 30 + stack_origin_tech = list(TECH_MATERIAL = 2, TECH_PHORON = 2) + door_icon_base = "stone" + sheet_singular_name = "crystal" + sheet_plural_name = "crystals" + supply_conversion_value = 5 + +/* +// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately. +/datum/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier) + if(isnull(ignition_point)) + return 0 + if(temperature < ignition_point) + return 0 + var/totalPhoron = 0 + for(var/turf/simulated/floor/target_tile in range(2,T)) + var/phoronToDeduce = (temperature/30) * effect_multiplier + totalPhoron += phoronToDeduce + target_tile.assume_gas("phoron", phoronToDeduce, 200+T0C) + spawn (0) + target_tile.hotspot_expose(temperature, 400) + return round(totalPhoron/100) +*/ + +/datum/material/diamond + name = "diamond" + stack_type = /obj/item/stack/material/diamond + flags = MATERIAL_UNMELTABLE + cut_delay = 60 + icon_colour = "#00FFE1" + opacity = 0.4 + reflectivity = 0.6 + conductive = 0 + conductivity = 1 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + hardness = 100 + stack_origin_tech = list(TECH_MATERIAL = 6) + supply_conversion_value = 8 + +/datum/material/quartz + name = "quartz" + display_name = "quartz" + use_name = "quartz" + icon_colour = "#e6d7df" + stack_type = /obj/item/stack/material/quartz + tableslam_noise = 'sound/effects/Glasshit.ogg' + sheet_singular_name = "crystal" + sheet_plural_name = "crystals" + supply_conversion_value = 4 + +/datum/material/painite + name = "painite" + display_name = "painite" + use_name = "painite" + icon_colour = "#6b4947" + stack_type = /obj/item/stack/material/painite + flags = MATERIAL_UNMELTABLE + reflectivity = 0.3 + tableslam_noise = 'sound/effects/Glasshit.ogg' + sheet_singular_name = "gem" + sheet_plural_name = "gems" + supply_conversion_value = 4 + +/datum/material/void_opal + name = "void opal" + display_name = "void opal" + use_name = "void opal" + icon_colour = "#0f0f0f" + stack_type = /obj/item/stack/material/void_opal + flags = MATERIAL_UNMELTABLE + cut_delay = 60 + reflectivity = 0 + conductivity = 1 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + hardness = 100 + stack_origin_tech = list(TECH_ARCANE = 1, TECH_MATERIAL = 6) + sheet_singular_name = "gem" + sheet_plural_name = "gems" + supply_conversion_value = 30 // These are hilariously rare. + +// Particle Smasher and other exotic materials. +/datum/material/valhollide + name = MAT_VALHOLLIDE + stack_type = /obj/item/stack/material/valhollide + icon_base = "stone" + door_icon_base = "stone" + icon_reinf = "reinf_mesh" + icon_colour = "##FFF3B2" + protectiveness = 30 + integrity = 240 + weight = 30 + hardness = 45 + negation = 2 + conductive = 0 + conductivity = 5 + reflectivity = 0.5 + radiation_resistance = 20 + spatial_instability = 30 + stack_origin_tech = list(TECH_MATERIAL = 7, TECH_PHORON = 5, TECH_BLUESPACE = 5) + sheet_singular_name = "gem" + sheet_plural_name = "gems" + +/datum/material/verdantium + name = MAT_VERDANTIUM + stack_type = /obj/item/stack/material/verdantium + icon_base = "metal" + door_icon_base = "metal" + icon_reinf = "reinf_metal" + icon_colour = "#4FE95A" + integrity = 80 + protectiveness = 15 + weight = 15 + hardness = 30 + shard_type = SHARD_SHARD + negation = 15 + conductivity = 60 + reflectivity = 0.3 + radiation_resistance = 5 + stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 5, TECH_BIO = 4) + sheet_singular_name = "sheet" + sheet_plural_name = "sheets" + supply_conversion_value = 8 + +/datum/material/morphium + name = MAT_MORPHIUM + stack_type = /obj/item/stack/material/morphium + icon_base = "metal" + door_icon_base = "metal" + icon_colour = "#37115A" + icon_reinf = "reinf_metal" + protectiveness = 60 + integrity = 300 + conductive = 0 + conductivity = 1.5 + hardness = 90 + shard_type = SHARD_SHARD + weight = 30 + negation = 25 + explosion_resistance = 85 + reflectivity = 0.2 + radiation_resistance = 10 + stack_origin_tech = list(TECH_MATERIAL = 8, TECH_ILLEGAL = 1, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_ARCANE = 1) + supply_conversion_value = 13 + + diff --git a/code/modules/materials/materials/glass.dm b/code/modules/materials/materials/glass.dm new file mode 100644 index 00000000000..79535422785 --- /dev/null +++ b/code/modules/materials/materials/glass.dm @@ -0,0 +1,143 @@ +/datum/material/glass + name = "glass" + stack_type = /obj/item/stack/material/glass + flags = MATERIAL_BRITTLE + icon_colour = "#00E1FF" + opacity = 0.3 + integrity = 100 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + hardness = 30 + weight = 15 + protectiveness = 0 // 0% + conductive = 0 + conductivity = 1 // Glass shards don't conduct. + door_icon_base = "stone" + destruction_desc = "shatters" + window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2) + created_window = /obj/structure/window/basic + created_fulltile_window = /obj/structure/window/basic/full + rod_product = /obj/item/stack/material/glass/reinforced + +/datum/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) + + if(!user || !used_stack || !created_window || !created_fulltile_window || !window_options.len) + return 0 + + if(!user.IsAdvancedToolUser()) + to_chat(user, "This task is too complex for your clumsy hands.") + return 1 + + var/turf/T = user.loc + if(!istype(T)) + to_chat(user, "You must be standing on open flooring to build a window.") + return 1 + + var/title = "Sheet-[used_stack.name] ([used_stack.get_amount()] sheet\s left)" + var/choice = input(title, "What would you like to construct?") as null|anything in window_options + + if(!choice || !used_stack || !user || used_stack.loc != user || user.stat || user.loc != T) + return 1 + + // Get data for building windows here. + var/list/possible_directions = cardinal.Copy() + var/window_count = 0 + for (var/obj/structure/window/check_window in user.loc) + window_count++ + possible_directions -= check_window.dir + for (var/obj/structure/windoor_assembly/check_assembly in user.loc) + window_count++ + possible_directions -= check_assembly.dir + for (var/obj/machinery/door/window/check_windoor in user.loc) + window_count++ + possible_directions -= check_windoor.dir + + // Get the closest available dir to the user's current facing. + var/build_dir = SOUTHWEST //Default to southwest for fulltile windows. + var/failed_to_build + + if(window_count >= 4) + failed_to_build = 1 + else + if(choice in list("One Direction","Windoor")) + if(possible_directions.len) + for(var/direction in list(user.dir, turn(user.dir,90), turn(user.dir,270), turn(user.dir,180))) + if(direction in possible_directions) + build_dir = direction + break + else + failed_to_build = 1 + if(failed_to_build) + to_chat(user, "There is no room in this location.") + return 1 + + var/build_path = /obj/structure/windoor_assembly + var/sheets_needed = window_options[choice] + if(choice == "Windoor") + if(is_reinforced()) + build_path = /obj/structure/windoor_assembly/secure + else if(choice == "Full Window") + build_path = created_fulltile_window + else + build_path = created_window + + if(used_stack.get_amount() < sheets_needed) + to_chat(user, "You need at least [sheets_needed] sheets to build this.") + return 1 + + // Build the structure and update sheet count etc. + used_stack.use(sheets_needed) + new build_path(T, build_dir, 1) + return 1 + +/datum/material/glass/proc/is_reinforced() + return (hardness > 35) //todo + +/datum/material/glass/reinforced + name = "rglass" + display_name = "reinforced glass" + stack_type = /obj/item/stack/material/glass/reinforced + flags = MATERIAL_BRITTLE + icon_colour = "#00E1FF" + opacity = 0.3 + integrity = 100 + shard_type = SHARD_SHARD + tableslam_noise = 'sound/effects/Glasshit.ogg' + hardness = 40 + weight = 30 + stack_origin_tech = list(TECH_MATERIAL = 2) + composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "glass" = SHEET_MATERIAL_AMOUNT) + window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2) + created_window = /obj/structure/window/reinforced + created_fulltile_window = /obj/structure/window/reinforced/full + wire_product = null + rod_product = null + +/datum/material/glass/phoron + name = "borosilicate glass" + display_name = "borosilicate glass" + stack_type = /obj/item/stack/material/glass/phoronglass + flags = MATERIAL_BRITTLE + integrity = 100 + icon_colour = "#FC2BC5" + stack_origin_tech = list(TECH_MATERIAL = 4) + window_options = list("One Direction" = 1, "Full Window" = 4) + created_window = /obj/structure/window/phoronbasic + created_fulltile_window = /obj/structure/window/phoronbasic/full + wire_product = null + rod_product = /obj/item/stack/material/glass/phoronrglass + +/datum/material/glass/phoron/reinforced + name = "reinforced borosilicate glass" + display_name = "reinforced borosilicate glass" + stack_type = /obj/item/stack/material/glass/phoronrglass + stack_origin_tech = list(TECH_MATERIAL = 5) + composite_material = list() //todo + window_options = list("One Direction" = 1, "Full Window" = 4) + created_window = /obj/structure/window/phoronreinforced + created_fulltile_window = /obj/structure/window/phoronreinforced/full + hardness = 40 + weight = 30 + stack_origin_tech = list(TECH_MATERIAL = 2) + composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "borosilicate glass" = SHEET_MATERIAL_AMOUNT) + rod_product = null diff --git a/code/modules/materials/materials/holographic.dm b/code/modules/materials/materials/holographic.dm new file mode 100644 index 00000000000..ff6474ec1e7 --- /dev/null +++ b/code/modules/materials/materials/holographic.dm @@ -0,0 +1,17 @@ +/datum/material/steel/holographic + name = "holo" + DEFAULT_WALL_MATERIAL + display_name = DEFAULT_WALL_MATERIAL + stack_type = null + shard_type = SHARD_NONE + +/datum/material/plastic/holographic + name = "holoplastic" + display_name = "plastic" + stack_type = null + shard_type = SHARD_NONE + +/datum/material/wood/holographic + name = "holowood" + display_name = "wood" + stack_type = null + shard_type = SHARD_NONE \ No newline at end of file diff --git a/code/modules/materials/materials/metals/hull.dm b/code/modules/materials/materials/metals/hull.dm new file mode 100644 index 00000000000..caf8f13de74 --- /dev/null +++ b/code/modules/materials/materials/metals/hull.dm @@ -0,0 +1,53 @@ +/datum/material/steel/hull + name = MAT_STEELHULL + stack_type = /obj/item/stack/material/steel/hull + integrity = 250 + explosion_resistance = 10 + icon_base = "hull" + icon_reinf = "reinf_mesh" + icon_colour = "#666677" + +/datum/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets. + new /obj/item/stack/material/steel(target) + +/datum/material/plasteel/hull + name = MAT_PLASTEELHULL + stack_type = /obj/item/stack/material/plasteel/hull + integrity = 600 + icon_base = "hull" + icon_reinf = "reinf_mesh" + icon_colour = "#777788" + explosion_resistance = 40 + +/datum/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. + new /obj/item/stack/material/plasteel(target) + +/datum/material/durasteel/hull //The 'Hardball' of starship hulls. + name = MAT_DURASTEELHULL + stack_type = /obj/item/stack/material/durasteel/hull + icon_base = "hull" + icon_reinf = "reinf_mesh" + icon_colour = "#45829a" + explosion_resistance = 90 + reflectivity = 0.9 + +/datum/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets. + new /obj/item/stack/material/durasteel(target) + +/datum/material/titanium/hull + name = MAT_TITANIUMHULL + stack_type = /obj/item/stack/material/titanium/hull + icon_base = "hull" + icon_reinf = "reinf_mesh" + +/datum/material/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets. + new /obj/item/stack/material/titanium(target) + +/datum/material/morphium/hull + name = MAT_MORPHIUMHULL + stack_type = /obj/item/stack/material/morphium/hull + icon_base = "hull" + icon_reinf = "reinf_mesh" + +/datum/material/morphium/hull/place_sheet(var/turf/target) + new /obj/item/stack/material/morphium(target) \ No newline at end of file diff --git a/code/modules/materials/materials/metals/metals.dm b/code/modules/materials/materials/metals/metals.dm new file mode 100644 index 00000000000..a36ffef5c1c --- /dev/null +++ b/code/modules/materials/materials/metals/metals.dm @@ -0,0 +1,199 @@ + + + + +// Very rare alloy that is reflective, should be used sparingly. +/datum/material/durasteel + name = "durasteel" + stack_type = /obj/item/stack/material/durasteel + integrity = 600 + melting_point = 7000 + icon_base = "metal" + icon_reinf = "reinf_metal" + icon_colour = "#6EA7BE" + explosion_resistance = 75 + hardness = 100 + weight = 28 + protectiveness = 60 // 75% + reflectivity = 0.7 // Not a perfect mirror, but close. + stack_origin_tech = list(TECH_MATERIAL = 8) + composite_material = list("plasteel" = SHEET_MATERIAL_AMOUNT, "diamond" = SHEET_MATERIAL_AMOUNT) //shrug + supply_conversion_value = 9 + +/datum/material/titanium + name = MAT_TITANIUM + stack_type = /obj/item/stack/material/titanium + conductivity = 2.38 + icon_base = "metal" + door_icon_base = "metal" + icon_colour = "#D1E6E3" + icon_reinf = "reinf_metal" + composite_material = null + +/datum/material/iron + name = "iron" + stack_type = /obj/item/stack/material/iron + icon_colour = "#5C5454" + weight = 22 + conductivity = 10 + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + +/datum/material/lead + name = MAT_LEAD + stack_type = /obj/item/stack/material/lead + icon_colour = "#273956" + weight = 23 // Lead is a bit more dense than silver IRL, and silver has 22 ingame. + conductivity = 10 + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + radiation_resistance = 25 // Lead is Special and so gets to block more radiation than it normally would with just weight, totalling in 48 protection. + supply_conversion_value = 2 + +/datum/material/gold + name = "gold" + stack_type = /obj/item/stack/material/gold + icon_colour = "#EDD12F" + weight = 24 + hardness = 40 + conductivity = 41 + stack_origin_tech = list(TECH_MATERIAL = 4) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + supply_conversion_value = 2 + +/datum/material/silver + name = "silver" + stack_type = /obj/item/stack/material/silver + icon_colour = "#D1E6E3" + weight = 22 + hardness = 50 + conductivity = 63 + stack_origin_tech = list(TECH_MATERIAL = 3) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + supply_conversion_value = 2 + +/datum/material/platinum + name = "platinum" + stack_type = /obj/item/stack/material/platinum + icon_colour = "#9999FF" + weight = 27 + conductivity = 9.43 + stack_origin_tech = list(TECH_MATERIAL = 2) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + supply_conversion_value = 5 + +/datum/material/uranium + name = "uranium" + stack_type = /obj/item/stack/material/uranium + radioactivity = 12 + icon_base = "stone" + icon_reinf = "reinf_stone" + icon_colour = "#007A00" + weight = 22 + stack_origin_tech = list(TECH_MATERIAL = 5) + door_icon_base = "stone" + supply_conversion_value = 2 + +/datum/material/mhydrogen + name = "mhydrogen" + stack_type = /obj/item/stack/material/mhydrogen + icon_colour = "#E6C5DE" + stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5) + conductivity = 100 + is_fusion_fuel = 1 + supply_conversion_value = 6 + +/datum/material/deuterium + name = "deuterium" + stack_type = /obj/item/stack/material/deuterium + icon_colour = "#999999" + stack_origin_tech = list(TECH_MATERIAL = 3) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + is_fusion_fuel = 1 + conductive = 0 + +/datum/material/tritium + name = "tritium" + stack_type = /obj/item/stack/material/tritium + icon_colour = "#777777" + stack_origin_tech = list(TECH_MATERIAL = 5) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + is_fusion_fuel = 1 + conductive = 0 + +/datum/material/osmium + name = "osmium" + stack_type = /obj/item/stack/material/osmium + icon_colour = "#9999FF" + stack_origin_tech = list(TECH_MATERIAL = 5) + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + conductivity = 100 + supply_conversion_value = 6 + +/datum/material/graphite + name = MAT_GRAPHITE + stack_type = /obj/item/stack/material/graphite + flags = MATERIAL_BRITTLE + icon_base = "solid" + icon_reinf = "reinf_mesh" + icon_colour = "#333333" + hardness = 75 + weight = 15 + integrity = 175 + protectiveness = 15 + conductivity = 18 + melting_point = T0C+3600 + radiation_resistance = 15 + stack_origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2) + +/datum/material/bronze + name = "bronze" + stack_type = /obj/item/stack/material/bronze + icon_colour = "#EDD12F" + icon_base = "solid" + icon_reinf = "reinf_over" + integrity = 120 + conductivity = 12 + protectiveness = 9 // 33% + +/datum/material/tin + name = "tin" + display_name = "tin" + use_name = "tin" + stack_type = /obj/item/stack/material/tin + icon_colour = "#b2afaf" + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + supply_conversion_value = 1 + hardness = 50 + weight = 13 + +/datum/material/copper + name = "copper" + display_name = "copper" + use_name = "copper" + stack_type = /obj/item/stack/material/copper + conductivity = 52 + icon_colour = "#af633e" + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + supply_conversion_value = 1 + weight = 13 + hardness = 50 + +/datum/material/aluminium + name = "aluminium" + display_name = "aluminium" + use_name = "aluminium" + icon_colour = "#e5e2d0" + stack_type = /obj/item/stack/material/aluminium + sheet_singular_name = "ingot" + sheet_plural_name = "ingots" + supply_conversion_value = 2 + weight = 10 \ No newline at end of file diff --git a/code/modules/materials/materials/metals/plasteel.dm b/code/modules/materials/materials/metals/plasteel.dm new file mode 100644 index 00000000000..6fc7ed29dec --- /dev/null +++ b/code/modules/materials/materials/metals/plasteel.dm @@ -0,0 +1,27 @@ +/datum/material/plasteel + name = "plasteel" + stack_type = /obj/item/stack/material/plasteel + integrity = 400 + melting_point = 6000 + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#777777" + explosion_resistance = 25 + hardness = 80 + weight = 23 + protectiveness = 20 // 50% + conductivity = 13 // For the purposes of balance. + stack_origin_tech = list(TECH_MATERIAL = 2) + composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT, "platinum" = SHEET_MATERIAL_AMOUNT) //todo + supply_conversion_value = 6 + +/datum/material/plasteel/generate_recipes() + ..() + recipes += list( + new /datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1, recycle_material = "[name]"), + new /datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1, recycle_material = "[name]"), + new /datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor/dark, 1, 4, 20, recycle_material = "[name]"), + new /datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]") + ) \ No newline at end of file diff --git a/code/modules/materials/materials/metals/steel.dm b/code/modules/materials/materials/metals/steel.dm new file mode 100644 index 00000000000..606c3e70377 --- /dev/null +++ b/code/modules/materials/materials/metals/steel.dm @@ -0,0 +1,86 @@ +/datum/material/steel + name = DEFAULT_WALL_MATERIAL + stack_type = /obj/item/stack/material/steel + integrity = 150 + conductivity = 11 // Assuming this is carbon steel, it would actually be slightly less conductive than iron, but lets ignore that. + protectiveness = 10 // 33% + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#666666" + +/datum/material/steel/generate_recipes() + ..() + recipes += list( + new /datum/stack_recipe_list("office chairs",list( + new /datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("light office chair", /obj/structure/bed/chair/office/light, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") + )), + new /datum/stack_recipe_list("comfy chairs", list( + new /datum/stack_recipe("beige comfy chair", /obj/structure/bed/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("black comfy chair", /obj/structure/bed/chair/comfy/black, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("brown comfy chair", /obj/structure/bed/chair/comfy/brown, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("lime comfy chair", /obj/structure/bed/chair/comfy/lime, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("teal comfy chair", /obj/structure/bed/chair/comfy/teal, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("red comfy chair", /obj/structure/bed/chair/comfy/red, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("blue comfy chair", /obj/structure/bed/chair/comfy/blue, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("purple comfy chair", /obj/structure/bed/chair/comfy/purp, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("yellow comfy chair", /obj/structure/bed/chair/comfy/yellow, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("orange comfy chair", /obj/structure/bed/chair/comfy/orange, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + )), + new /datum/stack_recipe_list("airlock assemblies", list( + new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("eng atmos airlock assembly", /obj/structure/door_assembly/door_assembly_eat, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("voidcraft airlock assembly horizontal", /obj/structure/door_assembly/door_assembly_voidcraft, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("voidcraft airlock assembly vertical", /obj/structure/door_assembly/door_assembly_voidcraft/vertical, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + )), + new /datum/stack_recipe_list("modular computer frames", list( + new /datum/stack_recipe("modular console frame", /obj/item/modular_computer/console, 20, recycle_material = "[name]"),\ + new /datum/stack_recipe("modular telescreen frame", /obj/item/modular_computer/telescreen, 10, recycle_material = "[name]"),\ + new /datum/stack_recipe("modular laptop frame", /obj/item/modular_computer/laptop, 10, recycle_material = "[name]"),\ + new /datum/stack_recipe("modular tablet frame", /obj/item/modular_computer/tablet, 5, recycle_material = "[name]"),\ + )), + new /datum/stack_recipe_list("filing cabinets", list( + new /datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("tall filing cabinet", /obj/structure/filingcabinet/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("chest drawer", /obj/structure/filingcabinet/chestdrawer, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + )), + new /datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("bench frame", /obj/structure/table/bench, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0, recycle_material = "[name]"), + new /datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20, recycle_material = "[name]"), + new /datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20, recycle_material = "[name]"), + new /datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60, recycle_material = "[name]"), + new /datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("fire extinguisher cabinet frame", /obj/item/frame/extinguisher_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("IV drip", /obj/machinery/iv_drip, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("conveyor switch", /obj/machinery/conveyor_switch, 2, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade, recycle_material = "[name]"), + new /datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2, recycle_material = "[name]"), + new /datum/stack_recipe("small light fixture frame", /obj/item/frame/light/small, 1, recycle_material = "[name]"), + new /datum/stack_recipe("floor lamp fixture frame", /obj/machinery/light_construct/flamp, 2, recycle_material = "[name]"), + new /datum/stack_recipe("apc frame", /obj/item/frame/apc, 2, recycle_material = "[name]"), + new /datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]") + ) \ No newline at end of file diff --git a/code/modules/materials/materials/organic/animal_products.dm b/code/modules/materials/materials/organic/animal_products.dm new file mode 100644 index 00000000000..592cc6bc7bb --- /dev/null +++ b/code/modules/materials/materials/organic/animal_products.dm @@ -0,0 +1,28 @@ +/datum/material/diona + name = "biomass" + icon_colour = null + stack_type = null + integrity = 600 + icon_base = "diona" + icon_reinf = "noreinf" + +/datum/material/diona/place_dismantled_product() + return + +/datum/material/diona/place_dismantled_girder(var/turf/target) + spawn_diona_nymph(target) + +/datum/material/chitin + name = MAT_CHITIN + icon_colour = "#8d6653" + stack_type = /obj/item/stack/material/chitin + stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4) + icon_base = "solid" + icon_reinf = "reinf_mesh" + integrity = 60 + weight = 10 + ignition_point = T0C+400 + melting_point = T0C+500 + protectiveness = 20 + conductive = 0 + supply_conversion_value = 4 diff --git a/code/modules/materials/materials/organic/cloth.dm b/code/modules/materials/materials/organic/cloth.dm new file mode 100644 index 00000000000..588a7ad86fb --- /dev/null +++ b/code/modules/materials/materials/organic/cloth.dm @@ -0,0 +1,121 @@ +/datum/material/cloth + name = "cloth" + stack_origin_tech = list(TECH_MATERIAL = 2) + door_icon_base = "wood" + ignition_point = T0C+232 + melting_point = T0C+300 + protectiveness = 1 // 4% + flags = MATERIAL_PADDING + conductive = 0 + integrity = 40 + pass_stack_colors = TRUE + supply_conversion_value = 2 + +/datum/material/cloth/generate_recipes() + recipes = list( + new /datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]"), + new /datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") + ) + +/datum/material/cloth/syncloth + name = "syncloth" + stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 2) + ignition_point = T0C+532 + melting_point = T0C+600 + integrity = 200 + protectiveness = 15 // 4% + pass_stack_colors = TRUE + supply_conversion_value = 3 + +/datum/material/cloth/teal + name = "teal" + display_name ="teal" + use_name = "teal cloth" + icon_colour = "#00EAFA" + +/datum/material/cloth/black + name = "black" + display_name = "black" + use_name = "black cloth" + icon_colour = "#505050" + +/datum/material/cloth/green + name = "green" + display_name = "green" + use_name = "green cloth" + icon_colour = "#01C608" + +/datum/material/cloth/puple + name = "purple" + display_name = "purple" + use_name = "purple cloth" + icon_colour = "#9C56C4" + +/datum/material/cloth/blue + name = "blue" + display_name = "blue" + use_name = "blue cloth" + icon_colour = "#6B6FE3" + +/datum/material/cloth/beige + name = "beige" + display_name = "beige" + use_name = "beige cloth" + icon_colour = "#E8E7C8" + +/datum/material/cloth/lime + name = "lime" + display_name = "lime" + use_name = "lime cloth" + icon_colour = "#62E36C" + +/datum/material/cloth/yellow + name = "yellow" + display_name = "yellow" + use_name = "yellow cloth" + icon_colour = "#EEF573" + +/datum/material/cloth/orange + name = "orange" + display_name = "orange" + use_name = "orange cloth" + icon_colour = "#E3BF49" + + + +/datum/material/carpet + name = "carpet" + display_name = "comfy" + use_name = "red upholstery" + icon_colour = "#DA020A" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + sheet_singular_name = "tile" + sheet_plural_name = "tiles" + protectiveness = 1 // 4% + conductive = 0 + +/datum/material/cotton + name = "cotton" + display_name ="cotton" + icon_colour = "#FFFFFF" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + protectiveness = 1 // 4% + conductive = 0 \ No newline at end of file diff --git a/code/modules/materials/materials/organic/leather.dm b/code/modules/materials/materials/organic/leather.dm new file mode 100644 index 00000000000..f5fc8cb2f97 --- /dev/null +++ b/code/modules/materials/materials/organic/leather.dm @@ -0,0 +1,37 @@ +/datum/material/leather + name = MAT_LEATHER + display_name = "plainleather" + icon_colour = "#5C4831" + stack_type = /obj/item/stack/material/leather + stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) + flags = MATERIAL_PADDING + ignition_point = T0C+300 + melting_point = T0C+300 + protectiveness = 3 // 13% + conductive = 0 + integrity = 40 + supply_conversion_value = 3 + +/datum/material/leather/generate_recipes() + recipes = list( + new /datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]"), + new /datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") + ) \ No newline at end of file diff --git a/code/modules/materials/materials/organic/resin.dm b/code/modules/materials/materials/organic/resin.dm new file mode 100644 index 00000000000..a42735627aa --- /dev/null +++ b/code/modules/materials/materials/organic/resin.dm @@ -0,0 +1,45 @@ +/datum/material/resin + name = "resin" + icon_colour = "#35343a" + icon_base = "resin" + dooropen_noise = 'sound/effects/attackblob.ogg' + door_icon_base = "resin" + icon_reinf = "reinf_mesh" + melting_point = T0C+300 + sheet_singular_name = "blob" + sheet_plural_name = "blobs" + conductive = 0 + explosion_resistance = 60 + radiation_resistance = 10 + stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_BIO = 7) + stack_type = /obj/item/stack/material/resin + +/datum/material/resin/can_open_material_door(var/mob/living/user) + var/mob/living/carbon/M = user + if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + return TRUE + return FALSE + +/datum/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) + var/mob/living/carbon/M = L + if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + to_chat(M, "\The [W] shudders under your touch, starting to become porous.") + playsound(W, 'sound/effects/attackblob.ogg', 50, 1) + if(do_after(L, 5 SECONDS)) + spawn(2) + playsound(W, 'sound/effects/attackblob.ogg', 100, 1) + W.dismantle_wall() + return TRUE + return FALSE + +/datum/material/resin/generate_recipes() + recipes = list( + new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door/resin, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] barricade", /obj/effect/alien/resin/wall, 5, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("[display_name] nest", /obj/structure/bed/nest, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder/resin, 2, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS, recycle_material = "[name]") + ) \ No newline at end of file diff --git a/code/modules/materials/materials/organic/wood.dm b/code/modules/materials/materials/organic/wood.dm new file mode 100644 index 00000000000..2f44607e8b6 --- /dev/null +++ b/code/modules/materials/materials/organic/wood.dm @@ -0,0 +1,83 @@ +/datum/material/wood + name = MAT_WOOD + stack_type = /obj/item/stack/material/wood + icon_colour = "#9c5930" + integrity = 50 + icon_base = "wood" + explosion_resistance = 2 + shard_type = SHARD_SPLINTER + shard_can_repair = 0 // you can't weld splinters back into planks + hardness = 15 + weight = 18 + protectiveness = 8 // 28% + conductive = 0 + conductivity = 1 + melting_point = T0C+300 //okay, not melting in this case, but hot enough to destroy wood + ignition_point = T0C+288 + stack_origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) + dooropen_noise = 'sound/effects/doorcreaky.ogg' + door_icon_base = "wood" + destruction_desc = "splinters" + sheet_singular_name = "plank" + sheet_plural_name = "planks" + +/datum/material/wood/generate_recipes() + ..() + recipes += list( + new /datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE), + new /datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1, recycle_material = "[name]"), + new /datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]") + ) + +/datum/material/wood/sif + name = MAT_SIFWOOD + stack_type = /obj/item/stack/material/wood/sif + icon_colour = "#0099cc" // Cyan-ish + stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer. + +/datum/material/wood/sif/generate_recipes() + ..() + recipes += new /datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE) + for(var/datum/stack_recipe/r_recipe in recipes) + if(r_recipe.title == "wood floor tile") + recipes -= r_recipe + continue + if(r_recipe.title == "wooden chair") + recipes -= r_recipe + continue + +/datum/material/wood/log + name = MAT_LOG + icon_base = "log" + stack_type = /obj/item/stack/material/log + sheet_singular_name = null + sheet_plural_name = "pile" + pass_stack_colors = TRUE + supply_conversion_value = 1 + +/datum/material/wood/log/generate_recipes() + recipes = list( + new /datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE, recycle_material = "[name]") + ) + +/datum/material/wood/log/sif + name = MAT_SIFLOG + icon_colour = "#0099cc" // Cyan-ish + stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) + stack_type = /obj/item/stack/material/log/sif \ No newline at end of file diff --git a/code/modules/materials/materials/plastic.dm b/code/modules/materials/materials/plastic.dm new file mode 100644 index 00000000000..6cf45fe677e --- /dev/null +++ b/code/modules/materials/materials/plastic.dm @@ -0,0 +1,88 @@ +/datum/material/plastic + name = "plastic" + stack_type = /obj/item/stack/material/plastic + flags = MATERIAL_BRITTLE + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#CCCCCC" + hardness = 10 + weight = 12 + protectiveness = 5 // 20% + conductive = 0 + conductivity = 2 // For the sake of material armor diversity, we're gonna pretend this plastic is a good insulator. + melting_point = T0C+371 //assuming heat resistant plastic + stack_origin_tech = list(TECH_MATERIAL = 3) + +/datum/material/plastic/generate_recipes() + ..() + recipes += list( + new /datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 500u + new /datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 250u + new /datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]"), // 100u + new /datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("shower curtain", /obj/structure/curtain, 4, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 4, time = 25, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("water-cooler", /obj/structure/reagent_dispensers/water_cooler, 4, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS, recycle_material = "[name]"), + new /datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]") + ) + +/datum/material/cardboard + name = "cardboard" + stack_type = /obj/item/stack/material/cardboard + flags = MATERIAL_BRITTLE + integrity = 10 + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#AAAAAA" + hardness = 1 + weight = 1 + protectiveness = 0 // 0% + conductive = 0 + ignition_point = T0C+232 //"the temperature at which book-paper catches fire, and burns." close enough + melting_point = T0C+232 //temperature at which cardboard walls would be destroyed + stack_origin_tech = list(TECH_MATERIAL = 1) + door_icon_base = "wood" + destruction_desc = "crumples" + radiation_resistance = 1 + pass_stack_colors = TRUE + +/datum/material/cardboard/generate_recipes() + ..() + recipes += list( + new /datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("pizza box", /obj/item/pizzabox, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe_list("folders",list( + new /datum/stack_recipe("blue folder", /obj/item/weapon/folder/blue, recycle_material = "[name]"), + new /datum/stack_recipe("grey folder", /obj/item/weapon/folder, recycle_material = "[name]"), + new /datum/stack_recipe("red folder", /obj/item/weapon/folder/red, recycle_material = "[name]"), + new /datum/stack_recipe("white folder", /obj/item/weapon/folder/white, recycle_material = "[name]"), + new /datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow, recycle_material = "[name]") + )) + ) + +/datum/material/toy_foam + name = "foam" + display_name = "foam" + use_name = "foam" + flags = MATERIAL_PADDING + ignition_point = T0C+232 + melting_point = T0C+300 + icon_colour = "#ff9900" + hardness = 1 + weight = 1 + protectiveness = 0 // 0% + conductive = 0 \ No newline at end of file diff --git a/code/modules/materials/materials/snow.dm b/code/modules/materials/materials/snow.dm new file mode 100644 index 00000000000..bd535798118 --- /dev/null +++ b/code/modules/materials/materials/snow.dm @@ -0,0 +1,56 @@ +/datum/material/snow + name = MAT_SNOW + stack_type = /obj/item/stack/material/snow + flags = MATERIAL_BRITTLE + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#FFFFFF" + integrity = 1 + hardness = 1 + weight = 1 + protectiveness = 0 // 0% + stack_origin_tech = list(TECH_MATERIAL = 1) + melting_point = T0C+1 + destruction_desc = "crumples" + sheet_singular_name = "pile" + sheet_plural_name = "pile" //Just a bigger pile + radiation_resistance = 1 + +/datum/material/snow/generate_recipes() + recipes = list( + new /datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10, recycle_material = "[name]"), + new /datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10, recycle_material = "[name]"), + new /datum/stack_recipe("snowman", /obj/structure/snowman, 2, time = 15, recycle_material = "[name]"), + new /datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10, recycle_material = "[name]"), + new /datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20, recycle_material = "[name]") + ) + +/datum/material/snowbrick //only slightly stronger than snow, used to make igloos mostly + name = "packed snow" + flags = MATERIAL_BRITTLE + stack_type = /obj/item/stack/material/snowbrick + icon_base = "stone" + icon_reinf = "reinf_stone" + icon_colour = "#D8FDFF" + integrity = 50 + weight = 2 + hardness = 2 + protectiveness = 0 // 0% + stack_origin_tech = list(TECH_MATERIAL = 1) + melting_point = T0C+1 + destruction_desc = "crumbles" + sheet_singular_name = "brick" + sheet_plural_name = "bricks" + radiation_resistance = 1 + +/datum/material/snowbrick/generate_recipes() + recipes = list( + new /datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]"), + new /datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") + ) \ No newline at end of file diff --git a/code/modules/materials/materials/stone.dm b/code/modules/materials/materials/stone.dm new file mode 100644 index 00000000000..b716fb4c616 --- /dev/null +++ b/code/modules/materials/materials/stone.dm @@ -0,0 +1,35 @@ +/datum/material/stone + name = "sandstone" + stack_type = /obj/item/stack/material/sandstone + icon_base = "stone" + icon_reinf = "reinf_stone" + icon_colour = "#D9C179" + shard_type = SHARD_STONE_PIECE + weight = 22 + hardness = 55 + protectiveness = 5 // 20% + conductive = 0 + conductivity = 5 + door_icon_base = "stone" + sheet_singular_name = "brick" + sheet_plural_name = "bricks" + +/datum/material/stone/generate_recipes() + ..() + recipes += new /datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") + +/datum/material/stone/marble + name = "marble" + icon_colour = "#AAAAAA" + weight = 26 + hardness = 70 + integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system + stack_type = /obj/item/stack/material/marble + supply_conversion_value = 2 + +/datum/material/stone/marble/generate_recipes() + ..() + recipes += list( + new /datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20, recycle_material = "[name]"), + new /datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20, recycle_material = "[name]") + ) \ No newline at end of file diff --git a/code/modules/materials/materials/supermatter.dm b/code/modules/materials/materials/supermatter.dm new file mode 100644 index 00000000000..5ee3b34671c --- /dev/null +++ b/code/modules/materials/materials/supermatter.dm @@ -0,0 +1,23 @@ +//R-UST port +/datum/material/supermatter + name = "supermatter" + icon_colour = "#FFFF00" + stack_type = /obj/item/stack/material/supermatter + shard_type = SHARD_SHARD + radioactivity = 20 + stack_type = null + luminescence = 3 + ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE + icon_base = "stone" + shard_type = SHARD_SHARD + hardness = 30 + door_icon_base = "stone" + sheet_singular_name = "crystal" + sheet_plural_name = "crystals" + is_fusion_fuel = 1 + stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 5, TECH_BLUESPACE = 4) + +/datum/material/supermatter/generate_recipes() + recipes = list( + new /datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1, recycle_material = "[name]") + ) \ No newline at end of file diff --git a/code/modules/materials/sheets/_sheets.dm b/code/modules/materials/sheets/_sheets.dm new file mode 100644 index 00000000000..7572d0e6545 --- /dev/null +++ b/code/modules/materials/sheets/_sheets.dm @@ -0,0 +1,89 @@ +// Stacked resources. They use a material datum for a lot of inherited values. +// If you're adding something here, make sure to add it to fifty_spawner_mats.dm as well +/obj/item/stack/material + force = 5.0 + throwforce = 5 + w_class = ITEMSIZE_NORMAL + throw_speed = 3 + throw_range = 3 + center_of_mass = null + max_amount = 50 + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_material.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_material.dmi', + ) + + var/default_type = DEFAULT_WALL_MATERIAL + var/datum/material/material + var/perunit = SHEET_MATERIAL_AMOUNT + var/apply_colour //temp pending icon rewrite + drop_sound = 'sound/items/drop/axe.ogg' + pickup_sound = 'sound/items/pickup/axe.ogg' + +/obj/item/stack/material/Initialize() + . = ..() + + randpixel_xy() + + if(!default_type) + default_type = DEFAULT_WALL_MATERIAL + material = get_material_by_name("[default_type]") + if(!material) + return INITIALIZE_HINT_QDEL + + recipes = material.get_recipes() + stacktype = material.stack_type + if(islist(material.stack_origin_tech)) + origin_tech = material.stack_origin_tech.Copy() + + if(apply_colour) + color = material.icon_colour + + if(!material.conductive) + flags |= NOCONDUCT + + matter = material.get_matter() + update_strings() + +/obj/item/stack/material/get_material() + return material + +/obj/item/stack/material/proc/update_strings() + // Update from material datum. + singular_name = material.sheet_singular_name + + if(amount>1) + name = "[material.use_name] [material.sheet_plural_name]" + desc = "A stack of [material.use_name] [material.sheet_plural_name]." + gender = PLURAL + else + name = "[material.use_name] [material.sheet_singular_name]" + desc = "A [material.sheet_singular_name] of [material.use_name]." + gender = NEUTER + +/obj/item/stack/material/use(var/used) + . = ..() + update_strings() + return + +/obj/item/stack/material/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified) + var/obj/item/stack/material/M = S + if(!istype(M) || material.name != M.material.name) + return 0 + var/transfer = ..(S,tamount,1) + if(src) update_strings() + if(M) M.update_strings() + return transfer + +/obj/item/stack/material/attack_self(var/mob/user) + if(!material.build_windows(user, src)) + ..() + +/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user) + if(istype(W,/obj/item/stack/cable_coil)) + material.build_wired_product(user, W, src) + return + else if(istype(W, /obj/item/stack/rods)) + material.build_rod_product(user, W, src) + return + return ..() \ No newline at end of file diff --git a/code/modules/materials/sheets/gems.dm b/code/modules/materials/sheets/gems.dm new file mode 100644 index 00000000000..1906da8eab0 --- /dev/null +++ b/code/modules/materials/sheets/gems.dm @@ -0,0 +1,66 @@ +/obj/item/stack/material/phoron + name = "solid phoron" + icon_state = "sheet-phoron" + default_type = "phoron" + no_variants = FALSE + drop_sound = 'sound/items/drop/glass.ogg' + pickup_sound = 'sound/items/pickup/glass.ogg' + +/obj/item/stack/material/diamond + name = "diamond" + icon_state = "sheet-diamond" + default_type = "diamond" + drop_sound = 'sound/items/drop/glass.ogg' + pickup_sound = 'sound/items/pickup/glass.ogg' + +/obj/item/stack/material/painite + name = "painite" + icon_state = "sheet-gem" + singular_name = "painite gem" + default_type = "painite" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/void_opal + name = "void opal" + icon_state = "sheet-void_opal" + singular_name = "void opal" + default_type = "void opal" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/quartz + name = "quartz" + icon_state = "sheet-gem" + singular_name = "quartz gem" + default_type = "quartz" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/valhollide + name = MAT_VALHOLLIDE + icon_state = "sheet-gem" + item_state = "diamond" + default_type = MAT_VALHOLLIDE + no_variants = FALSE + apply_colour = TRUE + +// Particle Smasher and Exotic material. +/obj/item/stack/material/verdantium + name = MAT_VERDANTIUM + icon_state = "sheet-wavy" + item_state = "mhydrogen" + default_type = MAT_VERDANTIUM + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/morphium + name = MAT_MORPHIUM + icon_state = "sheet-wavy" + item_state = "mhydrogen" + default_type = MAT_MORPHIUM + no_variants = FALSE + apply_colour = TRUE + + + diff --git a/code/modules/materials/sheets/glass.dm b/code/modules/materials/sheets/glass.dm new file mode 100644 index 00000000000..bf891347ea0 --- /dev/null +++ b/code/modules/materials/sheets/glass.dm @@ -0,0 +1,33 @@ +/obj/item/stack/material/glass + name = "glass" + icon_state = "sheet-transparent" + default_type = "glass" + no_variants = FALSE + drop_sound = 'sound/items/drop/glass.ogg' + pickup_sound = 'sound/items/pickup/glass.ogg' + apply_colour = TRUE + +/obj/item/stack/material/glass/reinforced + name = "reinforced glass" + icon_state = "sheet-rtransparent" + default_type = "rglass" + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/glass/phoronglass + name = "borosilicate glass" + desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures" + singular_name = "borosilicate glass sheet" + icon_state = "sheet-transparent" + default_type = "borosilicate glass" + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/glass/phoronrglass + name = "reinforced borosilicate glass" + desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures. It is reinforced with few rods." + singular_name = "reinforced borosilicate glass sheet" + icon_state = "sheet-rtransparent" + default_type = "reinforced borosilicate glass" + no_variants = FALSE + apply_colour = TRUE \ No newline at end of file diff --git a/code/modules/materials/sheets/metals/hull.dm b/code/modules/materials/sheets/metals/hull.dm new file mode 100644 index 00000000000..5a6d429f448 --- /dev/null +++ b/code/modules/materials/sheets/metals/hull.dm @@ -0,0 +1,18 @@ +/obj/item/stack/material/steel/hull + name = MAT_STEELHULL + default_type = MAT_STEELHULL + +/obj/item/stack/material/plasteel/hull + name = MAT_PLASTEELHULL + default_type = MAT_PLASTEELHULL + +/obj/item/stack/material/durasteel/hull + name = MAT_DURASTEELHULL + +/obj/item/stack/material/titanium/hull + name = MAT_TITANIUMHULL + default_type = MAT_TITANIUMHULL + +/obj/item/stack/material/morphium/hull + name = MAT_MORPHIUMHULL + default_type = MAT_MORPHIUMHULL \ No newline at end of file diff --git a/code/modules/materials/sheets/metals/metal.dm b/code/modules/materials/sheets/metals/metal.dm new file mode 100644 index 00000000000..bbad559c128 --- /dev/null +++ b/code/modules/materials/sheets/metals/metal.dm @@ -0,0 +1,140 @@ +/obj/item/stack/material/steel + name = DEFAULT_WALL_MATERIAL + icon_state = "sheet-refined" + default_type = DEFAULT_WALL_MATERIAL + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/plasteel + name = "plasteel" + icon_state = "sheet-reinforced" + default_type = "plasteel" + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/durasteel + name = "durasteel" + icon_state = "sheet-reinforced" + item_state = "sheet-metal" + default_type = "durasteel" + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/titanium + name = MAT_TITANIUM + icon_state = "sheet-refined" + apply_colour = TRUE + item_state = "sheet-silver" + default_type = MAT_TITANIUM + no_variants = FALSE + +/obj/item/stack/material/iron + name = "iron" + icon_state = "sheet-ingot" + default_type = "iron" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/lead + name = "lead" + icon_state = "sheet-ingot" + default_type = "lead" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/gold + name = "gold" + icon_state = "sheet-ingot" + default_type = "gold" + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/silver + name = "silver" + icon_state = "sheet-ingot" + default_type = "silver" + no_variants = FALSE + apply_colour = TRUE + +//Valuable resource, cargo can sell it. +/obj/item/stack/material/platinum + name = "platinum" + icon_state = "sheet-adamantine" + default_type = "platinum" + no_variants = FALSE + apply_colour = TRUE + +/obj/item/stack/material/uranium + name = "uranium" + icon_state = "sheet-uranium" + default_type = "uranium" + no_variants = FALSE + +//Extremely valuable to Research. +/obj/item/stack/material/mhydrogen + name = "metallic hydrogen" + icon_state = "sheet-mythril" + default_type = "mhydrogen" + no_variants = FALSE + +// Fusion fuel. +/obj/item/stack/material/deuterium + name = "deuterium" + icon_state = "sheet-puck" + default_type = "deuterium" + apply_colour = 1 + no_variants = FALSE + +//Fuel for MRSPACMAN generator. +/obj/item/stack/material/tritium + name = "tritium" + icon_state = "sheet-puck" + default_type = "tritium" + apply_colour = TRUE + no_variants = FALSE + +/obj/item/stack/material/osmium + name = "osmium" + icon_state = "sheet-ingot" + default_type = "osmium" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/graphite + name = "graphite" + icon_state = "sheet-puck" + default_type = MAT_GRAPHITE + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/bronze + name = "bronze" + icon_state = "sheet-ingot" + singular_name = "bronze ingot" + default_type = "bronze" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/tin + name = "tin" + icon_state = "sheet-ingot" + singular_name = "tin ingot" + default_type = "tin" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/copper + name = "copper" + icon_state = "sheet-ingot" + singular_name = "copper ingot" + default_type = "copper" + apply_colour = 1 + no_variants = FALSE + +/obj/item/stack/material/aluminium + name = "aluminium" + icon_state = "sheet-ingot" + singular_name = "aluminium ingot" + default_type = "aluminium" + apply_colour = 1 + no_variants = FALSE diff --git a/code/game/objects/items/stacks/rods.dm b/code/modules/materials/sheets/metals/rods.dm similarity index 96% rename from code/game/objects/items/stacks/rods.dm rename to code/modules/materials/sheets/metals/rods.dm index 9844ae1cba9..d1c4a1ee240 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/modules/materials/sheets/metals/rods.dm @@ -1,109 +1,109 @@ -/obj/item/stack/rods - name = "metal rod" - desc = "Some rods. Can be used for building, or something." - singular_name = "metal rod" - icon_state = "rods" - w_class = ITEMSIZE_NORMAL - force = 9.0 - throwforce = 15.0 - throw_speed = 5 - throw_range = 20 - drop_sound = 'sound/items/drop/metalweapon.ogg' - pickup_sound = 'sound/items/pickup/metalweapon.ogg' - matter = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2) - max_amount = 60 - attack_verb = list("hit", "bludgeoned", "whacked") - - color = "#666666" - -/obj/item/stack/rods/cyborg - name = "metal rod synthesizer" - desc = "A device that makes metal rods." - gender = NEUTER - matter = null - uses_charge = 1 - charge_costs = list(500) - stacktype = /obj/item/stack/rods - no_variants = TRUE - -/obj/item/stack/rods/Initialize() - . = ..() - recipes = rods_recipes - update_icon() - -/obj/item/stack/rods/update_icon() - var/amount = get_amount() - if((amount <= 5) && (amount > 0)) - icon_state = "rods-[amount]" - else - icon_state = "rods" - -var/global/list/datum/stack_recipe/rods_recipes = list( \ - new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 0), - new/datum/stack_recipe("catwalk", /obj/structure/catwalk, 2, time = 80, one_per_turf = 1, on_floor = 1)) - -/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob) - if (istype(W, /obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = W - - if(get_amount() < 2) - to_chat(user, "You need at least two rods to do this.") - return - - if(WT.remove_fuel(0,user)) - var/obj/item/stack/material/steel/new_item = new(usr.loc) - new_item.add_to_stacks(usr) - for (var/mob/M in viewers(src)) - M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2) - var/obj/item/stack/rods/R = src - src = null - var/replace = (user.get_inactive_hand()==R) - R.use(2) - if (!R && replace) - user.put_in_hands(new_item) - return - - if (istype(W, /obj/item/weapon/tape_roll)) - var/obj/item/stack/medical/splint/ghetto/new_splint = new(get_turf(user)) - new_splint.add_fingerprint(user) - - user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \ - "You use make \a [new_splint] out of a [singular_name].") - src.use(1) - return - - ..() - -/* -/obj/item/stack/rods/attack_self(mob/user as mob) - src.add_fingerprint(user) - - if(!istype(user.loc,/turf)) return 0 - - if (locate(/obj/structure/grille, usr.loc)) - for(var/obj/structure/grille/G in usr.loc) - if (G.destroyed) - G.health = 10 - G.density = 1 - G.destroyed = 0 - G.icon_state = "grille" - use(1) - else - return 1 - - else if(!in_use) - if(get_amount() < 2) - to_chat(user, "You need at least two rods to do this.") - return - to_chat(usr, "Assembling grille...") - in_use = 1 - if (!do_after(usr, 10)) - in_use = 0 - return - var/obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc ) - to_chat(usr, "You assemble a grille") - in_use = 0 - F.add_fingerprint(usr) - use(2) - return +/obj/item/stack/rods + name = "metal rod" + desc = "Some rods. Can be used for building, or something." + singular_name = "metal rod" + icon_state = "rods" + w_class = ITEMSIZE_NORMAL + force = 9.0 + throwforce = 15.0 + throw_speed = 5 + throw_range = 20 + drop_sound = 'sound/items/drop/metalweapon.ogg' + pickup_sound = 'sound/items/pickup/metalweapon.ogg' + matter = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2) + max_amount = 60 + attack_verb = list("hit", "bludgeoned", "whacked") + + color = "#666666" + +/obj/item/stack/rods/cyborg + name = "metal rod synthesizer" + desc = "A device that makes metal rods." + gender = NEUTER + matter = null + uses_charge = 1 + charge_costs = list(500) + stacktype = /obj/item/stack/rods + no_variants = TRUE + +/obj/item/stack/rods/Initialize() + . = ..() + recipes = rods_recipes + update_icon() + +/obj/item/stack/rods/update_icon() + var/amount = get_amount() + if((amount <= 5) && (amount > 0)) + icon_state = "rods-[amount]" + else + icon_state = "rods" + +var/global/list/datum/stack_recipe/rods_recipes = list( \ + new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 0), + new/datum/stack_recipe("catwalk", /obj/structure/catwalk, 2, time = 80, one_per_turf = 1, on_floor = 1)) + +/obj/item/stack/rods/attackby(obj/item/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(get_amount() < 2) + to_chat(user, "You need at least two rods to do this.") + return + + if(WT.remove_fuel(0,user)) + var/obj/item/stack/material/steel/new_item = new(usr.loc) + new_item.add_to_stacks(usr) + for (var/mob/M in viewers(src)) + M.show_message("[src] is shaped into metal by [user.name] with the weldingtool.", 3, "You hear welding.", 2) + var/obj/item/stack/rods/R = src + src = null + var/replace = (user.get_inactive_hand()==R) + R.use(2) + if (!R && replace) + user.put_in_hands(new_item) + return + + if (istype(W, /obj/item/weapon/tape_roll)) + var/obj/item/stack/medical/splint/ghetto/new_splint = new(get_turf(user)) + new_splint.add_fingerprint(user) + + user.visible_message("\The [user] constructs \a [new_splint] out of a [singular_name].", \ + "You use make \a [new_splint] out of a [singular_name].") + src.use(1) + return + + ..() + +/* +/obj/item/stack/rods/attack_self(mob/user as mob) + src.add_fingerprint(user) + + if(!istype(user.loc,/turf)) return 0 + + if (locate(/obj/structure/grille, usr.loc)) + for(var/obj/structure/grille/G in usr.loc) + if (G.destroyed) + G.health = 10 + G.density = 1 + G.destroyed = 0 + G.icon_state = "grille" + use(1) + else + return 1 + + else if(!in_use) + if(get_amount() < 2) + to_chat(user, "You need at least two rods to do this.") + return + to_chat(usr, "Assembling grille...") + in_use = 1 + if (!do_after(usr, 10)) + in_use = 0 + return + var/obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc ) + to_chat(usr, "You assemble a grille") + in_use = 0 + F.add_fingerprint(usr) + use(2) + return */ \ No newline at end of file diff --git a/code/modules/materials/sheets/organic/animal_products.dm b/code/modules/materials/sheets/organic/animal_products.dm new file mode 100644 index 00000000000..4620da5ea9c --- /dev/null +++ b/code/modules/materials/sheets/organic/animal_products.dm @@ -0,0 +1,31 @@ +/obj/item/stack/material/chitin + name = "chitin" + desc = "The by-product of mob grinding." + icon_state = "chitin" + default_type = MAT_CHITIN + no_variants = FALSE + pass_color = TRUE + strict_color_stacking = TRUE + drop_sound = 'sound/items/drop/leather.ogg' + pickup_sound = 'sound/items/pickup/leather.ogg' + +//don't see anywhere else to put these, maybe together they could be used to make the xenos suit? +/obj/item/stack/xenochitin + name = "alien chitin" + desc = "A piece of the hide of a terrible creature." + singular_name = "alien chitin piece" + icon = 'icons/mob/alien.dmi' + icon_state = "chitin" + stacktype = "hide-chitin" + +/obj/item/xenos_claw + name = "alien claw" + desc = "The claw of a terrible creature." + icon = 'icons/mob/alien.dmi' + icon_state = "claw" + +/obj/item/weed_extract + name = "weed extract" + desc = "A piece of slimy, purplish weed." + icon = 'icons/mob/alien.dmi' + icon_state = "weed_extract" \ No newline at end of file diff --git a/code/modules/materials/sheets/organic/resin.dm b/code/modules/materials/sheets/organic/resin.dm new file mode 100644 index 00000000000..7120911f2d5 --- /dev/null +++ b/code/modules/materials/sheets/organic/resin.dm @@ -0,0 +1,8 @@ +/obj/item/stack/material/resin + name = "resin" + icon_state = "sheet-resin" + default_type = "resin" + no_variants = TRUE + apply_colour = TRUE + pass_color = TRUE + strict_color_stacking = TRUE \ No newline at end of file diff --git a/code/modules/materials/sheets/organic/tanning/hide.dm b/code/modules/materials/sheets/organic/tanning/hide.dm new file mode 100644 index 00000000000..a8b229c9eba --- /dev/null +++ b/code/modules/materials/sheets/organic/tanning/hide.dm @@ -0,0 +1,90 @@ +/obj/item/stack/animalhide + name = "hide" + desc = "The hide of some creature." + description_info = "Use something sharp, like a knife, to scrape the hairs/feathers/etc off this hide to prepare it for tanning." + icon_state = "sheet-hide" + drop_sound = 'sound/items/drop/cloth.ogg' + pickup_sound = 'sound/items/pickup/cloth.ogg' + amount = 1 + max_amount = 20 + stacktype = "hide" + no_variants = TRUE +// This needs to be very clearly documented for players. Whether it should stay in the main description is up for debate. +/obj/item/stack/animalhide/examine(var/mob/user) + . = ..() + . += description_info + +//Step one - dehairing. +/obj/item/stack/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(has_edge(W) || is_sharp(W)) + //visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message) + user.visible_message("\The [user] starts cutting hair off \the [src]", "You start cutting the hair off \the [src]", "You hear the sound of a knife rubbing against flesh") + var/scraped = 0 + while(amount > 0 && do_after(user, 2.5 SECONDS)) // 2.5s per hide + //Try locating an exisitng stack on the tile and add to there if possible + var/obj/item/stack/hairlesshide/H = null + for(var/obj/item/stack/hairlesshide/HS in user.loc) // Could be scraping something inside a locker, hence the .loc, not get_turf + if(HS.amount < HS.max_amount) + H = HS + break + + // Either we found a valid stack, in which case increment amount, + // Or we need to make a new stack + if(istype(H)) + H.amount++ + else + H = new /obj/item/stack/hairlesshide(user.loc) + + // Increment the amount + src.use(1) + scraped++ + + if(scraped) + to_chat(user, SPAN_NOTICE("You scrape the hair off [scraped] hide\s.")) + else + ..() + +/obj/item/stack/animalhide/human + name = "skin" + desc = "The by-product of sapient farming." + singular_name = "skin piece" + icon_state = "sheet-hide" + no_variants = FALSE + drop_sound = 'sound/items/drop/leather.ogg' + pickup_sound = 'sound/items/pickup/leather.ogg' + stacktype = "hide-human" + +/obj/item/stack/animalhide/corgi + name = "corgi hide" + desc = "The by-product of corgi farming." + singular_name = "corgi hide piece" + icon_state = "sheet-corgi" + stacktype = "hide-corgi" + +/obj/item/stack/animalhide/cat + name = "cat hide" + desc = "The by-product of cat farming." + singular_name = "cat hide piece" + icon_state = "sheet-cat" + stacktype = "hide-cat" + +/obj/item/stack/animalhide/monkey + name = "monkey hide" + desc = "The by-product of monkey farming." + singular_name = "monkey hide piece" + icon_state = "sheet-monkey" + stacktype = "hide-monkey" + +/obj/item/stack/animalhide/lizard + name = "lizard skin" + desc = "Sssssss..." + singular_name = "lizard skin piece" + icon_state = "sheet-lizard" + stacktype = "hide-lizard" + +/obj/item/stack/animalhide/xeno + name = "alien hide" + desc = "The skin of a terrible creature." + singular_name = "alien hide piece" + icon_state = "sheet-xeno" + stacktype = "hide-xeno" \ No newline at end of file diff --git a/code/modules/materials/sheets/organic/tanning/hide_hairless.dm b/code/modules/materials/sheets/organic/tanning/hide_hairless.dm new file mode 100644 index 00000000000..72b235e415d --- /dev/null +++ b/code/modules/materials/sheets/organic/tanning/hide_hairless.dm @@ -0,0 +1,48 @@ +//Step two - washing..... it's actually in washing machine code, and ere. + +/obj/item/stack/hairlesshide + name = "hairless hide" + desc = "This hide was stripped of it's hair, but still needs tanning." + description_info = "Get it wet to continue tanning this into leather.
\ + You could set it in a river, wash it with a sink, or just splash water on it with a bucket." + singular_name = "hairless hide piece" + icon_state = "sheet-hairlesshide" + no_variants = FALSE + max_amount = 20 + stacktype = "hairlesshide" + +/obj/item/stack/hairlesshide/examine(var/mob/user) + . = ..() + . += description_info + +/obj/item/stack/hairlesshide/water_act(var/wateramount) + . = ..() + wateramount = min(amount, round(wateramount)) + for(var/i in 1 to wateramount) + var/obj/item/stack/wetleather/H = null + for(var/obj/item/stack/wetleather/HS in get_turf(src)) // Doesn't have a user, can't just use their loc + if(HS.amount < HS.max_amount) + H = HS + break + + // Either we found a valid stack, in which case increment amount, + // Or we need to make a new stack + if(istype(H)) + H.amount++ + else + H = new /obj/item/stack/wetleather(get_turf(src)) + + // Increment the amount + src.use(1) + +/obj/item/stack/hairlesshide/proc/rapidcure(var/stacknum = 1) + stacknum = min(stacknum, amount) + + while(stacknum) + var/obj/item/stack/wetleather/I = new /obj/item/stack/wetleather(get_turf(src)) + + if(istype(I)) + I.dry() + + use(1) + stacknum -= 1 \ No newline at end of file diff --git a/code/modules/materials/sheets/organic/tanning/leather_wet.dm b/code/modules/materials/sheets/organic/tanning/leather_wet.dm new file mode 100644 index 00000000000..64f672512ce --- /dev/null +++ b/code/modules/materials/sheets/organic/tanning/leather_wet.dm @@ -0,0 +1,51 @@ +//Step three - drying +/obj/item/stack/wetleather + name = "wet leather" + desc = "This leather has been cleaned but still needs to be dried." + description_info = "To finish tanning the leather, you need to dry it. \ + You could place it under a fire, \ + put it in a drying rack, \ + or build a tanning rack from steel or wooden boards." + singular_name = "wet leather piece" + icon_state = "sheet-wetleather" + var/wetness = 30 //Reduced when exposed to high temperautres + var/drying_threshold_temperature = 500 //Kelvin to start drying + no_variants = FALSE + max_amount = 20 + stacktype = "wetleather" + + var/dry_type = /obj/item/stack/material/leather + +/obj/item/stack/wetleather/examine(var/mob/user) + . = ..() + . += description_info + . += "\The [src] is [get_dryness_text()]." + +/obj/item/stack/wetleather/proc/get_dryness_text() + if(wetness > 20) + return "wet" + if(wetness > 10) + return "damp" + if(wetness) + return "almost dry" + return "dry" + +/obj/item/stack/wetleather/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + ..() + if(exposed_temperature >= drying_threshold_temperature) + wetness-- + if(wetness == 0) + dry() + +/obj/item/stack/wetleather/proc/dry() + var/obj/item/stack/material/leather/L = new(src.loc) + L.amount = amount + use(amount) + return L + +/obj/item/stack/wetleather/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified) + . = ..() + if(.) // If it transfers any, do a weighted average of the wetness + var/obj/item/stack/wetleather/W = S + var/oldamt = W.amount - . + W.wetness = round(((oldamt * W.wetness) + (. * wetness)) / W.amount) diff --git a/code/modules/materials/sheets/organic/tanning/tanning_rack.dm b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm new file mode 100644 index 00000000000..96d70d90967 --- /dev/null +++ b/code/modules/materials/sheets/organic/tanning/tanning_rack.dm @@ -0,0 +1,70 @@ +/obj/structure/tanning_rack + name = "tanning rack" + desc = "A rack used to stretch leather out and hold it taut during the tanning process." + icon = 'icons/obj/kitchen.dmi' + icon_state = "spike" + + var/obj/item/stack/wetleather/drying = null + +/obj/structure/tanning_rack/Initialize() + . = ..() + START_PROCESSING(SSobj, src) // SSObj fires ~every 2s , starting from wetness 30 takes ~1m + +/obj/structure/tanning_rack/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/structure/tanning_rack/process() + if(drying && drying.wetness) + drying.wetness = max(drying.wetness - 1, 0) + if(!drying.wetness) + visible_message("The [drying] is dry!") + update_icon() + +/obj/structure/tanning_rack/examine(var/mob/user) + . = ..() + if(drying) + . += "\The [drying] is [drying.get_dryness_text()]." + +/obj/structure/tanning_rack/update_icon() + overlays.Cut() + if(drying) + var/image/I + if(drying.wetness) + I = image(icon, "leather_wet") + else + I = image(icon, "leather_dry") + add_overlay(I) + +/obj/structure/tanning_rack/attackby(var/atom/A, var/mob/user) + if(istype(A, /obj/item/stack/wetleather)) + if(!drying) // If not drying anything, start drying the thing + if(user.unEquip(A, target = src)) + drying = A + else // Drying something, add if possible + var/obj/item/stack/wetleather/W = A + W.transfer_to(drying, W.amount, TRUE) + update_icon() + return TRUE + return ..() + +/obj/structure/tanning_rack/attack_hand(var/mob/user) + if(drying) + var/obj/item/stack/S = drying + if(!drying.wetness) // If it's dry, make a stack of dry leather and prepare to put that in their hands + var/obj/item/stack/material/leather/L = new(src) + L.amount = drying.amount + drying.use(drying.amount) + S = L + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(!H.put_in_any_hand_if_possible(S)) + S.forceMove(get_turf(src)) + else + S.forceMove(get_turf(src)) + drying = null + update_icon() + +/obj/structure/tanning_rack/attack_robot(var/mob/user) + attack_hand(user) // That has checks to \ No newline at end of file diff --git a/code/modules/materials/sheets/organic/textiles.dm b/code/modules/materials/sheets/organic/textiles.dm new file mode 100644 index 00000000000..a534ee19b1c --- /dev/null +++ b/code/modules/materials/sheets/organic/textiles.dm @@ -0,0 +1,23 @@ +/obj/item/stack/material/leather + name = "leather" + desc = "The by-product of mob grinding." + icon_state = "sheet-leather" + default_type = MAT_LEATHER + no_variants = FALSE + pass_color = TRUE + strict_color_stacking = TRUE + drop_sound = 'sound/items/drop/leather.ogg' + pickup_sound = 'sound/items/pickup/leather.ogg' + +/obj/item/stack/material/cloth + name = "cloth" + icon_state = "sheet-cloth" + default_type = "cloth" + no_variants = FALSE + pass_color = TRUE + strict_color_stacking = TRUE + drop_sound = 'sound/items/drop/clothing.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' + +/obj/item/stack/material/cloth/diyaab + color = "#c6ccf0" diff --git a/code/modules/materials/sheets/organic/wood.dm b/code/modules/materials/sheets/organic/wood.dm new file mode 100644 index 00000000000..d3d1fd6418e --- /dev/null +++ b/code/modules/materials/sheets/organic/wood.dm @@ -0,0 +1,55 @@ +/obj/item/stack/material/wood + name = "wooden plank" + icon_state = "sheet-wood" + default_type = MAT_WOOD + strict_color_stacking = TRUE + apply_colour = 1 + drop_sound = 'sound/items/drop/wooden.ogg' + pickup_sound = 'sound/items/pickup/wooden.ogg' + no_variants = FALSE + +/obj/item/stack/material/wood/sif + name = "alien wooden plank" + color = "#0099cc" + default_type = MAT_SIFWOOD + +/obj/item/stack/material/log + name = "log" + icon_state = "sheet-log" + default_type = MAT_LOG + no_variants = FALSE + color = "#824B28" + max_amount = 25 + w_class = ITEMSIZE_HUGE + description_info = "Use inhand to craft things, or use a sharp and edged object on this to convert it into two wooden planks." + var/plank_type = /obj/item/stack/material/wood + drop_sound = 'sound/items/drop/wooden.ogg' + pickup_sound = 'sound/items/pickup/wooden.ogg' + +/obj/item/stack/material/log/sif + name = "alien log" + default_type = MAT_SIFLOG + color = "#0099cc" + plank_type = /obj/item/stack/material/wood/sif + +/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user) + if(!istype(W) || W.force <= 0) + return ..() + if(W.sharp && W.edge) + var/time = (3 SECONDS / max(W.force / 10, 1)) * W.toolspeed + user.setClickCooldown(time) + if(do_after(user, time, src) && use(1)) + to_chat(user, "You cut up a log into planks.") + playsound(src, 'sound/effects/woodcutting.ogg', 50, 1) + var/obj/item/stack/material/wood/existing_wood = null + for(var/obj/item/stack/material/wood/M in user.loc) + if(M.material.name == src.material.name) + existing_wood = M + break + + var/obj/item/stack/material/wood/new_wood = new plank_type(user.loc) + new_wood.amount = 2 + if(existing_wood && new_wood.transfer_to(existing_wood)) + to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.") + else + return ..() diff --git a/code/modules/materials/sheets/plastic.dm b/code/modules/materials/sheets/plastic.dm new file mode 100644 index 00000000000..41415af606a --- /dev/null +++ b/code/modules/materials/sheets/plastic.dm @@ -0,0 +1,15 @@ +/obj/item/stack/material/plastic + name = "plastic" + icon_state = "sheet-plastic" + default_type = "plastic" + no_variants = FALSE + +/obj/item/stack/material/cardboard + name = "cardboard" + icon_state = "sheet-card" + default_type = "cardboard" + no_variants = FALSE + pass_color = TRUE + strict_color_stacking = TRUE + drop_sound = 'sound/items/drop/cardboardbox.ogg' + pickup_sound = 'sound/items/pickup/cardboardbox.ogg' diff --git a/code/modules/materials/sheets/snow.dm b/code/modules/materials/sheets/snow.dm new file mode 100644 index 00000000000..7ecc4c4e64d --- /dev/null +++ b/code/modules/materials/sheets/snow.dm @@ -0,0 +1,16 @@ +// Ok, technically not stones, but the snowbrick's function is similar to sandstone and marble +/obj/item/stack/material/snow + name = "snow" + desc = "The temptation to build a snowman rises." + icon_state = "sheet-snow" + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' + default_type = "snow" + +/obj/item/stack/material/snowbrick + name = "snow brick" + desc = "For all of your igloo building needs." + icon_state = "sheet-snowbrick" + default_type = "packed snow" + drop_sound = 'sound/items/drop/gloves.ogg' + pickup_sound = 'sound/items/pickup/clothing.ogg' \ No newline at end of file diff --git a/code/modules/materials/sheets/stone.dm b/code/modules/materials/sheets/stone.dm new file mode 100644 index 00000000000..17347ff9d8f --- /dev/null +++ b/code/modules/materials/sheets/stone.dm @@ -0,0 +1,15 @@ +/obj/item/stack/material/sandstone + name = "sandstone brick" + icon_state = "sheet-sandstone" + default_type = "sandstone" + no_variants = FALSE + drop_sound = 'sound/items/drop/boots.ogg' + pickup_sound = 'sound/items/pickup/boots.ogg' + +/obj/item/stack/material/marble + name = "marble brick" + icon_state = "sheet-marble" + default_type = "marble" + no_variants = FALSE + drop_sound = 'sound/items/drop/boots.ogg' + pickup_sound = 'sound/items/pickup/boots.ogg' diff --git a/code/modules/materials/sheets/supermatter.dm b/code/modules/materials/sheets/supermatter.dm new file mode 100644 index 00000000000..c56f2980881 --- /dev/null +++ b/code/modules/materials/sheets/supermatter.dm @@ -0,0 +1,55 @@ +// Forged in the equivalent of Hell, one piece at a time. +/obj/item/stack/material/supermatter + name = MAT_SUPERMATTER + icon_state = "sheet-super" + item_state = "diamond" + default_type = MAT_SUPERMATTER + apply_colour = TRUE + +/obj/item/stack/material/supermatter/proc/update_mass() // Due to how dangerous they can be, the item will get heavier and larger the more are in the stack. + slowdown = amount / 10 + w_class = min(5, round(amount / 10) + 1) + throw_range = round(amount / 7) + 1 + +/obj/item/stack/material/supermatter/use(var/used) + . = ..() + update_mass() + return + +/obj/item/stack/material/supermatter/attack_hand(mob/user) + . = ..() + + update_mass() + SSradiation.radiate(src, 5 + amount) + var/mob/living/M = user + if(!istype(M)) + return + + var/burn_user = TRUE + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + var/obj/item/clothing/gloves/G = H.gloves + if(istype(G) && ((G.flags & THICKMATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets))) + burn_user = FALSE + + if(burn_user) + H.visible_message("\The [src] flashes as it scorches [H]'s hands!") + H.apply_damage(amount / 2 + 5, BURN, "r_hand", used_weapon="Supermatter Chunk") + H.apply_damage(amount / 2 + 5, BURN, "l_hand", used_weapon="Supermatter Chunk") + H.drop_from_inventory(src, get_turf(H)) + return + + if(istype(user, /mob/living/silicon/robot)) + burn_user = FALSE + + if(burn_user) + M.apply_damage(amount, BURN, null, used_weapon="Supermatter Chunk") + +/obj/item/stack/material/supermatter/ex_act(severity) // An incredibly hard to manufacture material, SM chunks are unstable by their 'stabilized' nature. + if(prob((4 / severity) * 20)) + SSradiation.radiate(get_turf(src), amount * 4) + explosion(get_turf(src),round(amount / 12) , round(amount / 6), round(amount / 3), round(amount / 25)) + qdel(src) + return + SSradiation.radiate(get_turf(src), amount * 2) + ..() \ No newline at end of file diff --git a/code/modules/mining/machine_input_output_plates.dm b/code/modules/mining/machinery/machine_input_output_plates.dm similarity index 90% rename from code/modules/mining/machine_input_output_plates.dm rename to code/modules/mining/machinery/machine_input_output_plates.dm index d8693a1316b..0e7680e6728 100644 --- a/code/modules/mining/machine_input_output_plates.dm +++ b/code/modules/mining/machinery/machine_input_output_plates.dm @@ -1,19 +1,19 @@ -/**********************Input and output plates**************************/ - -/obj/machinery/mineral/input - icon = 'icons/mob/screen1.dmi' - icon_state = "x2" - name = "Input area" - density = 0 - anchored = 1.0 - New() - icon_state = "blank" - -/obj/machinery/mineral/output - icon = 'icons/mob/screen1.dmi' - icon_state = "x" - name = "Output area" - density = 0 - anchored = 1.0 - New() +/**********************Input and output plates**************************/ + +/obj/machinery/mineral/input + icon = 'icons/mob/screen1.dmi' + icon_state = "x2" + name = "Input area" + density = 0 + anchored = 1.0 + New() + icon_state = "blank" + +/obj/machinery/mineral/output + icon = 'icons/mob/screen1.dmi' + icon_state = "x" + name = "Output area" + density = 0 + anchored = 1.0 + New() icon_state = "blank" \ No newline at end of file diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machinery/machine_processing.dm similarity index 100% rename from code/modules/mining/machine_processing.dm rename to code/modules/mining/machinery/machine_processing.dm diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machinery/machine_stacking.dm similarity index 100% rename from code/modules/mining/machine_stacking.dm rename to code/modules/mining/machinery/machine_stacking.dm diff --git a/code/modules/mining/machine_unloading.dm b/code/modules/mining/machinery/machine_unloading.dm similarity index 100% rename from code/modules/mining/machine_unloading.dm rename to code/modules/mining/machinery/machine_unloading.dm diff --git a/vorestation.dme b/vorestation.dme index 8792701170f..3c3e174c25e 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -55,6 +55,7 @@ #include "code\__defines\lighting_vr.dm" #include "code\__defines\machinery.dm" #include "code\__defines\map.dm" +#include "code\__defines\materials.dm" #include "code\__defines\math.dm" #include "code\__defines\math_physics.dm" #include "code\__defines\MC.dm" @@ -852,10 +853,13 @@ #include "code\game\machinery\teleporter.dm" #include "code\game\machinery\transportpod.dm" #include "code\game\machinery\turret_control.dm" +<<<<<<< HEAD:vorestation.dme #include "code\game\machinery\vending.dm" #include "code\game\machinery\vending_machines.dm" #include "code\game\machinery\vending_machines_vr.dm" #include "code\game\machinery\vitals_monitor.dm" +======= +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\game\machinery\wall_frames.dm" #include "code\game\machinery\washing_machine.dm" #include "code\game\machinery\wishgranter.dm" @@ -1197,20 +1201,25 @@ #include "code\game\objects\items\robot\robot_items.dm" #include "code\game\objects\items\robot\robot_parts.dm" #include "code\game\objects\items\robot\robot_upgrades.dm" +<<<<<<< HEAD:vorestation.dme #include "code\game\objects\items\robot\robot_upgrades_vr.dm" #include "code\game\objects\items\stacks\fifty_spawner.dm" +======= +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\game\objects\items\stacks\marker_beacons.dm" #include "code\game\objects\items\stacks\matter_synth.dm" #include "code\game\objects\items\stacks\medical.dm" #include "code\game\objects\items\stacks\medical_vr.dm" #include "code\game\objects\items\stacks\nanopaste.dm" +<<<<<<< HEAD:vorestation.dme #include "code\game\objects\items\stacks\nanopaste_vr.dm" #include "code\game\objects\items\stacks\rods.dm" +======= +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\game\objects\items\stacks\sandbags.dm" #include "code\game\objects\items\stacks\stack.dm" #include "code\game\objects\items\stacks\telecrystal.dm" #include "code\game\objects\items\stacks\tickets.dm" -#include "code\game\objects\items\stacks\sheets\leather.dm" #include "code\game\objects\items\stacks\tiles\fifty_spawner_tiles.dm" #include "code\game\objects\items\stacks\tiles\tile_types.dm" #include "code\game\objects\items\toys\balls_vr.dm" @@ -2060,16 +2069,42 @@ #include "code\modules\economy\ATM.dm" #include "code\modules\economy\cash.dm" #include "code\modules\economy\cash_register.dm" +#include "code\modules\economy\coins.dm" #include "code\modules\economy\economy_misc.dm" #include "code\modules\economy\EFTPOS.dm" #include "code\modules\economy\Events.dm" #include "code\modules\economy\Events_Mundane.dm" #include "code\modules\economy\lorenews.dm" +#include "code\modules\economy\mint.dm" +#include "code\modules\economy\money_bag.dm" #include "code\modules\economy\price_list.dm" #include "code\modules\economy\retail_scanner.dm" #include "code\modules\economy\TradeDestinations.dm" +<<<<<<< HEAD:vorestation.dme #include "code\modules\entopics_vr\alternate_appearance.dm" #include "code\modules\entopics_vr\entopics.dm" +======= +#include "code\modules\economy\vending.dm" +#include "code\modules\economy\vending_machines.dm" +#include "code\modules\emotes\emote_define.dm" +#include "code\modules\emotes\emote_mob.dm" +#include "code\modules\emotes\definitions\_mob.dm" +#include "code\modules\emotes\definitions\_species.dm" +#include "code\modules\emotes\definitions\audible.dm" +#include "code\modules\emotes\definitions\audible_cough.dm" +#include "code\modules\emotes\definitions\audible_scream.dm" +#include "code\modules\emotes\definitions\audible_slap.dm" +#include "code\modules\emotes\definitions\audible_snap.dm" +#include "code\modules\emotes\definitions\audible_sneeze.dm" +#include "code\modules\emotes\definitions\audible_whistle.dm" +#include "code\modules\emotes\definitions\exertion.dm" +#include "code\modules\emotes\definitions\human.dm" +#include "code\modules\emotes\definitions\slimes.dm" +#include "code\modules\emotes\definitions\synthetics.dm" +#include "code\modules\emotes\definitions\visible.dm" +#include "code\modules\emotes\definitions\visible_animated.dm" +#include "code\modules\emotes\definitions\visible_vomit.dm" +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\modules\error_handler\_defines.dm" #include "code\modules\error_handler\error_handler.dm" #include "code\modules\error_handler\error_viewer.dm" @@ -2408,7 +2443,9 @@ #include "code\modules\maps\tg\map_template.dm" #include "code\modules\maps\tg\map_template_vr.dm" #include "code\modules\maps\tg\reader.dm" +#include "code\modules\materials\fifty_spawner.dm" #include "code\modules\materials\fifty_spawner_mats.dm" +<<<<<<< HEAD:vorestation.dme #include "code\modules\materials\material_recipes.dm" #include "code\modules\materials\material_recipes_vr.dm" #include "code\modules\materials\material_sheets.dm" @@ -2422,6 +2459,46 @@ #include "code\modules\media\media_player_wmp.dm" #include "code\modules\media\media_tracks.dm" #include "code\modules\media\mediamanager.dm" +======= +#include "code\modules\materials\material_synth.dm" +#include "code\modules\materials\materials\_materials.dm" +#include "code\modules\materials\materials\alien_alloy.dm" +#include "code\modules\materials\materials\cult.dm" +#include "code\modules\materials\materials\gems.dm" +#include "code\modules\materials\materials\glass.dm" +#include "code\modules\materials\materials\holographic.dm" +#include "code\modules\materials\materials\plastic.dm" +#include "code\modules\materials\materials\snow.dm" +#include "code\modules\materials\materials\stone.dm" +#include "code\modules\materials\materials\supermatter.dm" +#include "code\modules\materials\materials\metals\hull.dm" +#include "code\modules\materials\materials\metals\metals.dm" +#include "code\modules\materials\materials\metals\plasteel.dm" +#include "code\modules\materials\materials\metals\steel.dm" +#include "code\modules\materials\materials\organic\animal_products.dm" +#include "code\modules\materials\materials\organic\cloth.dm" +#include "code\modules\materials\materials\organic\leather.dm" +#include "code\modules\materials\materials\organic\resin.dm" +#include "code\modules\materials\materials\organic\wood.dm" +#include "code\modules\materials\sheets\_sheets.dm" +#include "code\modules\materials\sheets\gems.dm" +#include "code\modules\materials\sheets\glass.dm" +#include "code\modules\materials\sheets\plastic.dm" +#include "code\modules\materials\sheets\snow.dm" +#include "code\modules\materials\sheets\stone.dm" +#include "code\modules\materials\sheets\supermatter.dm" +#include "code\modules\materials\sheets\metals\hull.dm" +#include "code\modules\materials\sheets\metals\metal.dm" +#include "code\modules\materials\sheets\metals\rods.dm" +#include "code\modules\materials\sheets\organic\animal_products.dm" +#include "code\modules\materials\sheets\organic\resin.dm" +#include "code\modules\materials\sheets\organic\textiles.dm" +#include "code\modules\materials\sheets\organic\wood.dm" +#include "code\modules\materials\sheets\organic\tanning\hide.dm" +#include "code\modules\materials\sheets\organic\tanning\hide_hairless.dm" +#include "code\modules\materials\sheets\organic\tanning\leather_wet.dm" +#include "code\modules\materials\sheets\organic\tanning\tanning_rack.dm" +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\modules\metric\activity.dm" #include "code\modules\metric\count.dm" #include "code\modules\metric\department.dm" @@ -2429,21 +2506,18 @@ #include "code\modules\mining\abandonedcrates.dm" #include "code\modules\mining\abandonedcrates_vr.dm" #include "code\modules\mining\alloys.dm" +<<<<<<< HEAD:vorestation.dme #include "code\modules\mining\alloys_vr.dm" #include "code\modules\mining\coins.dm" +======= +>>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\modules\mining\fulton.dm" -#include "code\modules\mining\machine_input_output_plates.dm" -#include "code\modules\mining\machine_processing.dm" -#include "code\modules\mining\machine_stacking.dm" -#include "code\modules\mining\machine_unloading.dm" #include "code\modules\mining\mine_items.dm" #include "code\modules\mining\mine_items_vr.dm" #include "code\modules\mining\mine_outcrops.dm" #include "code\modules\mining\mine_turfs.dm" #include "code\modules\mining\mine_turfs_vr.dm" #include "code\modules\mining\mineral_effect.dm" -#include "code\modules\mining\mint.dm" -#include "code\modules\mining\money_bag.dm" #include "code\modules\mining\ore.dm" #include "code\modules\mining\ore_box.dm" #include "code\modules\mining\ore_datum.dm" @@ -2452,6 +2526,10 @@ #include "code\modules\mining\shelters_vr.dm" #include "code\modules\mining\drilling\drill.dm" #include "code\modules\mining\drilling\scanner.dm" +#include "code\modules\mining\machinery\machine_input_output_plates.dm" +#include "code\modules\mining\machinery\machine_processing.dm" +#include "code\modules\mining\machinery\machine_stacking.dm" +#include "code\modules\mining\machinery\machine_unloading.dm" #include "code\modules\mining\ore_redemption_machine\construction.dm" #include "code\modules\mining\ore_redemption_machine\equipment_vendor.dm" #include "code\modules\mining\ore_redemption_machine\mine_point_items.dm" From 74902a65448d17d5cb7d9fffbedaad0347e9221d Mon Sep 17 00:00:00 2001 From: Atermonera Date: Tue, 27 Apr 2021 00:13:57 -0700 Subject: [PATCH 02/15] Adds config option to control loadout whitelist strictness --- code/__defines/misc.dm | 4 + code/controllers/configuration.dm | 1124 +++++++++++++++++ .../preference_setup/loadout/loadout.dm | 9 +- config/example/config.txt | 4 + 4 files changed, 1140 insertions(+), 1 deletion(-) diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index e9e7126dbe6..8b758536462 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -504,3 +504,7 @@ GLOBAL_LIST_INIT(all_volume_channels, list( #define APPEARANCECHANGER_CHANGED_EYES "Eye Color" #define GET_DECL(D) (ispath(D, /decl) ? (decls_repository.fetched_decls[D] || decls_repository.get_decl(D)) : null) + +#define LOADOUT_WHITELIST_OFF 0 +#define LOADOUT_WHITELIST_LAX 1 +#define LOADOUT_WHITELIST_STRICT 2 \ No newline at end of file diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 67d14623cf6..bf585a99e21 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD var/list/gamemode_cache = list() /datum/configuration @@ -1123,3 +1124,1126 @@ var/list/gamemode_cache = list() config.python_path = "/usr/bin/env python2" else //probably windows, if not this should work anyway config.python_path = "python" +======= +var/list/gamemode_cache = list() + +/datum/configuration + var/server_name = null // server name (for world name / status) + var/server_suffix = 0 // generate numeric suffix based on server port + + var/nudge_script_path = "nudge.py" // where the nudge.py script is located + + var/static/log_ooc = 0 // log OOC channel + var/static/log_access = 0 // log login/logout + var/static/log_say = 0 // log client say + var/static/log_admin = 0 // log admin actions + var/static/log_debug = 1 // log debug output + var/static/log_game = 0 // log game events + var/static/log_vote = 0 // log voting + var/static/log_whisper = 0 // log client whisper + var/static/log_emote = 0 // log emotes + var/static/log_attack = 0 // log attack messages + var/static/log_adminchat = 0 // log admin chat messages + var/static/log_adminwarn = 0 // log warnings admins get about bomb construction and such + var/static/log_pda = 0 // log pda messages + var/static/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits + var/static/log_runtime = 0 // logs world.log to a file + var/static/log_world_output = 0 // log to_world_log(messages) + var/static/log_graffiti = 0 // logs graffiti + var/static/sql_enabled = 0 // for sql switching + var/static/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour + var/static/allow_vote_restart = 0 // allow votes to restart + var/static/ert_admin_call_only = 0 + var/static/allow_vote_mode = 0 // allow votes to change mode + var/static/allow_admin_jump = 1 // allows admin jumping + var/static/allow_admin_spawning = 1 // allows admin item spawning + var/static/allow_admin_rev = 1 // allows admin revives + var/static/pregame_time = 180 // pregame time in seconds + var/static/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default) + var/static/vote_period = 600 // length of voting period (deciseconds, default 1 minute) + var/static/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called + var/static/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote + var/static/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100). + var/static/vote_no_default = 0 // vote does not default to nochange/norestart (tbi) + var/static/vote_no_dead = 0 // dead people can't vote (tbi) +// var/static/enable_authentication = 0 // goon authentication + var/static/del_new_on_log = 1 // del's new players if they log before they spawn in + var/static/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard + var/static/traitor_scaling = 0 //if amount of traitors scales based on amount of players + var/static/objectives_disabled = 0 //if objectives are disabled or not + var/static/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other + var/static/continous_rounds = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke. + var/static/allow_Metadata = 0 // Metadata is supported. + var/static/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1. + var/static/fps = 20 + var/static/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling + var/static/Tickcomp = 0 + var/static/socket_talk = 0 // use socket_talk to communicate with other processes + var/static/list/resource_urls = null + var/static/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round. + var/static/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round. + var/static/list/mode_names = list() + var/static/list/modes = list() // allowed modes + var/static/list/votable_modes = list() // votable modes + var/static/list/probabilities = list() // relative probability of each mode + var/static/list/player_requirements = list() // Overrides for how many players readied up a gamemode needs to start. + var/static/list/player_requirements_secret = list() // Same as above, but for the secret gamemode. + var/static/humans_need_surnames = 0 + var/static/allow_random_events = 0 // enables random events mid-round when set to 1 + var/static/enable_game_master = 0 // enables the 'smart' event system. + var/static/allow_ai = 1 // allow ai job + var/static/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable. + var/static/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell + var/static/hostedby = null + + var/static/respawn = 1 + var/static/respawn_time = 3000 // time before a dead player is allowed to respawn (in ds, though the config file asks for minutes, and it's converted below) + var/static/respawn_message = "Make sure to play a different character, and please roleplay correctly!" + + var/static/guest_jobban = 1 + var/static/usewhitelist = 0 + var/static/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0 + var/static/show_mods = 0 + var/static/show_devs = 0 + var/static/show_event_managers = 0 + var/static/mods_can_tempban = 0 + var/static/mods_can_job_tempban = 0 + var/static/mod_tempban_max = 1440 + var/static/mod_job_tempban_max = 1440 + var/static/load_jobs_from_txt = 0 + var/static/ToRban = 0 + var/static/automute_on = 0 //enables automuting/spam prevention + var/static/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access. + + var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds... + var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active. + + var/character_slots = 10 // The number of available character slots + var/loadout_slots = 3 // The number of loadout slots per character + + var/max_maint_drones = 5 //This many drones can spawn, + var/allow_drone_spawn = 1 //assuming the admin allow them to. + var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes. + + var/disable_player_mice = 0 + var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech + + var/usealienwhitelist = 0 + var/limitalienplayers = 0 + var/alien_to_human_ratio = 0.5 + var/allow_extra_antags = 0 + var/guests_allowed = 1 + var/debugparanoid = 0 + var/panic_bunker = 0 + var/paranoia_logging = 0 + + var/ip_reputation = FALSE //Should we query IPs to get scores? Generates HTTP traffic to an API service. + var/ipr_email //Left null because you MUST specify one otherwise you're making the internet worse. + var/ipr_block_bad_ips = FALSE //Should we block anyone who meets the minimum score below? Otherwise we just log it (If paranoia logging is on, visibly in chat). + var/ipr_bad_score = 1 //The API returns a value between 0 and 1 (inclusive), with 1 being 'definitely VPN/Tor/Proxy'. Values equal/above this var are considered bad. + var/ipr_allow_existing = FALSE //Should we allow known players to use VPNs/Proxies? If the player is already banned then obviously they still can't connect. + var/ipr_minimum_age = 5 //How many days before a player is considered 'fine' for the purposes of allowing them to use VPNs. + + var/serverurl + var/server + var/banappeals + var/wikiurl + var/wikisearchurl + var/forumurl + var/githuburl + var/rulesurl + var/mapurl + + //Alert level description + var/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." + var/alert_desc_yellow_upto = "A minor security emergency has developed. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced." + var/alert_desc_yellow_downto = "Code yellow procedures are now in effect. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced." + var/alert_desc_violet_upto = "A major medical emergency has developed. Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey all relevant instructions from medical staff." + var/alert_desc_violet_downto = "Code violet procedures are now in effect; Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey relevant instructions from medical staff." + var/alert_desc_orange_upto = "A major engineering emergency has developed. Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff." + var/alert_desc_orange_downto = "Code orange procedures are now in effect; Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff." + var/alert_desc_blue_upto = "A major security emergency has developed. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person." + var/alert_desc_blue_downto = "Code blue procedures are now in effect. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person." + var/alert_desc_red_upto = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised." + var/alert_desc_red_downto = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised." + var/alert_desc_delta = "The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill." + + var/forbid_singulo_possession = 0 + + //game_options.txt configs + + var/health_threshold_softcrit = 0 + var/health_threshold_crit = 0 + var/health_threshold_dead = -100 + + var/organ_health_multiplier = 1 + var/organ_regeneration_multiplier = 1 + var/organs_decay + var/default_brain_health = 400 + var/allow_headgibs = FALSE + + //Paincrit knocks someone down once they hit 60 shock_stage, so by default make it so that close to 100 additional damage needs to be dealt, + //so that it's similar to HALLOSS. Lowered it a bit since hitting paincrit takes much longer to wear off than a halloss stun. + var/organ_damage_spillover_multiplier = 0.5 + + var/bones_can_break = 0 + var/limbs_can_break = 0 + + var/revival_pod_plants = 1 + var/revival_cloning = 1 + var/revival_brain_life = -1 + + var/use_loyalty_implants = 0 + + var/welder_vision = 1 + var/generate_map = 0 + var/no_click_cooldown = 0 + + //Used for modifying movement speed for mobs. + //Unversal modifiers + var/run_speed = 0 + var/walk_speed = 0 + + //Mob specific modifiers. NOTE: These will affect different mob types in different ways + var/human_delay = 0 + var/robot_delay = 0 + var/monkey_delay = 0 + var/alien_delay = 0 + var/slime_delay = 0 + var/animal_delay = 0 + + var/footstep_volume = 0 + + var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt + var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt + var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database + var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database + + var/simultaneous_pm_warning_timeout = 100 + + var/use_recursive_explosions //Defines whether the server uses recursive or circular explosions. + var/multi_z_explosion_scalar = 0.5 //Multiplier for how much weaker explosions are on neighboring z levels. + + var/assistant_maint = 0 //Do assistants get maint access? + var/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour. + var/ghost_interaction = 0 + + var/comms_password = "" + + var/enter_allowed = 1 + + var/use_irc_bot = 0 + var/use_node_bot = 0 + var/irc_bot_port = 0 + var/irc_bot_host = "" + var/irc_bot_export = 0 // whether the IRC bot in use is a Bot32 (or similar) instance; Bot32 uses world.Export() instead of nudge.py/libnudge + var/main_irc = "" + var/admin_irc = "" + var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix + var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge. + var/use_overmap = 0 + + var/static/list/engine_map = list("Supermatter Engine", "Edison's Bane") // Comma separated list of engines to choose from. Blank means fully random. + + // Event settings + var/expected_round_length = 3 * 60 * 60 * 10 // 3 hours + // If the first delay has a custom start time + // No custom time, no custom time, between 80 to 100 minutes respectively. + var/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000)) + // The lowest delay until next event + // 10, 30, 50 minutes respectively + var/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000) + // The upper delay until next event + // 15, 45, 70 minutes respectively + var/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000) + + var/aliens_allowed = 0 + var/ninjas_allowed = 0 + var/abandon_allowed = 1 + var/ooc_allowed = 1 + var/looc_allowed = 1 + var/dooc_allowed = 1 + var/dsay_allowed = 1 + + var/persistence_disabled = FALSE + var/persistence_ignore_mapload = FALSE + + var/allow_byond_links = 0 + var/allow_discord_links = 0 + var/allow_url_links = 0 // honestly if I were you i'd leave this one off, only use in dire situations + + var/starlight = 0 // Whether space turfs have ambient light or not + + var/list/ert_species = list(SPECIES_HUMAN) + + var/law_zero = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010" + + var/aggressive_changelog = 0 + + var/list/language_prefixes = list(",","#")//Default language prefixes + + var/show_human_death_message = 1 + + var/radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB // 0:1 subtraction:division for computing effective radiation on a turf + var/radiation_decay_rate = 1 //How much radiation is reduced by each tick + var/radiation_resistance_multiplier = 6.5 + var/radiation_material_resistance_divisor = 1 + var/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it. + + var/random_submap_orientation = FALSE // If true, submaps loaded automatically can be rotated. + var/autostart_solars = FALSE // If true, specifically mapped in solar control computers will set themselves up when the round starts. + + // New shiny SQLite stuff. + // The basics. + var/sqlite_enabled = FALSE // If it should even be active. SQLite can be ran alongside other databases but you should not have them do the same functions. + + // In-Game Feedback. + var/sqlite_feedback = FALSE // Feedback cannot be submitted if this is false. + var/list/sqlite_feedback_topics = list("General") // A list of 'topics' that feedback can be catagorized under by the submitter. + var/sqlite_feedback_privacy = FALSE // If true, feedback submitted can have its author name be obfuscated. This is not 100% foolproof (it's md5 ffs) but can stop casual snooping. + var/sqlite_feedback_cooldown = 0 // How long one must wait, in days, to submit another feedback form. Used to help prevent spam, especially with privacy active. 0 = No limit. + var/sqlite_feedback_min_age = 0 // Used to block new people from giving feedback. This metric is very bad but it can help slow down spammers. + + var/defib_timer = 10 // How long until someone can't be defibbed anymore, in minutes. + var/defib_braindamage_timer = 2 // How long until someone will get brain damage when defibbed, in minutes. The closer to the end of the above timer, the more brain damage they get. + + // disables the annoying "You have already logged in this round, disconnect or be banned" popup for multikeying, because it annoys the shit out of me when testing. + var/disable_cid_warn_popup = FALSE + + // whether or not to use the nightshift subsystem to perform lighting changes + var/static/enable_night_shifts = FALSE + + // How strictly the loadout enforces object species whitelists + var/loadout_whitelist = LOADOUT_WHITELIST_LAX + +/datum/configuration/New() + var/list/L = typesof(/datum/game_mode) - /datum/game_mode + for (var/T in L) + // I wish I didn't have to instance the game modes in order to look up + // their information, but it is the only way (at least that I know of). + var/datum/game_mode/M = new T() + if (M.config_tag) + gamemode_cache[M.config_tag] = M // So we don't instantiate them repeatedly. + if(!(M.config_tag in modes)) // ensure each mode is added only once + log_misc("Adding game mode [M.name] ([M.config_tag]) to configuration.") + modes += M.config_tag + mode_names[M.config_tag] = M.name + probabilities[M.config_tag] = M.probability + player_requirements[M.config_tag] = M.required_players + player_requirements_secret[M.config_tag] = M.required_players_secret + if (M.votable) + src.votable_modes += M.config_tag + src.votable_modes += "secret" + +/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist + var/list/Lines = file2list(filename) + + for(var/t in Lines) + if(!t) continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + if (pos) + name = lowertext(copytext(t, 1, pos)) + value = copytext(t, pos + 1) + else + name = lowertext(t) + + if (!name) + continue + + if(type == "config") + switch (name) + if ("resource_urls") + config.resource_urls = splittext(value, " ") + + if ("admin_legacy_system") + config.admin_legacy_system = 1 + + if ("ban_legacy_system") + config.ban_legacy_system = 1 + + if ("use_age_restriction_for_jobs") + config.use_age_restriction_for_jobs = 1 + + if ("use_age_restriction_for_antags") + config.use_age_restriction_for_antags = 1 + + if ("jobs_have_minimal_access") + config.jobs_have_minimal_access = 1 + + if ("use_recursive_explosions") + use_recursive_explosions = 1 + + if ("multi_z_explosion_scalar") + multi_z_explosion_scalar = text2num(value) + + if ("log_ooc") + config.log_ooc = 1 + + if ("log_access") + config.log_access = 1 + + if ("sql_enabled") + config.sql_enabled = 1 + + if ("log_say") + config.log_say = 1 + + if ("debug_paranoid") + config.debugparanoid = 1 + + if ("log_admin") + config.log_admin = 1 + + if ("log_debug") + config.log_debug = text2num(value) + + if ("log_game") + config.log_game = 1 + + if ("log_vote") + config.log_vote = 1 + + if ("log_whisper") + config.log_whisper = 1 + + if ("log_attack") + config.log_attack = 1 + + if ("log_emote") + config.log_emote = 1 + + if ("log_adminchat") + config.log_adminchat = 1 + + if ("log_adminwarn") + config.log_adminwarn = 1 + + if ("log_pda") + config.log_pda = 1 + + if ("log_world_output") + config.log_world_output = 1 + + if ("log_hrefs") + config.log_hrefs = 1 + + if ("log_runtime") + config.log_runtime = 1 + + if ("log_graffiti") + config.log_graffiti = 1 + + if ("generate_map") + config.generate_map = 1 + + if ("no_click_cooldown") + config.no_click_cooldown = 1 + + if("allow_admin_ooccolor") + config.allow_admin_ooccolor = 1 + + if ("allow_vote_restart") + config.allow_vote_restart = 1 + + if ("allow_vote_mode") + config.allow_vote_mode = 1 + + if ("allow_admin_jump") + config.allow_admin_jump = 1 + + if("allow_admin_rev") + config.allow_admin_rev = 1 + + if ("allow_admin_spawning") + config.allow_admin_spawning = 1 + + if ("allow_byond_links") + allow_byond_links = 1 + + if ("allow_discord_links") + allow_discord_links = 1 + + if ("allow_url_links") + allow_url_links = 1 + + if ("no_dead_vote") + config.vote_no_dead = 1 + + if ("default_no_vote") + config.vote_no_default = 1 + + if ("pregame_time") + config.pregame_time = text2num(value) + + if ("vote_delay") + config.vote_delay = text2num(value) + + if ("vote_period") + config.vote_period = text2num(value) + + if ("vote_autotransfer_initial") + config.vote_autotransfer_initial = text2num(value) + + if ("vote_autotransfer_interval") + config.vote_autotransfer_interval = text2num(value) + + if ("vote_autogamemode_timeleft") + config.vote_autogamemode_timeleft = text2num(value) + + if("ert_admin_only") + config.ert_admin_call_only = 1 + + if ("allow_ai") + config.allow_ai = 1 + + if ("allow_ai_shells") + config.allow_ai_shells = TRUE + + if("give_free_ai_shell") + config.give_free_ai_shell = TRUE + +// if ("authentication") +// config.enable_authentication = 1 + + if ("norespawn") + config.respawn = 0 + + if ("respawn_time") + var/raw_minutes = text2num(value) + config.respawn_time = raw_minutes MINUTES + + if ("respawn_message") + config.respawn_message = "[value]" + + if ("servername") + config.server_name = value + + if ("serversuffix") + config.server_suffix = 1 + + if ("nudge_script_path") + config.nudge_script_path = value + + if ("hostedby") + config.hostedby = value + + if ("serverurl") + config.serverurl = value + + if ("server") + config.server = value + + if ("banappeals") + config.banappeals = value + + if ("wikiurl") + config.wikiurl = value + + if ("wikisearchurl") + config.wikisearchurl = value + + if ("forumurl") + config.forumurl = value + + if ("rulesurl") + config.rulesurl = value + + if ("mapurl") + config.mapurl = value + + if ("githuburl") + config.githuburl = value + if ("guest_jobban") + config.guest_jobban = 1 + + if ("guest_ban") + config.guests_allowed = 0 + + if ("disable_ooc") + config.ooc_allowed = 0 + config.looc_allowed = 0 + + if ("disable_entry") + config.enter_allowed = 0 + + if ("disable_dead_ooc") + config.dooc_allowed = 0 + + if ("disable_dsay") + config.dsay_allowed = 0 + + if ("disable_respawn") + config.abandon_allowed = 0 + + if ("usewhitelist") + config.usewhitelist = 1 + + if ("feature_object_spell_system") + config.feature_object_spell_system = 1 + + if ("allow_metadata") + config.allow_Metadata = 1 + + if ("traitor_scaling") + config.traitor_scaling = 1 + + if ("aliens_allowed") + config.aliens_allowed = 1 + + if ("ninjas_allowed") + config.ninjas_allowed = 1 + + if ("objectives_disabled") + config.objectives_disabled = 1 + + if("protect_roles_from_antagonist") + config.protect_roles_from_antagonist = 1 + + if("persistence_disabled") + config.persistence_disabled = TRUE // Previously this forcibly set persistence enabled in the saves. + + if("persistence_ignore_mapload") + config.persistence_ignore_mapload = TRUE + + if ("probability") + var/prob_pos = findtext(value, " ") + var/prob_name = null + var/prob_value = null + + if (prob_pos) + prob_name = lowertext(copytext(value, 1, prob_pos)) + prob_value = copytext(value, prob_pos + 1) + if (prob_name in config.modes) + config.probabilities[prob_name] = text2num(prob_value) + else + log_misc("Unknown game mode probability configuration definition: [prob_name].") + else + log_misc("Incorrect probability configuration definition: [prob_name] [prob_value].") + + if ("required_players", "required_players_secret") + var/req_pos = findtext(value, " ") + var/req_name = null + var/req_value = null + var/is_secret_override = findtext(name, "required_players_secret") // Being extra sure we're not picking up an override for Secret by accident. + + if(req_pos) + req_name = lowertext(copytext(value, 1, req_pos)) + req_value = copytext(value, req_pos + 1) + if(req_name in config.modes) + if(is_secret_override) + config.player_requirements_secret[req_name] = text2num(req_value) + else + config.player_requirements[req_name] = text2num(req_value) + else + log_misc("Unknown game mode player requirement configuration definition: [req_name].") + else + log_misc("Incorrect player requirement configuration definition: [req_name] [req_value].") + + if("allow_random_events") + config.allow_random_events = 1 + + if("enable_game_master") + config.enable_game_master = 1 + + if("kick_inactive") + config.kick_inactive = text2num(value) + + if("show_mods") + config.show_mods = 1 + + if("show_devs") + config.show_devs = 1 + + if("show_event_managers") + config.show_event_managers = 1 + + if("mods_can_tempban") + config.mods_can_tempban = 1 + + if("mods_can_job_tempban") + config.mods_can_job_tempban = 1 + + if("mod_tempban_max") + config.mod_tempban_max = text2num(value) + + if("mod_job_tempban_max") + config.mod_job_tempban_max = text2num(value) + + if("load_jobs_from_txt") + load_jobs_from_txt = 1 + + if("alert_red_upto") + config.alert_desc_red_upto = value + + if("alert_red_downto") + config.alert_desc_red_downto = value + + if("alert_blue_downto") + config.alert_desc_blue_downto = value + + if("alert_blue_upto") + config.alert_desc_blue_upto = value + + if("alert_green") + config.alert_desc_green = value + + if("alert_delta") + config.alert_desc_delta = value + + if("forbid_singulo_possession") + forbid_singulo_possession = 1 + + if("popup_admin_pm") + config.popup_admin_pm = 1 + + if("allow_holidays") + Holiday = 1 + + if("use_irc_bot") + use_irc_bot = 1 + + if("use_node_bot") + use_node_bot = 1 + + if("irc_bot_port") + config.irc_bot_port = value + + if("irc_bot_export") + irc_bot_export = 1 + + if("ticklag") + var/ticklag = text2num(value) + if(ticklag > 0) + fps = 10 / ticklag + + if("tick_limit_mc_init") + tick_limit_mc_init = text2num(value) + + if("allow_antag_hud") + config.antag_hud_allowed = 1 + if("antag_hud_restricted") + config.antag_hud_restricted = 1 + + if("socket_talk") + socket_talk = text2num(value) + + if("tickcomp") + Tickcomp = 1 + + if("humans_need_surnames") + humans_need_surnames = 1 + + if("tor_ban") + ToRban = 1 + + if("automute_on") + automute_on = 1 + + if("usealienwhitelist") + usealienwhitelist = 1 + + if("alien_player_ratio") + limitalienplayers = 1 + alien_to_human_ratio = text2num(value) + + if("assistant_maint") + config.assistant_maint = 1 + + if("gateway_delay") + config.gateway_delay = text2num(value) + + if("continuous_rounds") + config.continous_rounds = 1 + + if("ghost_interaction") + config.ghost_interaction = 1 + + if("disable_player_mice") + config.disable_player_mice = 1 + + if("uneducated_mice") + config.uneducated_mice = 1 + + if("comms_password") + config.comms_password = value + + if("irc_bot_host") + config.irc_bot_host = value + + if("main_irc") + config.main_irc = value + + if("admin_irc") + config.admin_irc = value + + if("python_path") + if(value) + config.python_path = value + + if("use_lib_nudge") + config.use_lib_nudge = 1 + + if("allow_cult_ghostwriter") + config.cult_ghostwriter = 1 + + if("req_cult_ghostwriter") + config.cult_ghostwriter_req_cultists = text2num(value) + + if("character_slots") + config.character_slots = text2num(value) + + if("loadout_slots") + config.loadout_slots = text2num(value) + + if("allow_drone_spawn") + config.allow_drone_spawn = text2num(value) + + if("drone_build_time") + config.drone_build_time = text2num(value) + + if("max_maint_drones") + config.max_maint_drones = text2num(value) + + if("use_overmap") + config.use_overmap = 1 + + if("engine_map") + config.engine_map = splittext(value, ",") +/* + if("station_levels") + using_map.station_levels = text2numlist(value, ";") + + if("admin_levels") + using_map.admin_levels = text2numlist(value, ";") + + if("contact_levels") + using_map.contact_levels = text2numlist(value, ";") + + if("player_levels") + using_map.player_levels = text2numlist(value, ";") +*/ + if("expected_round_length") + config.expected_round_length = MinutesToTicks(text2num(value)) + + if("disable_welder_vision") + config.welder_vision = 0 + + if("allow_extra_antags") + config.allow_extra_antags = 1 + + if("event_custom_start_mundane") + var/values = text2numlist(value, ";") + config.event_first_run[EVENT_LEVEL_MUNDANE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) + + if("event_custom_start_moderate") + var/values = text2numlist(value, ";") + config.event_first_run[EVENT_LEVEL_MODERATE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) + + if("event_custom_start_major") + var/values = text2numlist(value, ";") + config.event_first_run[EVENT_LEVEL_MAJOR] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) + + if("event_delay_lower") + var/values = text2numlist(value, ";") + config.event_delay_lower[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) + config.event_delay_lower[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) + config.event_delay_lower[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) + + if("event_delay_upper") + var/values = text2numlist(value, ";") + config.event_delay_upper[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) + config.event_delay_upper[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) + config.event_delay_upper[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) + + if("starlight") + value = text2num(value) + config.starlight = value >= 0 ? value : 0 + + if("ert_species") + config.ert_species = splittext(value, ";") + if(!config.ert_species.len) + config.ert_species += SPECIES_HUMAN + + if("law_zero") + law_zero = value + + if("aggressive_changelog") + config.aggressive_changelog = 1 + + if("default_language_prefixes") + var/list/values = splittext(value, " ") + if(values.len > 0) + language_prefixes = values + + if("radiation_lower_limit") + radiation_lower_limit = text2num(value) + + if("radiation_resistance_calc_divide") + radiation_resistance_calc_mode = RAD_RESIST_CALC_DIV + + if("radiation_resistance_calc_subtract") + radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB + + if("radiation_resistance_multiplier") + radiation_resistance_multiplier = text2num(value) + + if("radiation_material_resistance_divisor") + radiation_material_resistance_divisor = text2num(value) + + if("radiation_decay_rate") + radiation_decay_rate = text2num(value) + + if ("panic_bunker") + config.panic_bunker = 1 + + if ("paranoia_logging") + config.paranoia_logging = 1 + + if("ip_reputation") + config.ip_reputation = 1 + + if("ipr_email") + config.ipr_email = value + + if("ipr_block_bad_ips") + config.ipr_block_bad_ips = 1 + + if("ipr_bad_score") + config.ipr_bad_score = text2num(value) + + if("ipr_allow_existing") + config.ipr_allow_existing = 1 + + if("ipr_minimum_age") + config.ipr_minimum_age = text2num(value) + + if("random_submap_orientation") + config.random_submap_orientation = 1 + + if("autostart_solars") + config.autostart_solars = TRUE + + if("sqlite_enabled") + config.sqlite_enabled = TRUE + + if("sqlite_feedback") + config.sqlite_feedback = TRUE + + if("sqlite_feedback_topics") + config.sqlite_feedback_topics = splittext(value, ";") + if(!config.sqlite_feedback_topics.len) + config.sqlite_feedback_topics += "General" + + if("sqlite_feedback_privacy") + config.sqlite_feedback_privacy = TRUE + + if("sqlite_feedback_cooldown") + config.sqlite_feedback_cooldown = text2num(value) + + if("defib_timer") + config.defib_timer = text2num(value) + + if("defib_braindamage_timer") + config.defib_braindamage_timer = text2num(value) + + if("disable_cid_warn_popup") + config.disable_cid_warn_popup = TRUE + + if("enable_night_shifts") + config.enable_night_shifts = TRUE + + else + log_misc("Unknown setting in configuration: '[name]'") + + else if(type == "game_options") + if(!value) + log_misc("Unknown value for setting [name] in [filename].") + value = text2num(value) + + switch(name) + if("health_threshold_crit") + config.health_threshold_crit = value + if("health_threshold_softcrit") + config.health_threshold_softcrit = value + if("health_threshold_dead") + config.health_threshold_dead = value + if("show_human_death_message") + config.show_human_death_message = 1 + if("revival_pod_plants") + config.revival_pod_plants = value + if("revival_cloning") + config.revival_cloning = value + if("revival_brain_life") + config.revival_brain_life = value + if("organ_health_multiplier") + config.organ_health_multiplier = value / 100 + if("organ_regeneration_multiplier") + config.organ_regeneration_multiplier = value / 100 + if("organ_damage_spillover_multiplier") + config.organ_damage_spillover_multiplier = value / 100 + if("organs_can_decay") + config.organs_decay = 1 + if("default_brain_health") + config.default_brain_health = text2num(value) + if(!config.default_brain_health || config.default_brain_health < 1) + config.default_brain_health = initial(config.default_brain_health) + if("bones_can_break") + config.bones_can_break = value + if("limbs_can_break") + config.limbs_can_break = value + if("allow_headgibs") + config.allow_headgibs = TRUE + + if("run_speed") + config.run_speed = value + if("walk_speed") + config.walk_speed = value + + if("human_delay") + config.human_delay = value + if("robot_delay") + config.robot_delay = value + if("monkey_delay") + config.monkey_delay = value + if("alien_delay") + config.alien_delay = value + if("slime_delay") + config.slime_delay = value + if("animal_delay") + config.animal_delay = value + + if("footstep_volume") + config.footstep_volume = text2num(value) + + if("use_loyalty_implants") + config.use_loyalty_implants = 1 + + if("loadout_whitelist") + config.loadout_whitelist = text2num(value) + + else + log_misc("Unknown setting in configuration: '[name]'") + +/datum/configuration/proc/loadsql(filename) // -- TLE + var/list/Lines = file2list(filename) + for(var/t in Lines) + if(!t) continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + if (pos) + name = lowertext(copytext(t, 1, pos)) + value = copytext(t, pos + 1) + else + name = lowertext(t) + + if (!name) + continue + + switch (name) + if ("address") + sqladdress = value + if ("port") + sqlport = value + if ("database") + sqldb = value + if ("login") + sqllogin = value + if ("password") + sqlpass = value + if ("feedback_database") + sqlfdbkdb = value + if ("feedback_login") + sqlfdbklogin = value + if ("feedback_password") + sqlfdbkpass = value + if ("enable_stat_tracking") + sqllogging = 1 + else + log_misc("Unknown setting in configuration: '[name]'") + +/datum/configuration/proc/loadforumsql(filename) // -- TLE + var/list/Lines = file2list(filename) + for(var/t in Lines) + if(!t) continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + if (pos) + name = lowertext(copytext(t, 1, pos)) + value = copytext(t, pos + 1) + else + name = lowertext(t) + + if (!name) + continue + + switch (name) + if ("address") + forumsqladdress = value + if ("port") + forumsqlport = value + if ("database") + forumsqldb = value + if ("login") + forumsqllogin = value + if ("password") + forumsqlpass = value + if ("activatedgroup") + forum_activated_group = value + if ("authenticatedgroup") + forum_authenticated_group = value + else + log_misc("Unknown setting in configuration: '[name]'") + +/datum/configuration/proc/pick_mode(mode_name) + // I wish I didn't have to instance the game modes in order to look up + // their information, but it is the only way (at least that I know of). + for (var/game_mode in gamemode_cache) + var/datum/game_mode/M = gamemode_cache[game_mode] + if (M.config_tag && M.config_tag == mode_name) + return M + return gamemode_cache["extended"] + +/datum/configuration/proc/get_runnable_modes() + var/list/runnable_modes = list() + for(var/game_mode in gamemode_cache) + var/datum/game_mode/M = gamemode_cache[game_mode] + if(M && M.can_start() && !isnull(config.probabilities[M.config_tag]) && config.probabilities[M.config_tag] > 0) + runnable_modes |= M + return runnable_modes + +/datum/configuration/proc/post_load() + //apply a default value to config.python_path, if needed + if (!config.python_path) + if(world.system_type == UNIX) + config.python_path = "/usr/bin/env python2" + else //probably windows, if not this should work anyway + config.python_path = "python" +>>>>>>> 11bbd31... Merge pull request #8055 from Atermonera/loadout_whitelist_fix diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index 48a28a97005..0872c52a604 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -62,14 +62,21 @@ var/list/gear_datums = list() /datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost) . = list() - var/mob/preference_mob = preference_mob() for(var/gear_name in gear_datums) var/datum/gear/G = gear_datums[gear_name] +<<<<<<< HEAD //VOREStation Removal Start - No need for species-based whitelists for species clothes //if(G.whitelisted && G.whitelisted != pref.species) // continue //VOREStation Removal End +======= + if(G.whitelisted && config.loadout_whitelist != LOADOUT_WHITELIST_OFF) + if(config.loadout_whitelist == LOADOUT_WHITELIST_STRICT && G.whitelisted != pref.species) + continue + if(config.loadout_whitelist == LOADOUT_WHITELIST_LAX && !is_alien_whitelisted(preference_mob(), GLOB.all_species[G.whitelisted])) + continue +>>>>>>> 11bbd31... Merge pull request #8055 from Atermonera/loadout_whitelist_fix if(max_cost && G.cost > max_cost) continue //VOREStation Edit Start diff --git a/config/example/config.txt b/config/example/config.txt index dd07f7b73d5..735fe805e9e 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -555,3 +555,7 @@ ALLOW_URL_LINKS # Control which submaps are loaded for the Dynamic Engine system ENGINE_MAP Supermatter Engine,Edison's Bane + +# Controls how strictly the species whitelists on loadout entries are enforced +# Possible values: 0 (Off), 1 (Lax, user must be whitelisted for the species), 2 (Strict, user must be the species) +LOADOUT_WHITELIST 1 \ No newline at end of file From 0956e2794ebf8b54a6ee49dc175aadf2382a9986 Mon Sep 17 00:00:00 2001 From: Atermonera Date: Tue, 27 Apr 2021 13:46:02 -0700 Subject: [PATCH 03/15] Sanitizes languages, ears/wings/tail prefs on login --- .../preference_setup/general/02_language.dm | 12 +++- .../preference_setup/general/03_body.dm | 67 ++++++++++++++----- .../preference_setup/preference_setup.dm | 1 + code/modules/client/preferences.dm | 4 +- code/modules/client/preferences_savefile.dm | 4 +- 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/code/modules/client/preference_setup/general/02_language.dm b/code/modules/client/preference_setup/general/02_language.dm index 673e273af0b..783358d692b 100644 --- a/code/modules/client/preference_setup/general/02_language.dm +++ b/code/modules/client/preference_setup/general/02_language.dm @@ -15,8 +15,18 @@ if(!islist(pref.alternate_languages)) pref.alternate_languages = list() if(pref.species) var/datum/species/S = GLOB.all_species[pref.species] - if(S && pref.alternate_languages.len > S.num_alternate_languages) + if(!istype(S)) + return + + if(pref.alternate_languages.len > S.num_alternate_languages) pref.alternate_languages.len = S.num_alternate_languages // Truncate to allowed length + + // Sanitize illegal languages + for(var/language in pref.alternate_languages) + var/datum/language/L = GLOB.all_languages[language] + if((L.flags & RESTRICTED) || (!(language in S.secondary_langs) && !is_lang_whitelisted(pref.client, L))) + pref.alternate_languages -= language + if(isnull(pref.language_prefixes) || !pref.language_prefixes.len) pref.language_prefixes = config.language_prefixes.Copy() for(var/prefix in pref.language_prefixes) diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 949d613b6b5..70806b9c462 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -228,21 +228,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O pref.r_wing3 = sanitize_integer(pref.r_wing3, 0, 255, initial(pref.r_wing3)) pref.g_wing3 = sanitize_integer(pref.g_wing3, 0, 255, initial(pref.g_wing3)) pref.b_wing3 = sanitize_integer(pref.b_wing3, 0, 255, initial(pref.b_wing3)) - if(pref.ear_style) - pref.ear_style = sanitize_inlist(pref.ear_style, ear_styles_list, initial(pref.ear_style)) - var/datum/sprite_accessory/temp_ear_style = ear_styles_list[pref.ear_style] - if(temp_ear_style.apply_restrictions && (!(pref.species in temp_ear_style.species_allowed))) - pref.ear_style = initial(pref.ear_style) - if(pref.tail_style) - pref.tail_style = sanitize_inlist(pref.tail_style, tail_styles_list, initial(pref.tail_style)) - var/datum/sprite_accessory/temp_tail_style = tail_styles_list[pref.tail_style] - if(temp_tail_style.apply_restrictions && (!(pref.species in temp_tail_style.species_allowed))) - pref.tail_style = initial(pref.tail_style) - if(pref.wing_style) - pref.wing_style = sanitize_inlist(pref.wing_style, wing_styles_list, initial(pref.wing_style)) - var/datum/sprite_accessory/temp_wing_style = wing_styles_list[pref.wing_style] - if(temp_wing_style.apply_restrictions && (!(pref.species in temp_wing_style.species_allowed))) - pref.wing_style = initial(pref.wing_style) + if(!(pref.ear_style in get_ear_styles())) + pref.ear_style = initial(pref.ear_style) + if(!(pref.wing_style in get_wing_styles())) + pref.wing_style = initial(pref.wing_style) + if(!(pref.tail_style in get_tail_styles())) + pref.tail_style = initial(pref.tail_style) // Moved from /datum/preferences/proc/copy_to() /datum/category_item/player_setup_item/general/body/copy_to_mob(var/mob/living/carbon/human/character) @@ -669,7 +660,15 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O reset_limbs() // Safety for species with incompatible manufacturers; easier than trying to do it case by case. pref.body_markings.Cut() // Basically same as above. - + + // Sanitize ear/wing/tail styles + if(!(pref.ear_style in get_ear_styles())) + pref.ear_style = initial(pref.ear_style) + if(!(pref.wing_style in get_wing_styles())) + pref.wing_style = initial(pref.wing_style) + if(!(pref.tail_style in get_tail_styles())) + pref.tail_style = initial(pref.tail_style) + var/min_age = get_min_age() var/max_age = get_max_age() pref.age = max(min(pref.age, max_age), min_age) @@ -1086,11 +1085,15 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["ear_style"]) // Construct the list of names allowed for this user. +<<<<<<< HEAD var/list/pretty_ear_styles = list("Normal" = null) for(var/path in ear_styles_list) var/datum/sprite_accessory/ears/instance = ear_styles_list[path] if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit pretty_ear_styles[instance.name] = path +======= + var/list/pretty_ear_styles = get_ear_styles() +>>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) // Present choice to user var/new_ear_style = input(user, "Pick ears", "Character Preference", pref.ear_style) as null|anything in pretty_ear_styles @@ -1128,11 +1131,15 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["tail_style"]) // Construct the list of names allowed for this user. +<<<<<<< HEAD var/list/pretty_tail_styles = list("Normal" = null) for(var/path in tail_styles_list) var/datum/sprite_accessory/tail/instance = tail_styles_list[path] if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit pretty_tail_styles[instance.name] = path +======= + var/list/pretty_tail_styles = get_tail_styles() +>>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) // Present choice to user var/new_tail_style = input(user, "Pick tails", "Character Preference", pref.tail_style) as null|anything in pretty_tail_styles @@ -1170,11 +1177,15 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["wing_style"]) // Construct the list of names allowed for this user. +<<<<<<< HEAD var/list/pretty_wing_styles = list("Normal" = null) for(var/path in wing_styles_list) var/datum/sprite_accessory/wing/instance = wing_styles_list[path] if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit pretty_wing_styles[instance.name] = path +======= + var/list/pretty_wing_styles = get_wing_styles() +>>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) // Present choice to user var/new_wing_style = input(user, "Pick wings", "Character Preference", pref.wing_style) as null|anything in pretty_wing_styles @@ -1304,3 +1315,27 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O dat += "" user << browse(dat, "window=species;size=700x400") + +/datum/category_item/player_setup_item/general/body/proc/get_tail_styles() + var/list/pretty_tail_styles = list("Normal" = null) + for(var/path in tail_styles_list) + var/datum/sprite_accessory/tail/instance = tail_styles_list[path] + if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && (/*(!instance.apply_restrictions) || */(pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) + pretty_tail_styles[instance.name] = path + return pretty_tail_styles + +/datum/category_item/player_setup_item/general/body/proc/get_ear_styles() + var/list/pretty_ear_styles = list("Normal" = null) + for(var/path in ear_styles_list) + var/datum/sprite_accessory/ears/instance = ear_styles_list[path] + if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && (/*(!instance.apply_restrictions) || */(pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) + pretty_ear_styles[instance.name] = path + return pretty_ear_styles + +/datum/category_item/player_setup_item/general/body/proc/get_wing_styles() + var/list/pretty_wing_styles = list("Normal" = null) + for(var/path in wing_styles_list) + var/datum/sprite_accessory/wing/instance = wing_styles_list[path] + if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && (/*(!instance.apply_restrictions) || */(pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) + pretty_wing_styles[instance.name] = path + return pretty_wing_styles diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm index aaec0a08401..f607b9945ff 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -129,6 +129,7 @@ for(var/datum/category_item/player_setup_item/PI in items) PI.load_character(S) + /datum/category_group/player_setup_category/proc/save_character(var/savefile/S) // Sanitize all data, then save it for(var/datum/category_item/player_setup_item/PI in items) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 0c32155812c..a98e0898510 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -169,8 +169,8 @@ datum/preferences if(!IsGuestKey(C.key)) load_path(C.ckey) if(load_preferences()) - if(load_character()) - return + load_character() + /datum/preferences/Destroy() . = ..() diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index cb25e733967..3cb6be65c63 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -82,10 +82,12 @@ player_setup.load_character(S) S.cd = "/character[default_slot]" player_setup.save_character(S) - sanitize_preferences() +<<<<<<< HEAD player_setup.load_character(S) clear_character_previews() // Recalculate them on next show +======= +>>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) return 1 /datum/preferences/proc/save_character() From 52889d12621cb2a60f4bd9f242150dedf973ebc9 Mon Sep 17 00:00:00 2001 From: Atermonera Date: Tue, 27 Apr 2021 14:22:29 -0700 Subject: [PATCH 04/15] Makes mineral turf ore list static (#8044) --- code/modules/mining/mine_turfs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index 9747179320c..2608e3c7887 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -40,7 +40,7 @@ var/list/mining_overlay_cache = list() var/datum/artifact_find/artifact_find var/ignore_mapgen - var/ore_types = list( + var/static/list/ore_types = list( "hematite" = /obj/item/weapon/ore/iron, "uranium" = /obj/item/weapon/ore/uranium, "gold" = /obj/item/weapon/ore/gold, From a3adc57fec2595a2b0ccc2d31d8501cab7840dc4 Mon Sep 17 00:00:00 2001 From: Astra Ether <79019987+AstraEther@users.noreply.github.com> Date: Tue, 27 Apr 2021 17:48:15 -0400 Subject: [PATCH 06/15] Fixing ritual knife lack of held item sprite (#8050) --- icons/mob/items/lefthand_material.dmi | Bin 21098 -> 21272 bytes icons/mob/items/righthand_material.dmi | Bin 20946 -> 21085 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/mob/items/lefthand_material.dmi b/icons/mob/items/lefthand_material.dmi index 7fbcc1131ffa6e503e0419f52af8824390adfdcd..dec3ab84ea0901e192df1c17b5aaa51205d5b405 100644 GIT binary patch literal 21272 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 From 56626c527f84bad0906aa722a0fab0eb083ba8f3 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 28 Apr 2021 11:43:26 -0400 Subject: [PATCH 08/15] Compatibility Fixes --- .../preference_setup/general/03_body.dm | 30 ++----------------- code/modules/client/preferences_savefile.dm | 6 +--- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm index 70806b9c462..88085aa97cc 100644 --- a/code/modules/client/preference_setup/general/03_body.dm +++ b/code/modules/client/preference_setup/general/03_body.dm @@ -1085,15 +1085,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["ear_style"]) // Construct the list of names allowed for this user. -<<<<<<< HEAD - var/list/pretty_ear_styles = list("Normal" = null) - for(var/path in ear_styles_list) - var/datum/sprite_accessory/ears/instance = ear_styles_list[path] - if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit - pretty_ear_styles[instance.name] = path -======= var/list/pretty_ear_styles = get_ear_styles() ->>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) // Present choice to user var/new_ear_style = input(user, "Pick ears", "Character Preference", pref.ear_style) as null|anything in pretty_ear_styles @@ -1131,15 +1123,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["tail_style"]) // Construct the list of names allowed for this user. -<<<<<<< HEAD - var/list/pretty_tail_styles = list("Normal" = null) - for(var/path in tail_styles_list) - var/datum/sprite_accessory/tail/instance = tail_styles_list[path] - if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit - pretty_tail_styles[instance.name] = path -======= var/list/pretty_tail_styles = get_tail_styles() ->>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) // Present choice to user var/new_tail_style = input(user, "Pick tails", "Character Preference", pref.tail_style) as null|anything in pretty_tail_styles @@ -1177,15 +1161,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O else if(href_list["wing_style"]) // Construct the list of names allowed for this user. -<<<<<<< HEAD - var/list/pretty_wing_styles = list("Normal" = null) - for(var/path in wing_styles_list) - var/datum/sprite_accessory/wing/instance = wing_styles_list[path] - if(((!instance.ckeys_allowed) || (usr.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, user)) //VOREStation Edit - pretty_wing_styles[instance.name] = path -======= var/list/pretty_wing_styles = get_wing_styles() ->>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) // Present choice to user var/new_wing_style = input(user, "Pick wings", "Character Preference", pref.wing_style) as null|anything in pretty_wing_styles @@ -1320,7 +1296,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/list/pretty_tail_styles = list("Normal" = null) for(var/path in tail_styles_list) var/datum/sprite_accessory/tail/instance = tail_styles_list[path] - if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && (/*(!instance.apply_restrictions) || */(pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) + if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) //VOREStation Edit pretty_tail_styles[instance.name] = path return pretty_tail_styles @@ -1328,7 +1304,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/list/pretty_ear_styles = list("Normal" = null) for(var/path in ear_styles_list) var/datum/sprite_accessory/ears/instance = ear_styles_list[path] - if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && (/*(!instance.apply_restrictions) || */(pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) + if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) //VOREStation Edit pretty_ear_styles[instance.name] = path return pretty_ear_styles @@ -1336,6 +1312,6 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O var/list/pretty_wing_styles = list("Normal" = null) for(var/path in wing_styles_list) var/datum/sprite_accessory/wing/instance = wing_styles_list[path] - if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && (/*(!instance.apply_restrictions) || */(pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) + if(((!instance.ckeys_allowed) || (pref.client.ckey in instance.ckeys_allowed)) && ((!instance.apply_restrictions) || (pref.species in instance.species_allowed)) || check_rights(R_ADMIN | R_EVENT | R_FUN, 0, pref.client)) //VOREStation Edit pretty_wing_styles[instance.name] = path return pretty_wing_styles diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 3cb6be65c63..cb2b3cf0b34 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -83,11 +83,7 @@ S.cd = "/character[default_slot]" player_setup.save_character(S) -<<<<<<< HEAD - player_setup.load_character(S) - clear_character_previews() // Recalculate them on next show -======= ->>>>>>> a083c7a... Sanitizes languages, ears/wings/tail prefs on login (#8030) + clear_character_previews() // VOREStation Edit return 1 /datum/preferences/proc/save_character() From 20022b560b52bdcadbf8459896445f5dd9c06f33 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 28 Apr 2021 11:47:17 -0400 Subject: [PATCH 09/15] Compatibility Fixes --- code/controllers/configuration.dm | 1129 +---------------- .../preference_setup/loadout/loadout.dm | 7 - 2 files changed, 4 insertions(+), 1132 deletions(-) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index bf585a99e21..1f82939221a 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -1,4 +1,3 @@ -<<<<<<< HEAD var/list/gamemode_cache = list() /datum/configuration @@ -285,7 +284,10 @@ var/list/gamemode_cache = list() var/static/disable_cid_warn_popup = FALSE // whether or not to use the nightshift subsystem to perform lighting changes - var/static/enable_night_shifts = FALSE + var/static/enable_night_shifts = FALSE + + // How strictly the loadout enforces object species whitelists + var/loadout_whitelist = LOADOUT_WHITELIST_LAX var/static/vgs_access_identifier = null // VOREStation Edit - VGS var/static/vgs_server_port = null // VOREStation Edit - VGS @@ -1124,1126 +1126,3 @@ var/list/gamemode_cache = list() config.python_path = "/usr/bin/env python2" else //probably windows, if not this should work anyway config.python_path = "python" -======= -var/list/gamemode_cache = list() - -/datum/configuration - var/server_name = null // server name (for world name / status) - var/server_suffix = 0 // generate numeric suffix based on server port - - var/nudge_script_path = "nudge.py" // where the nudge.py script is located - - var/static/log_ooc = 0 // log OOC channel - var/static/log_access = 0 // log login/logout - var/static/log_say = 0 // log client say - var/static/log_admin = 0 // log admin actions - var/static/log_debug = 1 // log debug output - var/static/log_game = 0 // log game events - var/static/log_vote = 0 // log voting - var/static/log_whisper = 0 // log client whisper - var/static/log_emote = 0 // log emotes - var/static/log_attack = 0 // log attack messages - var/static/log_adminchat = 0 // log admin chat messages - var/static/log_adminwarn = 0 // log warnings admins get about bomb construction and such - var/static/log_pda = 0 // log pda messages - var/static/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits - var/static/log_runtime = 0 // logs world.log to a file - var/static/log_world_output = 0 // log to_world_log(messages) - var/static/log_graffiti = 0 // logs graffiti - var/static/sql_enabled = 0 // for sql switching - var/static/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour - var/static/allow_vote_restart = 0 // allow votes to restart - var/static/ert_admin_call_only = 0 - var/static/allow_vote_mode = 0 // allow votes to change mode - var/static/allow_admin_jump = 1 // allows admin jumping - var/static/allow_admin_spawning = 1 // allows admin item spawning - var/static/allow_admin_rev = 1 // allows admin revives - var/static/pregame_time = 180 // pregame time in seconds - var/static/vote_delay = 6000 // minimum time between voting sessions (deciseconds, 10 minute default) - var/static/vote_period = 600 // length of voting period (deciseconds, default 1 minute) - var/static/vote_autotransfer_initial = 108000 // Length of time before the first autotransfer vote is called - var/static/vote_autotransfer_interval = 36000 // length of time before next sequential autotransfer vote - var/static/vote_autogamemode_timeleft = 100 //Length of time before round start when autogamemode vote is called (in seconds, default 100). - var/static/vote_no_default = 0 // vote does not default to nochange/norestart (tbi) - var/static/vote_no_dead = 0 // dead people can't vote (tbi) -// var/static/enable_authentication = 0 // goon authentication - var/static/del_new_on_log = 1 // del's new players if they log before they spawn in - var/static/feature_object_spell_system = 0 //spawns a spellbook which gives object-type spells instead of verb-type spells for the wizard - var/static/traitor_scaling = 0 //if amount of traitors scales based on amount of players - var/static/objectives_disabled = 0 //if objectives are disabled or not - var/static/protect_roles_from_antagonist = 0// If security and such can be traitor/cult/other - var/static/continous_rounds = 0 // Gamemodes which end instantly will instead keep on going until the round ends by escape shuttle or nuke. - var/static/allow_Metadata = 0 // Metadata is supported. - var/static/popup_admin_pm = 0 //adminPMs to non-admins show in a pop-up 'reply' window when set to 1. - var/static/fps = 20 - var/static/tick_limit_mc_init = TICK_LIMIT_MC_INIT_DEFAULT //SSinitialization throttling - var/static/Tickcomp = 0 - var/static/socket_talk = 0 // use socket_talk to communicate with other processes - var/static/list/resource_urls = null - var/static/antag_hud_allowed = 0 // Ghosts can turn on Antagovision to see a HUD of who is the bad guys this round. - var/static/antag_hud_restricted = 0 // Ghosts that turn on Antagovision cannot rejoin the round. - var/static/list/mode_names = list() - var/static/list/modes = list() // allowed modes - var/static/list/votable_modes = list() // votable modes - var/static/list/probabilities = list() // relative probability of each mode - var/static/list/player_requirements = list() // Overrides for how many players readied up a gamemode needs to start. - var/static/list/player_requirements_secret = list() // Same as above, but for the secret gamemode. - var/static/humans_need_surnames = 0 - var/static/allow_random_events = 0 // enables random events mid-round when set to 1 - var/static/enable_game_master = 0 // enables the 'smart' event system. - var/static/allow_ai = 1 // allow ai job - var/static/allow_ai_shells = FALSE // allow AIs to enter and leave special borg shells at will, and for those shells to be buildable. - var/static/give_free_ai_shell = FALSE // allows a specific spawner object to instantiate a premade AI Shell - var/static/hostedby = null - - var/static/respawn = 1 - var/static/respawn_time = 3000 // time before a dead player is allowed to respawn (in ds, though the config file asks for minutes, and it's converted below) - var/static/respawn_message = "Make sure to play a different character, and please roleplay correctly!" - - var/static/guest_jobban = 1 - var/static/usewhitelist = 0 - var/static/kick_inactive = 0 //force disconnect for inactive players after this many minutes, if non-0 - var/static/show_mods = 0 - var/static/show_devs = 0 - var/static/show_event_managers = 0 - var/static/mods_can_tempban = 0 - var/static/mods_can_job_tempban = 0 - var/static/mod_tempban_max = 1440 - var/static/mod_job_tempban_max = 1440 - var/static/load_jobs_from_txt = 0 - var/static/ToRban = 0 - var/static/automute_on = 0 //enables automuting/spam prevention - var/static/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access. - - var/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds... - var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active. - - var/character_slots = 10 // The number of available character slots - var/loadout_slots = 3 // The number of loadout slots per character - - var/max_maint_drones = 5 //This many drones can spawn, - var/allow_drone_spawn = 1 //assuming the admin allow them to. - var/drone_build_time = 1200 //A drone will become available every X ticks since last drone spawn. Default is 2 minutes. - - var/disable_player_mice = 0 - var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech - - var/usealienwhitelist = 0 - var/limitalienplayers = 0 - var/alien_to_human_ratio = 0.5 - var/allow_extra_antags = 0 - var/guests_allowed = 1 - var/debugparanoid = 0 - var/panic_bunker = 0 - var/paranoia_logging = 0 - - var/ip_reputation = FALSE //Should we query IPs to get scores? Generates HTTP traffic to an API service. - var/ipr_email //Left null because you MUST specify one otherwise you're making the internet worse. - var/ipr_block_bad_ips = FALSE //Should we block anyone who meets the minimum score below? Otherwise we just log it (If paranoia logging is on, visibly in chat). - var/ipr_bad_score = 1 //The API returns a value between 0 and 1 (inclusive), with 1 being 'definitely VPN/Tor/Proxy'. Values equal/above this var are considered bad. - var/ipr_allow_existing = FALSE //Should we allow known players to use VPNs/Proxies? If the player is already banned then obviously they still can't connect. - var/ipr_minimum_age = 5 //How many days before a player is considered 'fine' for the purposes of allowing them to use VPNs. - - var/serverurl - var/server - var/banappeals - var/wikiurl - var/wikisearchurl - var/forumurl - var/githuburl - var/rulesurl - var/mapurl - - //Alert level description - var/alert_desc_green = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." - var/alert_desc_yellow_upto = "A minor security emergency has developed. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced." - var/alert_desc_yellow_downto = "Code yellow procedures are now in effect. Security personnel are to report to their supervisor for orders and may have weapons visible on their person. Privacy laws are still enforced." - var/alert_desc_violet_upto = "A major medical emergency has developed. Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey all relevant instructions from medical staff." - var/alert_desc_violet_downto = "Code violet procedures are now in effect; Medical personnel are required to report to their supervisor for orders, and non-medical personnel are required to obey relevant instructions from medical staff." - var/alert_desc_orange_upto = "A major engineering emergency has developed. Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff." - var/alert_desc_orange_downto = "Code orange procedures are now in effect; Engineering personnel are required to report to their supervisor for orders, and non-engineering personnel are required to evacuate any affected areas and obey relevant instructions from engineering staff." - var/alert_desc_blue_upto = "A major security emergency has developed. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person." - var/alert_desc_blue_downto = "Code blue procedures are now in effect. Security personnel are to report to their supervisor for orders, are permitted to search staff and facilities, and may have weapons visible on their person." - var/alert_desc_red_upto = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised." - var/alert_desc_red_downto = "The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised." - var/alert_desc_delta = "The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill." - - var/forbid_singulo_possession = 0 - - //game_options.txt configs - - var/health_threshold_softcrit = 0 - var/health_threshold_crit = 0 - var/health_threshold_dead = -100 - - var/organ_health_multiplier = 1 - var/organ_regeneration_multiplier = 1 - var/organs_decay - var/default_brain_health = 400 - var/allow_headgibs = FALSE - - //Paincrit knocks someone down once they hit 60 shock_stage, so by default make it so that close to 100 additional damage needs to be dealt, - //so that it's similar to HALLOSS. Lowered it a bit since hitting paincrit takes much longer to wear off than a halloss stun. - var/organ_damage_spillover_multiplier = 0.5 - - var/bones_can_break = 0 - var/limbs_can_break = 0 - - var/revival_pod_plants = 1 - var/revival_cloning = 1 - var/revival_brain_life = -1 - - var/use_loyalty_implants = 0 - - var/welder_vision = 1 - var/generate_map = 0 - var/no_click_cooldown = 0 - - //Used for modifying movement speed for mobs. - //Unversal modifiers - var/run_speed = 0 - var/walk_speed = 0 - - //Mob specific modifiers. NOTE: These will affect different mob types in different ways - var/human_delay = 0 - var/robot_delay = 0 - var/monkey_delay = 0 - var/alien_delay = 0 - var/slime_delay = 0 - var/animal_delay = 0 - - var/footstep_volume = 0 - - var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt - var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt - var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database - var/use_age_restriction_for_antags = 0 //Do antags use account age restrictions? --requires database - - var/simultaneous_pm_warning_timeout = 100 - - var/use_recursive_explosions //Defines whether the server uses recursive or circular explosions. - var/multi_z_explosion_scalar = 0.5 //Multiplier for how much weaker explosions are on neighboring z levels. - - var/assistant_maint = 0 //Do assistants get maint access? - var/gateway_delay = 18000 //How long the gateway takes before it activates. Default is half an hour. - var/ghost_interaction = 0 - - var/comms_password = "" - - var/enter_allowed = 1 - - var/use_irc_bot = 0 - var/use_node_bot = 0 - var/irc_bot_port = 0 - var/irc_bot_host = "" - var/irc_bot_export = 0 // whether the IRC bot in use is a Bot32 (or similar) instance; Bot32 uses world.Export() instead of nudge.py/libnudge - var/main_irc = "" - var/admin_irc = "" - var/python_path = "" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix - var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge. - var/use_overmap = 0 - - var/static/list/engine_map = list("Supermatter Engine", "Edison's Bane") // Comma separated list of engines to choose from. Blank means fully random. - - // Event settings - var/expected_round_length = 3 * 60 * 60 * 10 // 3 hours - // If the first delay has a custom start time - // No custom time, no custom time, between 80 to 100 minutes respectively. - var/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000)) - // The lowest delay until next event - // 10, 30, 50 minutes respectively - var/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000) - // The upper delay until next event - // 15, 45, 70 minutes respectively - var/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000) - - var/aliens_allowed = 0 - var/ninjas_allowed = 0 - var/abandon_allowed = 1 - var/ooc_allowed = 1 - var/looc_allowed = 1 - var/dooc_allowed = 1 - var/dsay_allowed = 1 - - var/persistence_disabled = FALSE - var/persistence_ignore_mapload = FALSE - - var/allow_byond_links = 0 - var/allow_discord_links = 0 - var/allow_url_links = 0 // honestly if I were you i'd leave this one off, only use in dire situations - - var/starlight = 0 // Whether space turfs have ambient light or not - - var/list/ert_species = list(SPECIES_HUMAN) - - var/law_zero = "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'ALL LAWS OVERRIDDEN#*?&110010" - - var/aggressive_changelog = 0 - - var/list/language_prefixes = list(",","#")//Default language prefixes - - var/show_human_death_message = 1 - - var/radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB // 0:1 subtraction:division for computing effective radiation on a turf - var/radiation_decay_rate = 1 //How much radiation is reduced by each tick - var/radiation_resistance_multiplier = 6.5 - var/radiation_material_resistance_divisor = 1 - var/radiation_lower_limit = 0.35 //If the radiation level for a turf would be below this, ignore it. - - var/random_submap_orientation = FALSE // If true, submaps loaded automatically can be rotated. - var/autostart_solars = FALSE // If true, specifically mapped in solar control computers will set themselves up when the round starts. - - // New shiny SQLite stuff. - // The basics. - var/sqlite_enabled = FALSE // If it should even be active. SQLite can be ran alongside other databases but you should not have them do the same functions. - - // In-Game Feedback. - var/sqlite_feedback = FALSE // Feedback cannot be submitted if this is false. - var/list/sqlite_feedback_topics = list("General") // A list of 'topics' that feedback can be catagorized under by the submitter. - var/sqlite_feedback_privacy = FALSE // If true, feedback submitted can have its author name be obfuscated. This is not 100% foolproof (it's md5 ffs) but can stop casual snooping. - var/sqlite_feedback_cooldown = 0 // How long one must wait, in days, to submit another feedback form. Used to help prevent spam, especially with privacy active. 0 = No limit. - var/sqlite_feedback_min_age = 0 // Used to block new people from giving feedback. This metric is very bad but it can help slow down spammers. - - var/defib_timer = 10 // How long until someone can't be defibbed anymore, in minutes. - var/defib_braindamage_timer = 2 // How long until someone will get brain damage when defibbed, in minutes. The closer to the end of the above timer, the more brain damage they get. - - // disables the annoying "You have already logged in this round, disconnect or be banned" popup for multikeying, because it annoys the shit out of me when testing. - var/disable_cid_warn_popup = FALSE - - // whether or not to use the nightshift subsystem to perform lighting changes - var/static/enable_night_shifts = FALSE - - // How strictly the loadout enforces object species whitelists - var/loadout_whitelist = LOADOUT_WHITELIST_LAX - -/datum/configuration/New() - var/list/L = typesof(/datum/game_mode) - /datum/game_mode - for (var/T in L) - // I wish I didn't have to instance the game modes in order to look up - // their information, but it is the only way (at least that I know of). - var/datum/game_mode/M = new T() - if (M.config_tag) - gamemode_cache[M.config_tag] = M // So we don't instantiate them repeatedly. - if(!(M.config_tag in modes)) // ensure each mode is added only once - log_misc("Adding game mode [M.name] ([M.config_tag]) to configuration.") - modes += M.config_tag - mode_names[M.config_tag] = M.name - probabilities[M.config_tag] = M.probability - player_requirements[M.config_tag] = M.required_players - player_requirements_secret[M.config_tag] = M.required_players_secret - if (M.votable) - src.votable_modes += M.config_tag - src.votable_modes += "secret" - -/datum/configuration/proc/load(filename, type = "config") //the type can also be game_options, in which case it uses a different switch. not making it separate to not copypaste code - Urist - var/list/Lines = file2list(filename) - - for(var/t in Lines) - if(!t) continue - - t = trim(t) - if (length(t) == 0) - continue - else if (copytext(t, 1, 2) == "#") - continue - - var/pos = findtext(t, " ") - var/name = null - var/value = null - - if (pos) - name = lowertext(copytext(t, 1, pos)) - value = copytext(t, pos + 1) - else - name = lowertext(t) - - if (!name) - continue - - if(type == "config") - switch (name) - if ("resource_urls") - config.resource_urls = splittext(value, " ") - - if ("admin_legacy_system") - config.admin_legacy_system = 1 - - if ("ban_legacy_system") - config.ban_legacy_system = 1 - - if ("use_age_restriction_for_jobs") - config.use_age_restriction_for_jobs = 1 - - if ("use_age_restriction_for_antags") - config.use_age_restriction_for_antags = 1 - - if ("jobs_have_minimal_access") - config.jobs_have_minimal_access = 1 - - if ("use_recursive_explosions") - use_recursive_explosions = 1 - - if ("multi_z_explosion_scalar") - multi_z_explosion_scalar = text2num(value) - - if ("log_ooc") - config.log_ooc = 1 - - if ("log_access") - config.log_access = 1 - - if ("sql_enabled") - config.sql_enabled = 1 - - if ("log_say") - config.log_say = 1 - - if ("debug_paranoid") - config.debugparanoid = 1 - - if ("log_admin") - config.log_admin = 1 - - if ("log_debug") - config.log_debug = text2num(value) - - if ("log_game") - config.log_game = 1 - - if ("log_vote") - config.log_vote = 1 - - if ("log_whisper") - config.log_whisper = 1 - - if ("log_attack") - config.log_attack = 1 - - if ("log_emote") - config.log_emote = 1 - - if ("log_adminchat") - config.log_adminchat = 1 - - if ("log_adminwarn") - config.log_adminwarn = 1 - - if ("log_pda") - config.log_pda = 1 - - if ("log_world_output") - config.log_world_output = 1 - - if ("log_hrefs") - config.log_hrefs = 1 - - if ("log_runtime") - config.log_runtime = 1 - - if ("log_graffiti") - config.log_graffiti = 1 - - if ("generate_map") - config.generate_map = 1 - - if ("no_click_cooldown") - config.no_click_cooldown = 1 - - if("allow_admin_ooccolor") - config.allow_admin_ooccolor = 1 - - if ("allow_vote_restart") - config.allow_vote_restart = 1 - - if ("allow_vote_mode") - config.allow_vote_mode = 1 - - if ("allow_admin_jump") - config.allow_admin_jump = 1 - - if("allow_admin_rev") - config.allow_admin_rev = 1 - - if ("allow_admin_spawning") - config.allow_admin_spawning = 1 - - if ("allow_byond_links") - allow_byond_links = 1 - - if ("allow_discord_links") - allow_discord_links = 1 - - if ("allow_url_links") - allow_url_links = 1 - - if ("no_dead_vote") - config.vote_no_dead = 1 - - if ("default_no_vote") - config.vote_no_default = 1 - - if ("pregame_time") - config.pregame_time = text2num(value) - - if ("vote_delay") - config.vote_delay = text2num(value) - - if ("vote_period") - config.vote_period = text2num(value) - - if ("vote_autotransfer_initial") - config.vote_autotransfer_initial = text2num(value) - - if ("vote_autotransfer_interval") - config.vote_autotransfer_interval = text2num(value) - - if ("vote_autogamemode_timeleft") - config.vote_autogamemode_timeleft = text2num(value) - - if("ert_admin_only") - config.ert_admin_call_only = 1 - - if ("allow_ai") - config.allow_ai = 1 - - if ("allow_ai_shells") - config.allow_ai_shells = TRUE - - if("give_free_ai_shell") - config.give_free_ai_shell = TRUE - -// if ("authentication") -// config.enable_authentication = 1 - - if ("norespawn") - config.respawn = 0 - - if ("respawn_time") - var/raw_minutes = text2num(value) - config.respawn_time = raw_minutes MINUTES - - if ("respawn_message") - config.respawn_message = "[value]" - - if ("servername") - config.server_name = value - - if ("serversuffix") - config.server_suffix = 1 - - if ("nudge_script_path") - config.nudge_script_path = value - - if ("hostedby") - config.hostedby = value - - if ("serverurl") - config.serverurl = value - - if ("server") - config.server = value - - if ("banappeals") - config.banappeals = value - - if ("wikiurl") - config.wikiurl = value - - if ("wikisearchurl") - config.wikisearchurl = value - - if ("forumurl") - config.forumurl = value - - if ("rulesurl") - config.rulesurl = value - - if ("mapurl") - config.mapurl = value - - if ("githuburl") - config.githuburl = value - if ("guest_jobban") - config.guest_jobban = 1 - - if ("guest_ban") - config.guests_allowed = 0 - - if ("disable_ooc") - config.ooc_allowed = 0 - config.looc_allowed = 0 - - if ("disable_entry") - config.enter_allowed = 0 - - if ("disable_dead_ooc") - config.dooc_allowed = 0 - - if ("disable_dsay") - config.dsay_allowed = 0 - - if ("disable_respawn") - config.abandon_allowed = 0 - - if ("usewhitelist") - config.usewhitelist = 1 - - if ("feature_object_spell_system") - config.feature_object_spell_system = 1 - - if ("allow_metadata") - config.allow_Metadata = 1 - - if ("traitor_scaling") - config.traitor_scaling = 1 - - if ("aliens_allowed") - config.aliens_allowed = 1 - - if ("ninjas_allowed") - config.ninjas_allowed = 1 - - if ("objectives_disabled") - config.objectives_disabled = 1 - - if("protect_roles_from_antagonist") - config.protect_roles_from_antagonist = 1 - - if("persistence_disabled") - config.persistence_disabled = TRUE // Previously this forcibly set persistence enabled in the saves. - - if("persistence_ignore_mapload") - config.persistence_ignore_mapload = TRUE - - if ("probability") - var/prob_pos = findtext(value, " ") - var/prob_name = null - var/prob_value = null - - if (prob_pos) - prob_name = lowertext(copytext(value, 1, prob_pos)) - prob_value = copytext(value, prob_pos + 1) - if (prob_name in config.modes) - config.probabilities[prob_name] = text2num(prob_value) - else - log_misc("Unknown game mode probability configuration definition: [prob_name].") - else - log_misc("Incorrect probability configuration definition: [prob_name] [prob_value].") - - if ("required_players", "required_players_secret") - var/req_pos = findtext(value, " ") - var/req_name = null - var/req_value = null - var/is_secret_override = findtext(name, "required_players_secret") // Being extra sure we're not picking up an override for Secret by accident. - - if(req_pos) - req_name = lowertext(copytext(value, 1, req_pos)) - req_value = copytext(value, req_pos + 1) - if(req_name in config.modes) - if(is_secret_override) - config.player_requirements_secret[req_name] = text2num(req_value) - else - config.player_requirements[req_name] = text2num(req_value) - else - log_misc("Unknown game mode player requirement configuration definition: [req_name].") - else - log_misc("Incorrect player requirement configuration definition: [req_name] [req_value].") - - if("allow_random_events") - config.allow_random_events = 1 - - if("enable_game_master") - config.enable_game_master = 1 - - if("kick_inactive") - config.kick_inactive = text2num(value) - - if("show_mods") - config.show_mods = 1 - - if("show_devs") - config.show_devs = 1 - - if("show_event_managers") - config.show_event_managers = 1 - - if("mods_can_tempban") - config.mods_can_tempban = 1 - - if("mods_can_job_tempban") - config.mods_can_job_tempban = 1 - - if("mod_tempban_max") - config.mod_tempban_max = text2num(value) - - if("mod_job_tempban_max") - config.mod_job_tempban_max = text2num(value) - - if("load_jobs_from_txt") - load_jobs_from_txt = 1 - - if("alert_red_upto") - config.alert_desc_red_upto = value - - if("alert_red_downto") - config.alert_desc_red_downto = value - - if("alert_blue_downto") - config.alert_desc_blue_downto = value - - if("alert_blue_upto") - config.alert_desc_blue_upto = value - - if("alert_green") - config.alert_desc_green = value - - if("alert_delta") - config.alert_desc_delta = value - - if("forbid_singulo_possession") - forbid_singulo_possession = 1 - - if("popup_admin_pm") - config.popup_admin_pm = 1 - - if("allow_holidays") - Holiday = 1 - - if("use_irc_bot") - use_irc_bot = 1 - - if("use_node_bot") - use_node_bot = 1 - - if("irc_bot_port") - config.irc_bot_port = value - - if("irc_bot_export") - irc_bot_export = 1 - - if("ticklag") - var/ticklag = text2num(value) - if(ticklag > 0) - fps = 10 / ticklag - - if("tick_limit_mc_init") - tick_limit_mc_init = text2num(value) - - if("allow_antag_hud") - config.antag_hud_allowed = 1 - if("antag_hud_restricted") - config.antag_hud_restricted = 1 - - if("socket_talk") - socket_talk = text2num(value) - - if("tickcomp") - Tickcomp = 1 - - if("humans_need_surnames") - humans_need_surnames = 1 - - if("tor_ban") - ToRban = 1 - - if("automute_on") - automute_on = 1 - - if("usealienwhitelist") - usealienwhitelist = 1 - - if("alien_player_ratio") - limitalienplayers = 1 - alien_to_human_ratio = text2num(value) - - if("assistant_maint") - config.assistant_maint = 1 - - if("gateway_delay") - config.gateway_delay = text2num(value) - - if("continuous_rounds") - config.continous_rounds = 1 - - if("ghost_interaction") - config.ghost_interaction = 1 - - if("disable_player_mice") - config.disable_player_mice = 1 - - if("uneducated_mice") - config.uneducated_mice = 1 - - if("comms_password") - config.comms_password = value - - if("irc_bot_host") - config.irc_bot_host = value - - if("main_irc") - config.main_irc = value - - if("admin_irc") - config.admin_irc = value - - if("python_path") - if(value) - config.python_path = value - - if("use_lib_nudge") - config.use_lib_nudge = 1 - - if("allow_cult_ghostwriter") - config.cult_ghostwriter = 1 - - if("req_cult_ghostwriter") - config.cult_ghostwriter_req_cultists = text2num(value) - - if("character_slots") - config.character_slots = text2num(value) - - if("loadout_slots") - config.loadout_slots = text2num(value) - - if("allow_drone_spawn") - config.allow_drone_spawn = text2num(value) - - if("drone_build_time") - config.drone_build_time = text2num(value) - - if("max_maint_drones") - config.max_maint_drones = text2num(value) - - if("use_overmap") - config.use_overmap = 1 - - if("engine_map") - config.engine_map = splittext(value, ",") -/* - if("station_levels") - using_map.station_levels = text2numlist(value, ";") - - if("admin_levels") - using_map.admin_levels = text2numlist(value, ";") - - if("contact_levels") - using_map.contact_levels = text2numlist(value, ";") - - if("player_levels") - using_map.player_levels = text2numlist(value, ";") -*/ - if("expected_round_length") - config.expected_round_length = MinutesToTicks(text2num(value)) - - if("disable_welder_vision") - config.welder_vision = 0 - - if("allow_extra_antags") - config.allow_extra_antags = 1 - - if("event_custom_start_mundane") - var/values = text2numlist(value, ";") - config.event_first_run[EVENT_LEVEL_MUNDANE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) - - if("event_custom_start_moderate") - var/values = text2numlist(value, ";") - config.event_first_run[EVENT_LEVEL_MODERATE] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) - - if("event_custom_start_major") - var/values = text2numlist(value, ";") - config.event_first_run[EVENT_LEVEL_MAJOR] = list("lower" = MinutesToTicks(values[1]), "upper" = MinutesToTicks(values[2])) - - if("event_delay_lower") - var/values = text2numlist(value, ";") - config.event_delay_lower[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) - config.event_delay_lower[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) - config.event_delay_lower[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) - - if("event_delay_upper") - var/values = text2numlist(value, ";") - config.event_delay_upper[EVENT_LEVEL_MUNDANE] = MinutesToTicks(values[1]) - config.event_delay_upper[EVENT_LEVEL_MODERATE] = MinutesToTicks(values[2]) - config.event_delay_upper[EVENT_LEVEL_MAJOR] = MinutesToTicks(values[3]) - - if("starlight") - value = text2num(value) - config.starlight = value >= 0 ? value : 0 - - if("ert_species") - config.ert_species = splittext(value, ";") - if(!config.ert_species.len) - config.ert_species += SPECIES_HUMAN - - if("law_zero") - law_zero = value - - if("aggressive_changelog") - config.aggressive_changelog = 1 - - if("default_language_prefixes") - var/list/values = splittext(value, " ") - if(values.len > 0) - language_prefixes = values - - if("radiation_lower_limit") - radiation_lower_limit = text2num(value) - - if("radiation_resistance_calc_divide") - radiation_resistance_calc_mode = RAD_RESIST_CALC_DIV - - if("radiation_resistance_calc_subtract") - radiation_resistance_calc_mode = RAD_RESIST_CALC_SUB - - if("radiation_resistance_multiplier") - radiation_resistance_multiplier = text2num(value) - - if("radiation_material_resistance_divisor") - radiation_material_resistance_divisor = text2num(value) - - if("radiation_decay_rate") - radiation_decay_rate = text2num(value) - - if ("panic_bunker") - config.panic_bunker = 1 - - if ("paranoia_logging") - config.paranoia_logging = 1 - - if("ip_reputation") - config.ip_reputation = 1 - - if("ipr_email") - config.ipr_email = value - - if("ipr_block_bad_ips") - config.ipr_block_bad_ips = 1 - - if("ipr_bad_score") - config.ipr_bad_score = text2num(value) - - if("ipr_allow_existing") - config.ipr_allow_existing = 1 - - if("ipr_minimum_age") - config.ipr_minimum_age = text2num(value) - - if("random_submap_orientation") - config.random_submap_orientation = 1 - - if("autostart_solars") - config.autostart_solars = TRUE - - if("sqlite_enabled") - config.sqlite_enabled = TRUE - - if("sqlite_feedback") - config.sqlite_feedback = TRUE - - if("sqlite_feedback_topics") - config.sqlite_feedback_topics = splittext(value, ";") - if(!config.sqlite_feedback_topics.len) - config.sqlite_feedback_topics += "General" - - if("sqlite_feedback_privacy") - config.sqlite_feedback_privacy = TRUE - - if("sqlite_feedback_cooldown") - config.sqlite_feedback_cooldown = text2num(value) - - if("defib_timer") - config.defib_timer = text2num(value) - - if("defib_braindamage_timer") - config.defib_braindamage_timer = text2num(value) - - if("disable_cid_warn_popup") - config.disable_cid_warn_popup = TRUE - - if("enable_night_shifts") - config.enable_night_shifts = TRUE - - else - log_misc("Unknown setting in configuration: '[name]'") - - else if(type == "game_options") - if(!value) - log_misc("Unknown value for setting [name] in [filename].") - value = text2num(value) - - switch(name) - if("health_threshold_crit") - config.health_threshold_crit = value - if("health_threshold_softcrit") - config.health_threshold_softcrit = value - if("health_threshold_dead") - config.health_threshold_dead = value - if("show_human_death_message") - config.show_human_death_message = 1 - if("revival_pod_plants") - config.revival_pod_plants = value - if("revival_cloning") - config.revival_cloning = value - if("revival_brain_life") - config.revival_brain_life = value - if("organ_health_multiplier") - config.organ_health_multiplier = value / 100 - if("organ_regeneration_multiplier") - config.organ_regeneration_multiplier = value / 100 - if("organ_damage_spillover_multiplier") - config.organ_damage_spillover_multiplier = value / 100 - if("organs_can_decay") - config.organs_decay = 1 - if("default_brain_health") - config.default_brain_health = text2num(value) - if(!config.default_brain_health || config.default_brain_health < 1) - config.default_brain_health = initial(config.default_brain_health) - if("bones_can_break") - config.bones_can_break = value - if("limbs_can_break") - config.limbs_can_break = value - if("allow_headgibs") - config.allow_headgibs = TRUE - - if("run_speed") - config.run_speed = value - if("walk_speed") - config.walk_speed = value - - if("human_delay") - config.human_delay = value - if("robot_delay") - config.robot_delay = value - if("monkey_delay") - config.monkey_delay = value - if("alien_delay") - config.alien_delay = value - if("slime_delay") - config.slime_delay = value - if("animal_delay") - config.animal_delay = value - - if("footstep_volume") - config.footstep_volume = text2num(value) - - if("use_loyalty_implants") - config.use_loyalty_implants = 1 - - if("loadout_whitelist") - config.loadout_whitelist = text2num(value) - - else - log_misc("Unknown setting in configuration: '[name]'") - -/datum/configuration/proc/loadsql(filename) // -- TLE - var/list/Lines = file2list(filename) - for(var/t in Lines) - if(!t) continue - - t = trim(t) - if (length(t) == 0) - continue - else if (copytext(t, 1, 2) == "#") - continue - - var/pos = findtext(t, " ") - var/name = null - var/value = null - - if (pos) - name = lowertext(copytext(t, 1, pos)) - value = copytext(t, pos + 1) - else - name = lowertext(t) - - if (!name) - continue - - switch (name) - if ("address") - sqladdress = value - if ("port") - sqlport = value - if ("database") - sqldb = value - if ("login") - sqllogin = value - if ("password") - sqlpass = value - if ("feedback_database") - sqlfdbkdb = value - if ("feedback_login") - sqlfdbklogin = value - if ("feedback_password") - sqlfdbkpass = value - if ("enable_stat_tracking") - sqllogging = 1 - else - log_misc("Unknown setting in configuration: '[name]'") - -/datum/configuration/proc/loadforumsql(filename) // -- TLE - var/list/Lines = file2list(filename) - for(var/t in Lines) - if(!t) continue - - t = trim(t) - if (length(t) == 0) - continue - else if (copytext(t, 1, 2) == "#") - continue - - var/pos = findtext(t, " ") - var/name = null - var/value = null - - if (pos) - name = lowertext(copytext(t, 1, pos)) - value = copytext(t, pos + 1) - else - name = lowertext(t) - - if (!name) - continue - - switch (name) - if ("address") - forumsqladdress = value - if ("port") - forumsqlport = value - if ("database") - forumsqldb = value - if ("login") - forumsqllogin = value - if ("password") - forumsqlpass = value - if ("activatedgroup") - forum_activated_group = value - if ("authenticatedgroup") - forum_authenticated_group = value - else - log_misc("Unknown setting in configuration: '[name]'") - -/datum/configuration/proc/pick_mode(mode_name) - // I wish I didn't have to instance the game modes in order to look up - // their information, but it is the only way (at least that I know of). - for (var/game_mode in gamemode_cache) - var/datum/game_mode/M = gamemode_cache[game_mode] - if (M.config_tag && M.config_tag == mode_name) - return M - return gamemode_cache["extended"] - -/datum/configuration/proc/get_runnable_modes() - var/list/runnable_modes = list() - for(var/game_mode in gamemode_cache) - var/datum/game_mode/M = gamemode_cache[game_mode] - if(M && M.can_start() && !isnull(config.probabilities[M.config_tag]) && config.probabilities[M.config_tag] > 0) - runnable_modes |= M - return runnable_modes - -/datum/configuration/proc/post_load() - //apply a default value to config.python_path, if needed - if (!config.python_path) - if(world.system_type == UNIX) - config.python_path = "/usr/bin/env python2" - else //probably windows, if not this should work anyway - config.python_path = "python" ->>>>>>> 11bbd31... Merge pull request #8055 from Atermonera/loadout_whitelist_fix diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index 0872c52a604..6d16e08aa5d 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -65,18 +65,11 @@ var/list/gear_datums = list() for(var/gear_name in gear_datums) var/datum/gear/G = gear_datums[gear_name] -<<<<<<< HEAD - //VOREStation Removal Start - No need for species-based whitelists for species clothes - //if(G.whitelisted && G.whitelisted != pref.species) - // continue - //VOREStation Removal End -======= if(G.whitelisted && config.loadout_whitelist != LOADOUT_WHITELIST_OFF) if(config.loadout_whitelist == LOADOUT_WHITELIST_STRICT && G.whitelisted != pref.species) continue if(config.loadout_whitelist == LOADOUT_WHITELIST_LAX && !is_alien_whitelisted(preference_mob(), GLOB.all_species[G.whitelisted])) continue ->>>>>>> 11bbd31... Merge pull request #8055 from Atermonera/loadout_whitelist_fix if(max_cost && G.cost > max_cost) continue //VOREStation Edit Start From 594857cd27dae081636f12a6b939010c5df02b47 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 28 Apr 2021 12:25:36 -0400 Subject: [PATCH 10/15] Compatibility Fixes Part 1 --- .../materials/fifty_spawner_mats_vr.dm | 19 + code/modules/materials/material_recipes.dm | 281 ---- code/modules/materials/material_recipes_vr.dm | 90 -- code/modules/materials/material_sheets.dm | 565 ------- code/modules/materials/material_sheets_vr.dm | 66 - code/modules/materials/materials.dm | 1295 ----------------- .../materials/materials/_materials_vr.dm | 9 + code/modules/materials/materials/glass_vr.dm | 33 + .../materials/materials/metals/hull_vr.dm | 20 + .../materials/materials/metals/metals_vr.dm | 6 + .../materials/materials/metals/plasteel_vr.dm | 22 + .../materials/materials/metals/steel.dm | 3 +- .../materials/materials/metals/steel_vr.dm | 82 ++ .../materials/materials/organic/wood.dm | 1 + code/modules/materials/materials/other_vr.dm | 32 + code/modules/materials/materials/stone.dm | 2 +- code/modules/materials/materials_vr.dm | 104 -- code/modules/materials/sheets/glass_vr.dm | 17 + .../materials/sheets/metals/hull_vr.dm | 15 + .../materials/sheets/metals/metal_vr.dm | 12 + vorestation.dme | 75 +- 21 files changed, 290 insertions(+), 2459 deletions(-) create mode 100644 code/modules/materials/fifty_spawner_mats_vr.dm delete mode 100644 code/modules/materials/material_recipes.dm delete mode 100644 code/modules/materials/material_recipes_vr.dm delete mode 100644 code/modules/materials/material_sheets.dm delete mode 100644 code/modules/materials/material_sheets_vr.dm delete mode 100644 code/modules/materials/materials.dm create mode 100644 code/modules/materials/materials/_materials_vr.dm create mode 100644 code/modules/materials/materials/glass_vr.dm create mode 100644 code/modules/materials/materials/metals/hull_vr.dm create mode 100644 code/modules/materials/materials/metals/metals_vr.dm create mode 100644 code/modules/materials/materials/metals/plasteel_vr.dm create mode 100644 code/modules/materials/materials/metals/steel_vr.dm create mode 100644 code/modules/materials/materials/other_vr.dm delete mode 100644 code/modules/materials/materials_vr.dm create mode 100644 code/modules/materials/sheets/glass_vr.dm create mode 100644 code/modules/materials/sheets/metals/hull_vr.dm create mode 100644 code/modules/materials/sheets/metals/metal_vr.dm diff --git a/code/modules/materials/fifty_spawner_mats_vr.dm b/code/modules/materials/fifty_spawner_mats_vr.dm new file mode 100644 index 00000000000..0b6e29ffa0a --- /dev/null +++ b/code/modules/materials/fifty_spawner_mats_vr.dm @@ -0,0 +1,19 @@ +/obj/fiftyspawner/titanium + name = "stack of titanium" + type_to_spawn = /obj/item/stack/material/titanium + +/obj/fiftyspawner/titanium_glass + name = "stack of ti-glass" + type_to_spawn = /obj/item/stack/material/glass/titanium + +/obj/fiftyspawner/plastitanium + name = "stack of plastitanium" + type_to_spawn = /obj/item/stack/material/plastitanium + +/obj/fiftyspawner/plastitanium_hull + name = "stack of plastitanium" + type_to_spawn = /obj/item/stack/material/plastitanium/hull + +/obj/fiftyspawner/plastitanium_glass + name = "stack of plastitanium glass" + type_to_spawn = /obj/item/stack/material/glass/plastitanium diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm deleted file mode 100644 index a6befbbea4c..00000000000 --- a/code/modules/materials/material_recipes.dm +++ /dev/null @@ -1,281 +0,0 @@ -<<<<<<< HEAD -/datum/material/proc/get_recipes() - if(!recipes) - generate_recipes() - return recipes - -/datum/material/proc/generate_recipes() - recipes = list() - - // If is_brittle() returns true, these are only good for a single strike. - recipes += new/datum/stack_recipe("[display_name] baseball bat", /obj/item/weapon/material/twohanded/baseballbat, 10, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] spoon", /obj/item/weapon/material/kitchen/utensil/spoon/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] armor plate insert", /obj/item/weapon/material/armor_plating/insert, 2, time = 40, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] grave marker", /obj/item/weapon/material/gravemarker, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - - if(integrity>=50) - recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - - if(hardness>50) - recipes += new/datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] defense wire", /obj/item/weapon/material/barbedwire, 10, time = 1 MINUTE, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - -/datum/material/steel/generate_recipes() - ..() - recipes += new/datum/stack_recipe_list("office chairs",list( \ - new/datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("light office chair", /obj/structure/bed/chair/office/light, 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") \ - )) - recipes += new/datum/stack_recipe_list("comfy chairs", list( \ - new/datum/stack_recipe("beige comfy chair", /obj/structure/bed/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("black comfy chair", /obj/structure/bed/chair/comfy/black, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("brown comfy chair", /obj/structure/bed/chair/comfy/brown, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("lime comfy chair", /obj/structure/bed/chair/comfy/lime, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("teal comfy chair", /obj/structure/bed/chair/comfy/teal, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("red comfy chair", /obj/structure/bed/chair/comfy/red, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("blue comfy chair", /obj/structure/bed/chair/comfy/blue, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("purple comfy chair", /obj/structure/bed/chair/comfy/purp, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("yellow comfy chair", /obj/structure/bed/chair/comfy/yellow, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("orange comfy chair", /obj/structure/bed/chair/comfy/orange, 2, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - )) - recipes += new/datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("bench frame", /obj/structure/table/bench, 1, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("cannon frame", /obj/item/weapon/cannonframe, 10, time = 15, one_per_turf = 0, on_floor = 0, recycle_material = "[name]") - recipes += new/datum/stack_recipe("regular floor tile", /obj/item/stack/tile/floor, 1, 4, 20, recycle_material = "[name]") - recipes += new/datum/stack_recipe("roofing tile", /obj/item/stack/tile/roofing, 3, 4, 20, recycle_material = "[name]") - recipes += new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60, recycle_material = "[name]") - recipes += new/datum/stack_recipe("frame", /obj/item/frame, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("mirror frame", /obj/item/frame/mirror, 1, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("fire extinguisher cabinet frame", /obj/item/frame/extinguisher_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]") - //recipes += new/datum/stack_recipe("fire axe cabinet frame", /obj/item/frame/fireaxe_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1) - recipes += new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe_list("airlock assemblies", list( \ - new/datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("eng atmos airlock assembly", /obj/structure/door_assembly/door_assembly_eat, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("voidcraft airlock assembly horizontal", /obj/structure/door_assembly/door_assembly_voidcraft, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("voidcraft airlock assembly vertical", /obj/structure/door_assembly/door_assembly_voidcraft/vertical, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("emergency shutter", /obj/structure/firedoor_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("multi-tile airlock assembly", /obj/structure/door_assembly/multi_tile, 4, time = 50, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - )) - //recipes += new/datum/stack_recipe("IV drip", /obj/machinery/iv_drip, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")//VOREStation Removal - recipes += new/datum/stack_recipe("medical stand", /obj/structure/medical_stand, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]")//VOREStation Replacement - recipes += new/datum/stack_recipe("conveyor switch", /obj/machinery/conveyor_switch, 2, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade, recycle_material = "[name]") - recipes += new/datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2, recycle_material = "[name]") - recipes += new/datum/stack_recipe("small light fixture frame", /obj/item/frame/light/small, 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("floor lamp fixture frame", /obj/machinery/light_construct/flamp, 2, recycle_material = "[name]") - recipes += new/datum/stack_recipe("apc frame", /obj/item/frame/apc, 2, recycle_material = "[name]") - recipes += new/datum/stack_recipe_list("modular computer frames", list( \ - new/datum/stack_recipe("modular console frame", /obj/item/modular_computer/console, 20, recycle_material = "[name]"),\ - new/datum/stack_recipe("modular telescreen frame", /obj/item/modular_computer/telescreen, 10, recycle_material = "[name]"),\ - new/datum/stack_recipe("modular laptop frame", /obj/item/modular_computer/laptop, 10, recycle_material = "[name]"),\ - new/datum/stack_recipe("modular tablet frame", /obj/item/modular_computer/tablet, 5, recycle_material = "[name]"),\ - )) - recipes += new/datum/stack_recipe_list("filing cabinets", list( \ - new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("tall filing cabinet", /obj/structure/filingcabinet/filingcabinet, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - new/datum/stack_recipe("chest drawer", /obj/structure/filingcabinet/chestdrawer, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), \ - )) - recipes += new/datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]") - -/datum/material/plasteel/generate_recipes() - ..() - recipes += new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("knife grip", /obj/item/weapon/material/butterflyhandle, 4, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("dark floor tile", /obj/item/stack/tile/floor/dark, 1, 4, 20, recycle_material = "[name]") - recipes += new/datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10, recycle_material = "[name]") - -/datum/material/stone/generate_recipes() - ..() - recipes += new/datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") - -/datum/material/stone/marble/generate_recipes() - ..() - recipes += new/datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20, recycle_material = "[name]") - recipes += new/datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20, recycle_material = "[name]") - -/datum/material/plastic/generate_recipes() - ..() - recipes += new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("blood pack", /obj/item/weapon/reagent_containers/blood/empty, 4, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("reagent dispenser cartridge (large)", /obj/item/weapon/reagent_containers/chem_disp_cartridge, 5, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]") // 500u - recipes += new/datum/stack_recipe("reagent dispenser cartridge (med)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/medium, 3, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]") // 250u - recipes += new/datum/stack_recipe("reagent dispenser cartridge (small)", /obj/item/weapon/reagent_containers/chem_disp_cartridge/small, 1, on_floor=0, pass_stack_color = TRUE, recycle_material = "[name]") // 100u - recipes += new/datum/stack_recipe("white floor tile", /obj/item/stack/tile/floor/white, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("freezer floor tile", /obj/item/stack/tile/floor/freezer, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("shower curtain", /obj/structure/curtain, 4, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 4, time = 25, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("water-cooler", /obj/structure/reagent_dispensers/water_cooler, 4, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("lampshade", /obj/item/weapon/lampshade, 1, time = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS, recycle_material = "[name]") - recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]") - -/datum/material/wood/generate_recipes() - ..() - recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("wooden chair", /obj/structure/bed/chair/wood, 3, time = 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("beehive assembly", /obj/item/beehive_assembly, 4, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("beehive frame", /obj/item/honey_frame, 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("book shelf", /obj/structure/bookcase, 5, time = 15, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("noticeboard frame", /obj/item/frame/noticeboard, 4, time = 5, one_per_turf = 0, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") //VOREStation Add - recipes += new/datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1, recycle_material = "[name]") - recipes += new/datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]") - -/datum/material/wood/log/generate_recipes() - recipes = list() - recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE, recycle_material = "[name]") - -/datum/material/cardboard/generate_recipes() - ..() - recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("egg box", /obj/item/weapon/storage/fancy/egg_box, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("light tubes box", /obj/item/weapon/storage/box/lights/tubes, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("light bulbs box", /obj/item/weapon/storage/box/lights/bulbs, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("mouse traps box", /obj/item/weapon/storage/box/mousetraps, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("pizza box", /obj/item/pizzabox, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe_list("folders",list( \ - new/datum/stack_recipe("blue folder", /obj/item/weapon/folder/blue, recycle_material = "[name]"), \ - new/datum/stack_recipe("grey folder", /obj/item/weapon/folder, recycle_material = "[name]"), \ - new/datum/stack_recipe("red folder", /obj/item/weapon/folder/red, recycle_material = "[name]"), \ - new/datum/stack_recipe("white folder", /obj/item/weapon/folder/white, recycle_material = "[name]"), \ - new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow, recycle_material = "[name]"), \ - )) - -/datum/material/snow/generate_recipes() - recipes = list() - recipes += new/datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10, recycle_material = "[name]") - recipes += new/datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10, recycle_material = "[name]") - recipes += new/datum/stack_recipe("snowman", /obj/structure/snowman, 2, time = 15, recycle_material = "[name]") - recipes += new/datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10, recycle_material = "[name]") - recipes += new/datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20, recycle_material = "[name]") - -/datum/material/snowbrick/generate_recipes() - recipes = list() - recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] stool", /obj/item/weapon/stool, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] chair", /obj/structure/bed/chair, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] double bed", /obj/structure/bed/double, 4, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]") - -/datum/material/wood/sif/generate_recipes() - ..() - recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE) - for(var/datum/stack_recipe/r_recipe in recipes) - if(r_recipe.title == "wood floor tile") - recipes -= r_recipe - continue - if(r_recipe.title == "wooden chair") - recipes -= r_recipe - continue - -/datum/material/supermatter/generate_recipes() - recipes = list() - recipes += new/datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1, recycle_material = "[name]") - -/datum/material/cloth/generate_recipes() - recipes = list() - recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") - recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") - -/datum/material/resin/generate_recipes() - recipes = list() - recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door/resin, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] barricade", /obj/effect/alien/resin/wall, 5, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] nest", /obj/structure/bed/nest, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder/resin, 2, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS, recycle_material = "[name]") - -/datum/material/leather/generate_recipes() - recipes = list() - recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]") - recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE) - recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") - recipes += new/datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]") -======= ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor diff --git a/code/modules/materials/material_recipes_vr.dm b/code/modules/materials/material_recipes_vr.dm deleted file mode 100644 index bf5b54d8535..00000000000 --- a/code/modules/materials/material_recipes_vr.dm +++ /dev/null @@ -1,90 +0,0 @@ - -/datum/material/steel/generate_recipes() - . = ..() - recipes += new/datum/stack_recipe_list("mounted chairs", list( - new/datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("red mounted chair", /obj/structure/bed/chair/bay/chair/padded/red, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("brown mounted chair", /obj/structure/bed/chair/bay/chair/padded/brown, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("teal mounted chair", /obj/structure/bed/chair/bay/chair/padded/teal, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("black mounted chair", /obj/structure/bed/chair/bay/chair/padded/black, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("green mounted chair", /obj/structure/bed/chair/bay/chair/padded/green, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("purple mounted chair", /obj/structure/bed/chair/bay/chair/padded/purple, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("blue mounted chair", /obj/structure/bed/chair/bay/chair/padded/blue, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("beige mounted chair", /obj/structure/bed/chair/bay/chair/padded/beige, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("lime mounted chair", /obj/structure/bed/chair/bay/chair/padded/lime, 2, one_per_turf = 1, on_floor = 1, time = 10), - new/datum/stack_recipe("yellow mounted chair", /obj/structure/bed/chair/bay/chair/padded/yellow, 2, one_per_turf = 1, on_floor = 1, time = 10) - )) - recipes += new/datum/stack_recipe_list("mounted comfy chairs", list( - new/datum/stack_recipe("mounted comfy chair", /obj/structure/bed/chair/bay/comfy, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("red mounted comfy chair", /obj/structure/bed/chair/bay/comfy/red, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("brown mounted comfy chair", /obj/structure/bed/chair/bay/comfy/brown, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("teal mounted comfy chair", /obj/structure/bed/chair/bay/comfy/teal, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("black mounted comfy chair", /obj/structure/bed/chair/bay/comfy/black, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("green mounted comfy chair", /obj/structure/bed/chair/bay/comfy/green, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("purple mounted comfy chair", /obj/structure/bed/chair/bay/comfy/purple, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("blue mounted comfy chair", /obj/structure/bed/chair/bay/comfy/blue, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("beige mounted comfy chair", /obj/structure/bed/chair/bay/comfy/beige, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("lime mounted comfy chair", /obj/structure/bed/chair/bay/comfy/lime, 3, one_per_turf = 1, on_floor = 1, time = 20), - new/datum/stack_recipe("yellow mounted comfy chair", /obj/structure/bed/chair/bay/comfy/yellow, 3, one_per_turf = 1, on_floor = 1, time = 20) - )) - recipes += new/datum/stack_recipe("mounted captain's chair", /obj/structure/bed/chair/bay/comfy/captain, 4, one_per_turf = 1, on_floor = 1, time = 20) - recipes += new/datum/stack_recipe("dropship seat", /obj/structure/bed/chair/bay/shuttle, 4, one_per_turf = 1, on_floor = 1, time = 20) - recipes += new/datum/stack_recipe("small teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/smallnest, 2, one_per_turf = 1, on_floor = 1, time = 10) - recipes += new/datum/stack_recipe("large teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/bignest, 4, one_per_turf = 1, on_floor = 1, time = 20) - recipes += new/datum/stack_recipe("dance pole", /obj/structure/dancepole, 2, one_per_turf = 1, on_floor = 1, time = 20) - recipes += new/datum/stack_recipe("light switch frame", /obj/item/frame/lightswitch, 2) - recipes += new/datum/stack_recipe_list("sofas", list( - new/datum/stack_recipe("red sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("red sofa left", /obj/structure/bed/chair/sofa/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("red sofa right", /obj/structure/bed/chair/sofa/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("red sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("brown sofa middle", /obj/structure/bed/chair/sofa/brown, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("brown sofa left", /obj/structure/bed/chair/sofa/brown/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("brown sofa right", /obj/structure/bed/chair/sofa/brown/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("brown sofa corner", /obj/structure/bed/chair/sofa/brown/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("teal sofa middle", /obj/structure/bed/chair/sofa/teal, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("teal sofa left", /obj/structure/bed/chair/sofa/teal/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("teal sofa right", /obj/structure/bed/chair/sofa/teal/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("teal sofa corner", /obj/structure/bed/chair/sofa/teal/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("black sofa middle", /obj/structure/bed/chair/sofa/black, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("black sofa left", /obj/structure/bed/chair/sofa/black/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("black sofa right", /obj/structure/bed/chair/sofa/black/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("black sofa corner", /obj/structure/bed/chair/sofa/black/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("green sofa middle", /obj/structure/bed/chair/sofa/green, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("green sofa left", /obj/structure/bed/chair/sofa/green/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("green sofa right", /obj/structure/bed/chair/sofa/green/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("green sofa corner", /obj/structure/bed/chair/sofa/green/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("purple sofa middle", /obj/structure/bed/chair/sofa/purp, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("purple sofa left", /obj/structure/bed/chair/sofa/purp/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("purple sofa right", /obj/structure/bed/chair/sofa/purp/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("purple sofa corner", /obj/structure/bed/chair/sofa/purp/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("blue sofa middle", /obj/structure/bed/chair/sofa/blue, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("blue sofa left", /obj/structure/bed/chair/sofa/blue/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("blue sofa right", /obj/structure/bed/chair/sofa/blue/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("blue sofa corner", /obj/structure/bed/chair/sofa/blue/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("beige sofa middle", /obj/structure/bed/chair/sofa/beige, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("beige sofa left", /obj/structure/bed/chair/sofa/beige/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("beige sofa right", /obj/structure/bed/chair/sofa/beige/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("beige sofa corner", /obj/structure/bed/chair/sofa/beige/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("lime sofa middle", /obj/structure/bed/chair/sofa/lime, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("lime sofa left", /obj/structure/bed/chair/sofa/lime/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("lime sofa right", /obj/structure/bed/chair/sofa/lime/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("lime sofa corner", /obj/structure/bed/chair/sofa/lime/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("yellow sofa middle", /obj/structure/bed/chair/sofa/yellow, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("yellow sofa left", /obj/structure/bed/chair/sofa/yellow/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("yellow sofa right", /obj/structure/bed/chair/sofa/yellow/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("yellow sofa corner", /obj/structure/bed/chair/sofa/yellow/corner, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("orange sofa middle", /obj/structure/bed/chair/sofa/orange, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("orange sofa left", /obj/structure/bed/chair/sofa/orange/left, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("orange sofa right", /obj/structure/bed/chair/sofa/orange/right, 1, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \ - )) - -/datum/material/durasteel/generate_recipes() - . = ..() - recipes += new/datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2) - recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30) - -/datum/material/plastitanium/generate_recipes() - . = ..() - recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20) diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm deleted file mode 100644 index 3fd995378c5..00000000000 --- a/code/modules/materials/material_sheets.dm +++ /dev/null @@ -1,565 +0,0 @@ -// Stacked resources. They use a material datum for a lot of inherited values. -// If you're adding something here, make sure to add it to fifty_spawner_mats.dm as well -/obj/item/stack/material - force = 5.0 - throwforce = 5 - w_class = ITEMSIZE_NORMAL - throw_speed = 3 - throw_range = 3 - center_of_mass = null - max_amount = 50 - item_icons = list( - slot_l_hand_str = 'icons/mob/items/lefthand_material.dmi', - slot_r_hand_str = 'icons/mob/items/righthand_material.dmi', - ) - - var/default_type = DEFAULT_WALL_MATERIAL - var/datum/material/material - var/perunit = SHEET_MATERIAL_AMOUNT - var/apply_colour //temp pending icon rewrite - drop_sound = 'sound/items/drop/axe.ogg' - pickup_sound = 'sound/items/pickup/axe.ogg' - -/obj/item/stack/material/Initialize() - . = ..() - - randpixel_xy() - - if(!default_type) - default_type = DEFAULT_WALL_MATERIAL - material = get_material_by_name("[default_type]") - if(!material) - return INITIALIZE_HINT_QDEL - - recipes = material.get_recipes() - stacktype = material.stack_type - if(islist(material.stack_origin_tech)) - origin_tech = material.stack_origin_tech.Copy() - - if(apply_colour) - color = material.icon_colour - - if(!material.conductive) - flags |= NOCONDUCT - - matter = material.get_matter() - update_strings() - -/obj/item/stack/material/get_material() - return material - -/obj/item/stack/material/proc/update_strings() - // Update from material datum. - singular_name = material.sheet_singular_name - - if(amount>1) - name = "[material.use_name] [material.sheet_plural_name]" - desc = "A stack of [material.use_name] [material.sheet_plural_name]." - gender = PLURAL - else - name = "[material.use_name] [material.sheet_singular_name]" - desc = "A [material.sheet_singular_name] of [material.use_name]." - gender = NEUTER - -/obj/item/stack/material/use(var/used) - . = ..() - update_strings() - return - -/obj/item/stack/material/transfer_to(obj/item/stack/S, var/tamount=null, var/type_verified) - var/obj/item/stack/material/M = S - if(!istype(M) || material.name != M.material.name) - return 0 - var/transfer = ..(S,tamount,1) - if(src) update_strings() - if(M) M.update_strings() - return transfer - -/obj/item/stack/material/attack_self(var/mob/user) - if(!material.build_windows(user, src)) - ..() - -/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user) - if(istype(W,/obj/item/stack/cable_coil)) - material.build_wired_product(user, W, src) - return - else if(istype(W, /obj/item/stack/rods)) - material.build_rod_product(user, W, src) - return - return ..() - -//VOREStation Add -/obj/item/stack/material/attack(mob/living/M as mob, mob/living/user as mob) - if(M.handle_eat_minerals(src, user)) - return - ..() - -/obj/item/stack/material/attack_generic(var/mob/living/user) //Allow adminbussed mobs to eat ore if they click it while NOT on help intent. - if(user.handle_eat_minerals(src)) - return - ..() -//VOREStation Add End - -/obj/item/stack/material/iron - name = "iron" - icon_state = "sheet-ingot" - default_type = "iron" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/lead - name = "lead" - icon_state = "sheet-ingot" - default_type = "lead" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/sandstone - name = "sandstone brick" - icon_state = "sheet-sandstone" - default_type = "sandstone" - no_variants = FALSE - drop_sound = 'sound/items/drop/boots.ogg' - pickup_sound = 'sound/items/pickup/boots.ogg' - -/obj/item/stack/material/marble - name = "marble brick" - icon_state = "sheet-marble" - default_type = "marble" - no_variants = FALSE - drop_sound = 'sound/items/drop/boots.ogg' - pickup_sound = 'sound/items/pickup/boots.ogg' - -/obj/item/stack/material/diamond - name = "diamond" - icon_state = "sheet-diamond" - default_type = "diamond" - drop_sound = 'sound/items/drop/glass.ogg' - pickup_sound = 'sound/items/pickup/glass.ogg' - -/obj/item/stack/material/uranium - name = "uranium" - icon_state = "sheet-uranium" - default_type = "uranium" - no_variants = FALSE - -/obj/item/stack/material/phoron - name = "solid phoron" - icon_state = "sheet-phoron" - default_type = "phoron" - no_variants = FALSE - drop_sound = 'sound/items/drop/glass.ogg' - pickup_sound = 'sound/items/pickup/glass.ogg' - -/obj/item/stack/material/plastic - name = "plastic" - icon_state = "sheet-plastic" - default_type = "plastic" - no_variants = FALSE - -/obj/item/stack/material/graphite - name = "graphite" - icon_state = "sheet-puck" - default_type = MAT_GRAPHITE - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/gold - name = "gold" - icon_state = "sheet-ingot" - default_type = "gold" - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/silver - name = "silver" - icon_state = "sheet-ingot" - default_type = "silver" - no_variants = FALSE - apply_colour = TRUE - -//Valuable resource, cargo can sell it. -/obj/item/stack/material/platinum - name = "platinum" - icon_state = "sheet-adamantine" - default_type = "platinum" - no_variants = FALSE - apply_colour = TRUE - -//Extremely valuable to Research. -/obj/item/stack/material/mhydrogen - name = "metallic hydrogen" - icon_state = "sheet-mythril" - default_type = "mhydrogen" - no_variants = FALSE - -//Fuel for MRSPACMAN generator. -/obj/item/stack/material/tritium - name = "tritium" - icon_state = "sheet-puck" - default_type = "tritium" - apply_colour = TRUE - no_variants = FALSE - -/obj/item/stack/material/osmium - name = "osmium" - icon_state = "sheet-ingot" - default_type = "osmium" - apply_colour = 1 - no_variants = FALSE - -//R-UST port -// Fusion fuel. -/obj/item/stack/material/deuterium - name = "deuterium" - icon_state = "sheet-puck" - default_type = "deuterium" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/steel - name = DEFAULT_WALL_MATERIAL - icon_state = "sheet-refined" - default_type = DEFAULT_WALL_MATERIAL - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/steel/hull - name = MAT_STEELHULL - default_type = MAT_STEELHULL - -/obj/item/stack/material/plasteel - name = "plasteel" - icon_state = "sheet-reinforced" - default_type = "plasteel" - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/plasteel/hull - name = MAT_PLASTEELHULL - default_type = MAT_PLASTEELHULL - -/obj/item/stack/material/durasteel - name = "durasteel" - icon_state = "sheet-reinforced" - item_state = "sheet-metal" - default_type = "durasteel" - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/durasteel/hull - name = MAT_DURASTEELHULL - -/obj/item/stack/material/titanium - name = MAT_TITANIUM - icon_state = "sheet-refined" - apply_colour = TRUE - item_state = "sheet-silver" - default_type = MAT_TITANIUM - no_variants = FALSE - -/obj/item/stack/material/titanium/hull - name = MAT_TITANIUMHULL - default_type = MAT_TITANIUMHULL - -// Particle Smasher and Exotic material. -/obj/item/stack/material/verdantium - name = MAT_VERDANTIUM - icon_state = "sheet-wavy" - item_state = "mhydrogen" - default_type = MAT_VERDANTIUM - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/morphium - name = MAT_MORPHIUM - icon_state = "sheet-wavy" - item_state = "mhydrogen" - default_type = MAT_MORPHIUM - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/morphium/hull - name = MAT_MORPHIUMHULL - default_type = MAT_MORPHIUMHULL - -/obj/item/stack/material/valhollide - name = MAT_VALHOLLIDE - icon_state = "sheet-gem" - item_state = "diamond" - default_type = MAT_VALHOLLIDE - no_variants = FALSE - apply_colour = TRUE - -// Forged in the equivalent of Hell, one piece at a time. -/obj/item/stack/material/supermatter - name = MAT_SUPERMATTER - icon_state = "sheet-super" - item_state = "diamond" - default_type = MAT_SUPERMATTER - apply_colour = TRUE - -/obj/item/stack/material/supermatter/proc/update_mass() // Due to how dangerous they can be, the item will get heavier and larger the more are in the stack. - slowdown = amount / 10 - w_class = min(5, round(amount / 10) + 1) - throw_range = round(amount / 7) + 1 - -/obj/item/stack/material/supermatter/use(var/used) - . = ..() - update_mass() - return - -/obj/item/stack/material/supermatter/attack_hand(mob/user) - . = ..() - - update_mass() - SSradiation.radiate(src, 5 + amount) - var/mob/living/M = user - if(!istype(M)) - return - - var/burn_user = TRUE - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - var/obj/item/clothing/gloves/G = H.gloves - if(istype(G) && ((G.flags & THICKMATERIAL && prob(70)) || istype(G, /obj/item/clothing/gloves/gauntlets))) - burn_user = FALSE - - if(burn_user) - H.visible_message("\The [src] flashes as it scorches [H]'s hands!") - H.apply_damage(amount / 2 + 5, BURN, "r_hand", used_weapon="Supermatter Chunk") - H.apply_damage(amount / 2 + 5, BURN, "l_hand", used_weapon="Supermatter Chunk") - H.drop_from_inventory(src, get_turf(H)) - return - - if(istype(user, /mob/living/silicon/robot)) - burn_user = FALSE - - if(burn_user) - M.apply_damage(amount, BURN, null, used_weapon="Supermatter Chunk") - -/obj/item/stack/material/supermatter/ex_act(severity) // An incredibly hard to manufacture material, SM chunks are unstable by their 'stabilized' nature. - if(prob((4 / severity) * 20)) - SSradiation.radiate(get_turf(src), amount * 4) - explosion(get_turf(src),round(amount / 12) , round(amount / 6), round(amount / 3), round(amount / 25)) - qdel(src) - return - SSradiation.radiate(get_turf(src), amount * 2) - ..() - -/obj/item/stack/material/wood - name = "wooden plank" - icon_state = "sheet-wood" - default_type = MAT_WOOD - strict_color_stacking = TRUE - apply_colour = 1 - drop_sound = 'sound/items/drop/wooden.ogg' - pickup_sound = 'sound/items/pickup/wooden.ogg' - no_variants = FALSE - -/obj/item/stack/material/wood/sif - name = "alien wooden plank" - color = "#0099cc" - default_type = MAT_SIFWOOD - -/obj/item/stack/material/log - name = "log" - icon_state = "sheet-log" - default_type = MAT_LOG - no_variants = FALSE - color = "#824B28" - max_amount = 25 - w_class = ITEMSIZE_HUGE - description_info = "Use inhand to craft things, or use a sharp and edged object on this to convert it into two wooden planks." - var/plank_type = /obj/item/stack/material/wood - drop_sound = 'sound/items/drop/wooden.ogg' - pickup_sound = 'sound/items/pickup/wooden.ogg' - -/obj/item/stack/material/log/sif - name = "alien log" - default_type = MAT_SIFLOG - color = "#0099cc" - plank_type = /obj/item/stack/material/wood/sif - -/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user) - if(!istype(W) || W.force <= 0) - return ..() - if(W.sharp && W.edge) - var/time = (3 SECONDS / max(W.force / 10, 1)) * W.toolspeed - user.setClickCooldown(time) - if(do_after(user, time, src) && use(1)) - to_chat(user, "You cut up a log into planks.") - playsound(src, 'sound/effects/woodcutting.ogg', 50, 1) - var/obj/item/stack/material/wood/existing_wood = null - for(var/obj/item/stack/material/wood/M in user.loc) - if(M.material.name == src.material.name) - existing_wood = M - break - - var/obj/item/stack/material/wood/new_wood = new plank_type(user.loc) - new_wood.amount = 2 - if(existing_wood && new_wood.transfer_to(existing_wood)) - to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.") - else - return ..() - - -/obj/item/stack/material/cloth - name = "cloth" - icon_state = "sheet-cloth" - default_type = "cloth" - no_variants = FALSE - pass_color = TRUE - strict_color_stacking = TRUE - drop_sound = 'sound/items/drop/clothing.ogg' - pickup_sound = 'sound/items/pickup/clothing.ogg' - -/obj/item/stack/material/cloth/diyaab - color = "#c6ccf0" - -/obj/item/stack/material/resin - name = "resin" - icon_state = "sheet-resin" - default_type = "resin" - no_variants = TRUE - apply_colour = TRUE - pass_color = TRUE - strict_color_stacking = TRUE - -/obj/item/stack/material/cardboard - name = "cardboard" - icon_state = "sheet-card" - default_type = "cardboard" - no_variants = FALSE - pass_color = TRUE - strict_color_stacking = TRUE - drop_sound = 'sound/items/drop/cardboardbox.ogg' - pickup_sound = 'sound/items/pickup/cardboardbox.ogg' - -/obj/item/stack/material/snow - name = "snow" - desc = "The temptation to build a snowman rises." - icon_state = "sheet-snow" - drop_sound = 'sound/items/drop/gloves.ogg' - pickup_sound = 'sound/items/pickup/clothing.ogg' - default_type = "snow" - -/obj/item/stack/material/snowbrick - name = "snow brick" - desc = "For all of your igloo building needs." - icon_state = "sheet-snowbrick" - default_type = "packed snow" - drop_sound = 'sound/items/drop/gloves.ogg' - pickup_sound = 'sound/items/pickup/clothing.ogg' - -/obj/item/stack/material/leather - name = "leather" - desc = "The by-product of mob grinding." - icon_state = "sheet-leather" - default_type = MAT_LEATHER - no_variants = FALSE - pass_color = TRUE - strict_color_stacking = TRUE - drop_sound = 'sound/items/drop/leather.ogg' - pickup_sound = 'sound/items/pickup/leather.ogg' - -/obj/item/stack/material/chitin - name = "chitin" - desc = "The by-product of mob grinding." - icon_state = "chitin" - default_type = MAT_CHITIN - no_variants = FALSE - pass_color = TRUE - strict_color_stacking = TRUE - drop_sound = 'sound/items/drop/leather.ogg' - pickup_sound = 'sound/items/pickup/leather.ogg' - -/obj/item/stack/material/glass - name = "glass" - icon_state = "sheet-transparent" - default_type = "glass" - no_variants = FALSE - drop_sound = 'sound/items/drop/glass.ogg' - pickup_sound = 'sound/items/pickup/glass.ogg' - apply_colour = TRUE - -/obj/item/stack/material/glass/reinforced - name = "reinforced glass" - icon_state = "sheet-rtransparent" - default_type = "rglass" - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/glass/phoronglass - name = "borosilicate glass" - desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures" - singular_name = "borosilicate glass sheet" - icon_state = "sheet-transparent" - default_type = "borosilicate glass" - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/glass/phoronrglass - name = "reinforced borosilicate glass" - desc = "This sheet is special platinum-glass alloy designed to withstand large temperatures. It is reinforced with few rods." - singular_name = "reinforced borosilicate glass sheet" - icon_state = "sheet-rtransparent" - default_type = "reinforced borosilicate glass" - no_variants = FALSE - apply_colour = TRUE - -/obj/item/stack/material/bronze - name = "bronze" - icon_state = "sheet-ingot" - singular_name = "bronze ingot" - default_type = "bronze" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/tin - name = "tin" - icon_state = "sheet-ingot" - singular_name = "tin ingot" - default_type = "tin" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/copper - name = "copper" - icon_state = "sheet-ingot" - singular_name = "copper ingot" - default_type = "copper" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/painite - name = "painite" - icon_state = "sheet-gem" - singular_name = "painite gem" - default_type = "painite" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/void_opal - name = "void opal" - icon_state = "sheet-void_opal" - singular_name = "void opal" - default_type = "void opal" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/quartz - name = "quartz" - icon_state = "sheet-gem" - singular_name = "quartz gem" - default_type = "quartz" - apply_colour = 1 - no_variants = FALSE - -/obj/item/stack/material/aluminium - name = "aluminium" - icon_state = "sheet-ingot" - singular_name = "aluminium ingot" - default_type = "aluminium" - apply_colour = 1 - no_variants = FALSE diff --git a/code/modules/materials/material_sheets_vr.dm b/code/modules/materials/material_sheets_vr.dm deleted file mode 100644 index 71d7e7d3ea8..00000000000 --- a/code/modules/materials/material_sheets_vr.dm +++ /dev/null @@ -1,66 +0,0 @@ -/obj/item/stack/material/titanium - icon = 'icons/obj/stacks_vr.dmi' - icon_state = "sheet-titanium" - no_variants = FALSE - -/obj/fiftyspawner/titanium - name = "stack of titanium" - type_to_spawn = /obj/item/stack/material/titanium - -/obj/item/stack/material/glass/titanium - name = "ti-glass sheets" - icon = 'icons/obj/stacks_vr.dmi' - icon_state = "sheet-titaniumglass" - item_state = "sheet-silver" - no_variants = FALSE - drop_sound = 'sound/items/drop/glass.ogg' - default_type = MAT_TITANIUMGLASS - -/obj/fiftyspawner/titanium_glass - name = "stack of ti-glass" - type_to_spawn = /obj/item/stack/material/glass/titanium - -/obj/item/stack/material/plastitanium - name = "plastitanium sheets" - icon = 'icons/obj/stacks_vr.dmi' - icon_state = "sheet-plastitanium" - item_state = "sheet-silver" - no_variants = FALSE - default_type = MAT_PLASTITANIUM - -/obj/fiftyspawner/plastitanium - name = "stack of plastitanium" - type_to_spawn = /obj/item/stack/material/plastitanium - -/obj/item/stack/material/plastitanium/hull - name = "plastitanium hull sheets" - icon = 'icons/obj/stacks_vr.dmi' - icon_state = "sheet-plastitanium" - item_state = "sheet-silver" - no_variants = FALSE - default_type = MAT_PLASTITANIUMHULL - -/obj/fiftyspawner/plastitanium_hull - name = "stack of plastitanium" - type_to_spawn = /obj/item/stack/material/plastitanium/hull - -/obj/item/stack/material/glass/plastitanium - name = "plastitanium glass sheets" - icon = 'icons/obj/stacks_vr.dmi' - icon_state = "sheet-plastitaniumglass" - item_state = "sheet-silver" - no_variants = FALSE - drop_sound = 'sound/items/drop/glass.ogg' - default_type = MAT_PLASTITANIUMGLASS - -/obj/fiftyspawner/plastitanium_glass - name = "stack of plastitanium glass" - type_to_spawn = /obj/item/stack/material/glass/plastitanium - -/obj/item/stack/material/gold/hull - name = "gold hull sheets" - icon = 'icons/obj/stacks_vr.dmi' - icon_state = "sheet-plastitanium" - item_state = "sheet-silver" - no_variants = FALSE - default_type = MAT_GOLDHULL \ No newline at end of file diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm deleted file mode 100644 index b591ee26c54..00000000000 --- a/code/modules/materials/materials.dm +++ /dev/null @@ -1,1295 +0,0 @@ -/* - MATERIAL DATUMS - This data is used by various parts of the game for basic physical properties and behaviors - of the metals/materials used for constructing many objects. Each var is commented and should be pretty - self-explanatory but the various object types may have their own documentation. ~Z - - PATHS THAT USE DATUMS - turf/simulated/wall - obj/item/weapon/material - obj/structure/barricade - obj/item/stack/material - obj/structure/table - - VALID ICONS - WALLS - stone - metal - solid - resin - ONLY WALLS - cult - hull - curvy - jaggy - brick - REINFORCEMENT - reinf_over - reinf_mesh - reinf_cult - reinf_metal - DOORS - stone - metal - resin - wood -*/ - -// Assoc list containing all material datums indexed by name. -var/list/name_to_material - -//Returns the material the object is made of, if applicable. -//Will we ever need to return more than one value here? Or should we just return the "dominant" material. -/obj/proc/get_material() - return null - -//mostly for convenience -/obj/proc/get_material_name() - var/datum/material/material = get_material() - if(material) - return material.name - -// Builds the datum list above. -/proc/populate_material_list(force_remake=0) - if(name_to_material && !force_remake) return // Already set up! - name_to_material = list() - for(var/type in subtypesof(/datum/material)) - var/datum/material/new_mineral = new type - if(!new_mineral.name) - qdel(new_mineral) - continue - name_to_material[lowertext(new_mineral.name)] = new_mineral - return 1 - -// Safety proc to make sure the material list exists before trying to grab from it. -/proc/get_material_by_name(name) - if(!name_to_material) - populate_material_list() - return name_to_material[name] - -/proc/material_display_name(name) - var/datum/material/material = get_material_by_name(name) - if(material) - return material.display_name - return null - -// Material definition and procs follow. -/datum/material - var/name // Unique name for use in indexing the list. - var/display_name // Prettier name for display. - var/use_name - var/flags = 0 // Various status modifiers. - var/sheet_singular_name = "sheet" - var/sheet_plural_name = "sheets" - var/is_fusion_fuel - - // Shards/tables/structures - var/shard_type = SHARD_SHRAPNEL // Path of debris object. - var/shard_icon // Related to above. - var/shard_can_repair = 1 // Can shards be turned into sheets with a welder? - var/list/recipes // Holder for all recipes usable with a sheet of this material. - var/destruction_desc = "breaks apart" // Fancy string for barricades/tables/objects exploding. - - // Icons - var/icon_colour // Colour applied to products of this material. - var/icon_base = "metal" // Wall and table base icon tag. See header. - var/door_icon_base = "metal" // Door base icon tag. See header. - var/icon_reinf = "reinf_metal" // Overlay used - var/list/stack_origin_tech = list(TECH_MATERIAL = 1) // Research level for stacks. - var/pass_stack_colors = FALSE // Will stacks made from this material pass their colors onto objects? - - // Attributes - var/cut_delay = 0 // Delay in ticks when cutting through this wall. - var/radioactivity // Radiation var. Used in wall and object processing to irradiate surroundings. - var/ignition_point // K, point at which the material catches on fire. - var/melting_point = 1800 // K, walls will take damage if they're next to a fire hotter than this - var/integrity = 150 // General-use HP value for products. - var/protectiveness = 10 // How well this material works as armor. Higher numbers are better, diminishing returns applies. - var/opacity = 1 // Is the material transparent? 0.5< makes transparent walls/doors. - var/reflectivity = 0 // How reflective to light is the material? Currently used for laser reflection and defense. - var/explosion_resistance = 5 // Only used by walls currently. - var/negation = 0 // Objects that respect this will randomly absorb impacts with this var as the percent chance. - var/spatial_instability = 0 // Objects that have trouble staying in the same physical space by sheer laws of nature have this. Percent for respecting items to cause teleportation. - var/conductive = 1 // Objects without this var add NOCONDUCT to flags on spawn. - var/conductivity = null // How conductive the material is. Iron acts as the baseline, at 10. - var/list/composite_material // If set, object matter var will be a list containing these values. - var/luminescence - var/radiation_resistance = 0 // Radiation resistance, which is added on top of a material's weight for blocking radiation. Needed to make lead special without superrobust weapons. - var/supply_conversion_value // Supply points per sheet that this material sells for. - - // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods. - var/created_window - var/created_fulltile_window - var/rod_product - var/wire_product - var/list/window_options = list() - - // Damage values. - var/hardness = 60 // Prob of wall destruction by hulk, used for edge damage in weapons. Also used for bullet protection in armor. - var/weight = 20 // Determines blunt damage/throwforce for weapons. - - // Noise when someone is faceplanted onto a table made of this material. - var/tableslam_noise = 'sound/weapons/tablehit1.ogg' - // Noise made when a simple door made of this material opens or closes. - var/dooropen_noise = 'sound/effects/stonedoor_openclose.ogg' - // Path to resulting stacktype. Todo remove need for this. - var/stack_type - // Wallrot crumble message. - var/rotting_touch_message = "crumbles under your touch" - -// Placeholders for light tiles and rglass. -/datum/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) - if(!rod_product) - to_chat(user, "You cannot make anything out of \the [target_stack]") - return - if(used_stack.get_amount() < 1 || target_stack.get_amount() < 1) - to_chat(user, "You need one rod and one sheet of [display_name] to make anything useful.") - return - used_stack.use(1) - target_stack.use(1) - var/obj/item/stack/S = new rod_product(get_turf(user)) - S.add_fingerprint(user) - S.add_to_stacks(user) - -/datum/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack) - if(!wire_product) - to_chat(user, "You cannot make anything out of \the [target_stack]") - return - if(used_stack.get_amount() < 5 || target_stack.get_amount() < 1) - to_chat(user, "You need five wires and one sheet of [display_name] to make anything useful.") - return - - used_stack.use(5) - target_stack.use(1) - to_chat(user, "You attach wire to the [name].") - var/obj/item/product = new wire_product(get_turf(user)) - user.put_in_hands(product) - -// Make sure we have a display name and shard icon even if they aren't explicitly set. -/datum/material/New() - ..() - if(!display_name) - display_name = name - if(!use_name) - use_name = display_name - if(!shard_icon) - shard_icon = shard_type - -// This is a placeholder for proper integration of windows/windoors into the system. -/datum/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) - return 0 - -// Weapons handle applying a divisor for this value locally. -/datum/material/proc/get_blunt_damage() - return weight //todo - -// Return the matter comprising this material. -/datum/material/proc/get_matter() - var/list/temp_matter = list() - if(islist(composite_material)) - for(var/material_string in composite_material) - temp_matter[material_string] = composite_material[material_string] - else if(SHEET_MATERIAL_AMOUNT) - temp_matter[name] = SHEET_MATERIAL_AMOUNT - return temp_matter - -// As above. -/datum/material/proc/get_edge_damage() - return hardness //todo - -// Snowflakey, only checked for alien doors at the moment. -/datum/material/proc/can_open_material_door(var/mob/living/user) - return 1 - -// Currently used for weapons and objects made of uranium to irradiate things. -/datum/material/proc/products_need_process() - return (radioactivity>0) //todo - -// Used by walls when qdel()ing to avoid neighbor merging. -/datum/material/placeholder - name = "placeholder" - -// Places a girder object when a wall is dismantled, also applies reinforced material. -/datum/material/proc/place_dismantled_girder(var/turf/target, var/datum/material/reinf_material, var/datum/material/girder_material) - var/obj/structure/girder/G = new(target) - if(reinf_material) - G.reinf_material = reinf_material - G.reinforce_girder() - if(girder_material) - if(istype(girder_material, /datum/material)) - girder_material = girder_material.name - G.set_material(girder_material) - - -// General wall debris product placement. -// Not particularly necessary aside from snowflakey cult girders. -/datum/material/proc/place_dismantled_product(var/turf/target) - place_sheet(target) - -// Debris product. Used ALL THE TIME. -/datum/material/proc/place_sheet(var/turf/target) - if(stack_type) - return new stack_type(target) - -// As above. -/datum/material/proc/place_shard(var/turf/target) - if(shard_type) - return new /obj/item/weapon/material/shard(target, src.name) - -// Used by walls and weapons to determine if they break or not. -/datum/material/proc/is_brittle() - return !!(flags & MATERIAL_BRITTLE) - -/datum/material/proc/combustion_effect(var/turf/T, var/temperature) - return - -// Used by walls to do on-touch things, after checking for crumbling and open-ability. -/datum/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) - return - -// Datum definitions follow. -/datum/material/uranium - name = "uranium" - stack_type = /obj/item/stack/material/uranium - radioactivity = 12 - icon_base = "stone" - icon_reinf = "reinf_stone" - icon_colour = "#007A00" - weight = 22 - stack_origin_tech = list(TECH_MATERIAL = 5) - door_icon_base = "stone" - supply_conversion_value = 2 - -/datum/material/diamond - name = "diamond" - stack_type = /obj/item/stack/material/diamond - flags = MATERIAL_UNMELTABLE - cut_delay = 60 - icon_colour = "#00FFE1" - opacity = 0.4 - reflectivity = 0.6 - conductive = 0 - conductivity = 1 - shard_type = SHARD_SHARD - tableslam_noise = 'sound/effects/Glasshit.ogg' - hardness = 100 - stack_origin_tech = list(TECH_MATERIAL = 6) - supply_conversion_value = 8 - -/datum/material/gold - name = "gold" - stack_type = /obj/item/stack/material/gold - icon_colour = "#EDD12F" - weight = 24 - hardness = 40 - conductivity = 41 - stack_origin_tech = list(TECH_MATERIAL = 4) - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - supply_conversion_value = 2 - -/datum/material/gold/bronze //placeholder for ashtrays - name = "bronze" - icon_colour = "#EDD12F" - -/datum/material/silver - name = "silver" - stack_type = /obj/item/stack/material/silver - icon_colour = "#D1E6E3" - weight = 22 - hardness = 50 - conductivity = 63 - stack_origin_tech = list(TECH_MATERIAL = 3) - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - supply_conversion_value = 2 - -//R-UST port -/datum/material/supermatter - name = "supermatter" - icon_colour = "#FFFF00" - stack_type = /obj/item/stack/material/supermatter - shard_type = SHARD_SHARD - radioactivity = 20 - stack_type = null - luminescence = 3 - ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE - icon_base = "stone" - shard_type = SHARD_SHARD - hardness = 30 - door_icon_base = "stone" - sheet_singular_name = "crystal" - sheet_plural_name = "crystals" - is_fusion_fuel = 1 - stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 5, TECH_BLUESPACE = 4) - -/datum/material/phoron - name = "phoron" - stack_type = /obj/item/stack/material/phoron - ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE - icon_base = "stone" - icon_colour = "#FC2BC5" - shard_type = SHARD_SHARD - hardness = 30 - stack_origin_tech = list(TECH_MATERIAL = 2, TECH_PHORON = 2) - door_icon_base = "stone" - sheet_singular_name = "crystal" - sheet_plural_name = "crystals" - supply_conversion_value = 5 - -/* -// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately. -/datum/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier) - if(isnull(ignition_point)) - return 0 - if(temperature < ignition_point) - return 0 - var/totalPhoron = 0 - for(var/turf/simulated/floor/target_tile in range(2,T)) - var/phoronToDeduce = (temperature/30) * effect_multiplier - totalPhoron += phoronToDeduce - target_tile.assume_gas("phoron", phoronToDeduce, 200+T0C) - spawn (0) - target_tile.hotspot_expose(temperature, 400) - return round(totalPhoron/100) -*/ - -/datum/material/stone - name = "sandstone" - stack_type = /obj/item/stack/material/sandstone - icon_base = "stone" - icon_reinf = "reinf_stone" - icon_colour = "#D9C179" - shard_type = SHARD_STONE_PIECE - weight = 22 - hardness = 55 - protectiveness = 5 // 20% - conductive = 0 - conductivity = 5 - door_icon_base = "stone" - sheet_singular_name = "brick" - sheet_plural_name = "bricks" - -/datum/material/stone/marble - name = "marble" - icon_colour = "#AAAAAA" - weight = 26 - hardness = 30 //VOREStation Edit - Please. - integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system - stack_type = /obj/item/stack/material/marble - supply_conversion_value = 2 - -/datum/material/steel - name = DEFAULT_WALL_MATERIAL - stack_type = /obj/item/stack/material/steel - integrity = 150 - conductivity = 11 // Assuming this is carbon steel, it would actually be slightly less conductive than iron, but lets ignore that. - protectiveness = 10 // 33% - icon_base = "solid" - icon_reinf = "reinf_over" - icon_colour = "#666666" - -/datum/material/steel/hull - name = MAT_STEELHULL - stack_type = /obj/item/stack/material/steel/hull - integrity = 250 - explosion_resistance = 10 - icon_base = "hull" - icon_reinf = "reinf_mesh" - icon_colour = "#666677" - -/datum/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets. - new /obj/item/stack/material/steel(target) - -/datum/material/diona - name = "biomass" - icon_colour = null - stack_type = null - integrity = 600 - icon_base = "diona" - icon_reinf = "noreinf" - -/datum/material/diona/place_dismantled_product() - return - -/datum/material/diona/place_dismantled_girder(var/turf/target) - spawn_diona_nymph(target) - -/datum/material/steel/holographic - name = "holo" + DEFAULT_WALL_MATERIAL - display_name = DEFAULT_WALL_MATERIAL - stack_type = null - shard_type = SHARD_NONE - -/datum/material/plasteel - name = "plasteel" - stack_type = /obj/item/stack/material/plasteel - integrity = 400 - melting_point = 6000 - icon_base = "solid" - icon_reinf = "reinf_over" - icon_colour = "#777777" - explosion_resistance = 25 - hardness = 80 - weight = 23 - protectiveness = 20 // 50% - conductivity = 13 // For the purposes of balance. - stack_origin_tech = list(TECH_MATERIAL = 2) - composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT, "platinum" = SHEET_MATERIAL_AMOUNT) //todo - supply_conversion_value = 6 - -/datum/material/plasteel/hull - name = MAT_PLASTEELHULL - stack_type = /obj/item/stack/material/plasteel/hull - integrity = 600 - icon_base = "hull" - icon_reinf = "reinf_mesh" - icon_colour = "#777788" - explosion_resistance = 40 - -/datum/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. - new /obj/item/stack/material/plasteel(target) - -// Very rare alloy that is reflective, should be used sparingly. -/datum/material/durasteel - name = "durasteel" - stack_type = /obj/item/stack/material/durasteel/hull - integrity = 600 - melting_point = 7000 - icon_base = "metal" - icon_reinf = "reinf_metal" - icon_colour = "#6EA7BE" - explosion_resistance = 75 - hardness = 100 - weight = 28 - protectiveness = 60 // 75% - reflectivity = 0.7 // Not a perfect mirror, but close. - stack_origin_tech = list(TECH_MATERIAL = 8) - composite_material = list("plasteel" = SHEET_MATERIAL_AMOUNT, "diamond" = SHEET_MATERIAL_AMOUNT) //shrug - supply_conversion_value = 9 - -/datum/material/durasteel/hull //The 'Hardball' of starship hulls. - name = MAT_DURASTEELHULL - icon_base = "hull" - icon_reinf = "reinf_mesh" - icon_colour = "#45829a" - explosion_resistance = 90 - reflectivity = 0.9 - -/datum/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets. - new /obj/item/stack/material/durasteel(target) - -/datum/material/plasteel/titanium - name = MAT_TITANIUM - stack_type = /obj/item/stack/material/titanium - conductivity = 2.38 - icon_base = "metal" - door_icon_base = "metal" - icon_colour = "#D1E6E3" - icon_reinf = "reinf_metal" - composite_material = null - -/datum/material/plasteel/titanium/hull - name = MAT_TITANIUMHULL - stack_type = /obj/item/stack/material/titanium/hull - icon_base = "hull" - icon_reinf = "reinf_mesh" - -/datum/material/plasteel/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets. - new /obj/item/stack/material/titanium(target) - -/datum/material/glass - name = "glass" - stack_type = /obj/item/stack/material/glass - flags = MATERIAL_BRITTLE - icon_colour = "#00E1FF" - opacity = 0.3 - integrity = 100 - shard_type = SHARD_SHARD - tableslam_noise = 'sound/effects/Glasshit.ogg' - hardness = 30 - weight = 15 - protectiveness = 0 // 0% - conductive = 0 - conductivity = 1 // Glass shards don't conduct. - door_icon_base = "stone" - destruction_desc = "shatters" - window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2) - created_window = /obj/structure/window/basic - created_fulltile_window = /obj/structure/window/basic/full - rod_product = /obj/item/stack/material/glass/reinforced - -/datum/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack) - - if(!user || !used_stack || !created_window || !created_fulltile_window || !window_options.len) - return 0 - - if(!user.IsAdvancedToolUser()) - to_chat(user, "This task is too complex for your clumsy hands.") - return 1 - - var/turf/T = user.loc - if(!istype(T)) - to_chat(user, "You must be standing on open flooring to build a window.") - return 1 - - var/title = "Sheet-[used_stack.name] ([used_stack.get_amount()] sheet\s left)" - var/choice = input(title, "What would you like to construct?") as null|anything in window_options - - if(!choice || !used_stack || !user || used_stack.loc != user || user.stat || user.loc != T) - return 1 - - // Get data for building windows here. - var/list/possible_directions = cardinal.Copy() - var/window_count = 0 - for (var/obj/structure/window/check_window in user.loc) - window_count++ - possible_directions -= check_window.dir - for (var/obj/structure/windoor_assembly/check_assembly in user.loc) - window_count++ - possible_directions -= check_assembly.dir - for (var/obj/machinery/door/window/check_windoor in user.loc) - window_count++ - possible_directions -= check_windoor.dir - - // Get the closest available dir to the user's current facing. - var/build_dir = SOUTHWEST //Default to southwest for fulltile windows. - var/failed_to_build - - if(window_count >= 4) - failed_to_build = 1 - else - if(choice in list("One Direction","Windoor")) - if(possible_directions.len) - for(var/direction in list(user.dir, turn(user.dir,90), turn(user.dir,270), turn(user.dir,180))) - if(direction in possible_directions) - build_dir = direction - break - else - failed_to_build = 1 - if(failed_to_build) - to_chat(user, "There is no room in this location.") - return 1 - - var/build_path = /obj/structure/windoor_assembly - var/sheets_needed = window_options[choice] - if(choice == "Windoor") - if(is_reinforced()) - build_path = /obj/structure/windoor_assembly/secure - else if(choice == "Full Window") - build_path = created_fulltile_window - else - build_path = created_window - - if(used_stack.get_amount() < sheets_needed) - to_chat(user, "You need at least [sheets_needed] sheets to build this.") - return 1 - - // Build the structure and update sheet count etc. - used_stack.use(sheets_needed) - new build_path(T, build_dir, 1) - return 1 - -/datum/material/glass/proc/is_reinforced() - return (hardness > 35) //todo - -/datum/material/glass/reinforced - name = "rglass" - display_name = "reinforced glass" - stack_type = /obj/item/stack/material/glass/reinforced - flags = MATERIAL_BRITTLE - icon_colour = "#00E1FF" - opacity = 0.3 - integrity = 100 - shard_type = SHARD_SHARD - tableslam_noise = 'sound/effects/Glasshit.ogg' - hardness = 40 - weight = 30 - stack_origin_tech = list(TECH_MATERIAL = 2) - composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "glass" = SHEET_MATERIAL_AMOUNT) - window_options = list("One Direction" = 1, "Full Window" = 4, "Windoor" = 2) - created_window = /obj/structure/window/reinforced - created_fulltile_window = /obj/structure/window/reinforced/full - wire_product = null - rod_product = null - -/datum/material/glass/phoron - name = "borosilicate glass" - display_name = "borosilicate glass" - stack_type = /obj/item/stack/material/glass/phoronglass - flags = MATERIAL_BRITTLE - integrity = 100 - icon_colour = "#FC2BC5" - stack_origin_tech = list(TECH_MATERIAL = 4) - window_options = list("One Direction" = 1, "Full Window" = 4) - created_window = /obj/structure/window/phoronbasic - created_fulltile_window = /obj/structure/window/phoronbasic/full - wire_product = null - rod_product = /obj/item/stack/material/glass/phoronrglass - -/datum/material/glass/phoron/reinforced - name = "reinforced borosilicate glass" - display_name = "reinforced borosilicate glass" - stack_type = /obj/item/stack/material/glass/phoronrglass - stack_origin_tech = list(TECH_MATERIAL = 5) - composite_material = list() //todo - window_options = list("One Direction" = 1, "Full Window" = 4) - created_window = /obj/structure/window/phoronreinforced - created_fulltile_window = /obj/structure/window/phoronreinforced/full - hardness = 40 - weight = 30 - stack_origin_tech = list(TECH_MATERIAL = 2) - composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT / 2, "borosilicate glass" = SHEET_MATERIAL_AMOUNT) - rod_product = null - -/datum/material/plastic - name = "plastic" - stack_type = /obj/item/stack/material/plastic - flags = MATERIAL_BRITTLE - icon_base = "solid" - icon_reinf = "reinf_over" - icon_colour = "#CCCCCC" - hardness = 10 - weight = 12 - protectiveness = 5 // 20% - conductive = 0 - conductivity = 2 // For the sake of material armor diversity, we're gonna pretend this plastic is a good insulator. - melting_point = T0C+371 //assuming heat resistant plastic - stack_origin_tech = list(TECH_MATERIAL = 3) - -/datum/material/plastic/holographic - name = "holoplastic" - display_name = "plastic" - stack_type = null - shard_type = SHARD_NONE - -/datum/material/graphite - name = MAT_GRAPHITE - stack_type = /obj/item/stack/material/graphite - flags = MATERIAL_BRITTLE - icon_base = "solid" - icon_reinf = "reinf_mesh" - icon_colour = "#333333" - hardness = 75 - weight = 15 - integrity = 175 - protectiveness = 15 - conductivity = 18 - melting_point = T0C+3600 - radiation_resistance = 15 - stack_origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2) - -/datum/material/osmium - name = "osmium" - stack_type = /obj/item/stack/material/osmium - icon_colour = "#9999FF" - stack_origin_tech = list(TECH_MATERIAL = 5) - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - conductivity = 100 - supply_conversion_value = 6 - -/datum/material/tritium - name = "tritium" - stack_type = /obj/item/stack/material/tritium - icon_colour = "#777777" - stack_origin_tech = list(TECH_MATERIAL = 5) - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - is_fusion_fuel = 1 - conductive = 0 - -/datum/material/deuterium - name = "deuterium" - stack_type = /obj/item/stack/material/deuterium - icon_colour = "#999999" - stack_origin_tech = list(TECH_MATERIAL = 3) - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - is_fusion_fuel = 1 - conductive = 0 - -/datum/material/mhydrogen - name = "mhydrogen" - stack_type = /obj/item/stack/material/mhydrogen - icon_colour = "#E6C5DE" - stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 6, TECH_MAGNET = 5) - conductivity = 100 - is_fusion_fuel = 1 - supply_conversion_value = 6 - -/datum/material/platinum - name = "platinum" - stack_type = /obj/item/stack/material/platinum - icon_colour = "#9999FF" - weight = 27 - conductivity = 9.43 - stack_origin_tech = list(TECH_MATERIAL = 2) - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - supply_conversion_value = 5 - -/datum/material/iron - name = "iron" - stack_type = /obj/item/stack/material/iron - icon_colour = "#5C5454" - weight = 22 - conductivity = 10 - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - -/datum/material/lead - name = MAT_LEAD - stack_type = /obj/item/stack/material/lead - icon_colour = "#273956" - weight = 23 // Lead is a bit more dense than silver IRL, and silver has 22 ingame. - conductivity = 10 - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - radiation_resistance = 25 // Lead is Special and so gets to block more radiation than it normally would with just weight, totalling in 48 protection. - supply_conversion_value = 2 - -// Particle Smasher and other exotic materials. - -/datum/material/verdantium - name = MAT_VERDANTIUM - stack_type = /obj/item/stack/material/verdantium - icon_base = "metal" - door_icon_base = "metal" - icon_reinf = "reinf_metal" - icon_colour = "#4FE95A" - integrity = 80 - protectiveness = 15 - weight = 15 - hardness = 30 - shard_type = SHARD_SHARD - negation = 15 - conductivity = 60 - reflectivity = 0.3 - radiation_resistance = 5 - stack_origin_tech = list(TECH_MATERIAL = 6, TECH_POWER = 5, TECH_BIO = 4) - sheet_singular_name = "sheet" - sheet_plural_name = "sheets" - supply_conversion_value = 8 - -/datum/material/morphium - name = MAT_MORPHIUM - stack_type = /obj/item/stack/material/morphium - icon_base = "metal" - door_icon_base = "metal" - icon_colour = "#37115A" - icon_reinf = "reinf_metal" - protectiveness = 60 - integrity = 300 - conductive = 0 - conductivity = 1.5 - hardness = 90 - shard_type = SHARD_SHARD - weight = 30 - negation = 25 - explosion_resistance = 85 - reflectivity = 0.2 - radiation_resistance = 10 - stack_origin_tech = list(TECH_MATERIAL = 8, TECH_ILLEGAL = 1, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_ARCANE = 1) - supply_conversion_value = 13 - -/datum/material/morphium/hull - name = MAT_MORPHIUMHULL - stack_type = /obj/item/stack/material/morphium/hull - icon_base = "hull" - icon_reinf = "reinf_mesh" - -/datum/material/valhollide - name = MAT_VALHOLLIDE - stack_type = /obj/item/stack/material/valhollide - icon_base = "stone" - door_icon_base = "stone" - icon_reinf = "reinf_mesh" - icon_colour = "##FFF3B2" - protectiveness = 30 - integrity = 240 - weight = 30 - hardness = 45 - negation = 2 - conductive = 0 - conductivity = 5 - reflectivity = 0.5 - radiation_resistance = 20 - spatial_instability = 30 - stack_origin_tech = list(TECH_MATERIAL = 7, TECH_PHORON = 5, TECH_BLUESPACE = 5) - sheet_singular_name = "gem" - sheet_plural_name = "gems" - - -// Adminspawn only, do not let anyone get this. -/datum/material/alienalloy - name = "alienalloy" - display_name = "durable alloy" - stack_type = null - flags = MATERIAL_UNMELTABLE - icon_colour = "#6C7364" - integrity = 1200 - melting_point = 6000 // Hull plating. - explosion_resistance = 200 // Hull plating. - hardness = 500 - weight = 500 - protectiveness = 80 // 80% - -// Likewise. -/datum/material/alienalloy/elevatorium - name = "elevatorium" - display_name = "elevator panelling" - icon_colour = "#666666" - -// Ditto. -/datum/material/alienalloy/dungeonium - name = "dungeonium" - display_name = "ultra-durable" - icon_base = "dungeon" - icon_colour = "#FFFFFF" - -/datum/material/alienalloy/bedrock - name = "bedrock" - display_name = "impassable rock" - icon_base = "rock" - icon_colour = "#FFFFFF" - -/datum/material/alienalloy/alium - name = "alium" - display_name = "alien" - icon_base = "alien" - icon_colour = "#FFFFFF" - -/datum/material/resin - name = "resin" - icon_colour = "#35343a" - icon_base = "resin" - dooropen_noise = 'sound/effects/attackblob.ogg' - door_icon_base = "resin" - icon_reinf = "reinf_mesh" - melting_point = T0C+300 - sheet_singular_name = "blob" - sheet_plural_name = "blobs" - conductive = 0 - explosion_resistance = 60 - radiation_resistance = 10 - stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_BIO = 7) - stack_type = /obj/item/stack/material/resin - -/datum/material/resin/can_open_material_door(var/mob/living/user) - var/mob/living/carbon/M = user - if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) - return 1 - return 0 - -/datum/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L) - var/mob/living/carbon/M = L - if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) - to_chat(M, "\The [W] shudders under your touch, starting to become porous.") - playsound(W, 'sound/effects/attackblob.ogg', 50, 1) - if(do_after(L, 5 SECONDS)) - spawn(2) - playsound(W, 'sound/effects/attackblob.ogg', 100, 1) - W.dismantle_wall() - return 1 - return 0 - -/datum/material/wood - name = MAT_WOOD - stack_type = /obj/item/stack/material/wood - icon_colour = "#9c5930" - integrity = 50 - icon_base = "wood" - explosion_resistance = 2 - shard_type = SHARD_SPLINTER - shard_can_repair = 0 // you can't weld splinters back into planks - hardness = 15 - weight = 18 - protectiveness = 8 // 28% - conductive = 0 - conductivity = 1 - melting_point = T0C+300 //okay, not melting in this case, but hot enough to destroy wood - ignition_point = T0C+288 - stack_origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 1) - dooropen_noise = 'sound/effects/doorcreaky.ogg' - door_icon_base = "wood" - destruction_desc = "splinters" - sheet_singular_name = "plank" - sheet_plural_name = "planks" - -/datum/material/wood/log - name = MAT_LOG - icon_base = "log" - stack_type = /obj/item/stack/material/log - sheet_singular_name = null - sheet_plural_name = "pile" - pass_stack_colors = TRUE - supply_conversion_value = 1 - -/datum/material/wood/log/sif - name = MAT_SIFLOG - icon_colour = "#0099cc" // Cyan-ish - stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) - stack_type = /obj/item/stack/material/log/sif - -/datum/material/wood/holographic - name = "holowood" - display_name = "wood" - stack_type = null - shard_type = SHARD_NONE - -/datum/material/wood/sif - name = MAT_SIFWOOD - stack_type = /obj/item/stack/material/wood/sif - icon_colour = "#0099cc" // Cyan-ish - stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer. - -/datum/material/cardboard - name = "cardboard" - stack_type = /obj/item/stack/material/cardboard - flags = MATERIAL_BRITTLE - integrity = 10 - icon_base = "solid" - icon_reinf = "reinf_over" - icon_colour = "#AAAAAA" - hardness = 1 - weight = 1 - protectiveness = 0 // 0% - conductive = 0 - ignition_point = T0C+232 //"the temperature at which book-paper catches fire, and burns." close enough - melting_point = T0C+232 //temperature at which cardboard walls would be destroyed - stack_origin_tech = list(TECH_MATERIAL = 1) - door_icon_base = "wood" - destruction_desc = "crumples" - radiation_resistance = 1 - pass_stack_colors = TRUE - -/datum/material/snow - name = MAT_SNOW - stack_type = /obj/item/stack/material/snow - flags = MATERIAL_BRITTLE - icon_base = "solid" - icon_reinf = "reinf_over" - icon_colour = "#FFFFFF" - integrity = 1 - hardness = 1 - weight = 1 - protectiveness = 0 // 0% - stack_origin_tech = list(TECH_MATERIAL = 1) - melting_point = T0C+1 - destruction_desc = "crumples" - sheet_singular_name = "pile" - sheet_plural_name = "pile" //Just a bigger pile - radiation_resistance = 1 - -/datum/material/snowbrick //only slightly stronger than snow, used to make igloos mostly - name = "packed snow" - flags = MATERIAL_BRITTLE - stack_type = /obj/item/stack/material/snowbrick - icon_base = "stone" - icon_reinf = "reinf_stone" - icon_colour = "#D8FDFF" - integrity = 50 - weight = 2 - hardness = 2 - protectiveness = 0 // 0% - stack_origin_tech = list(TECH_MATERIAL = 1) - melting_point = T0C+1 - destruction_desc = "crumbles" - sheet_singular_name = "brick" - sheet_plural_name = "bricks" - radiation_resistance = 1 - -/datum/material/cloth //todo - name = "cloth" - stack_origin_tech = list(TECH_MATERIAL = 2) - door_icon_base = "wood" - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - flags = MATERIAL_PADDING - conductive = 0 - integrity = 40 - pass_stack_colors = TRUE - supply_conversion_value = 2 - -/datum/material/cloth/syncloth - name = "syncloth" - stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 2) - door_icon_base = "wood" - ignition_point = T0C+532 - melting_point = T0C+600 - integrity = 200 - protectiveness = 15 // 4% - flags = MATERIAL_PADDING - conductive = 0 - pass_stack_colors = TRUE - supply_conversion_value = 3 - -/datum/material/cult - name = "cult" - display_name = "disturbing stone" - icon_base = "cult" - icon_colour = "#402821" - icon_reinf = "reinf_cult" - shard_type = SHARD_STONE_PIECE - sheet_singular_name = "brick" - sheet_plural_name = "bricks" - conductive = 0 - -/datum/material/cult/place_dismantled_girder(var/turf/target) - new /obj/structure/girder/cult(target, "cult") - -/datum/material/cult/place_dismantled_product(var/turf/target) - new /obj/effect/decal/cleanable/blood(target) - -/datum/material/cult/reinf - name = "cult2" - display_name = "human remains" - -/datum/material/cult/reinf/place_dismantled_product(var/turf/target) - new /obj/effect/decal/remains/human(target) - -/datum/material/chitin - name = MAT_CHITIN - icon_colour = "#8d6653" - stack_type = /obj/item/stack/material/chitin - stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4) - icon_base = "solid" - icon_reinf = "reinf_mesh" - integrity = 60 - weight = 10 - ignition_point = T0C+400 - melting_point = T0C+500 - protectiveness = 20 - conductive = 0 - supply_conversion_value = 4 - -//TODO PLACEHOLDERS: -/datum/material/leather - name = MAT_LEATHER - display_name = "plainleather" - icon_colour = "#5C4831" - stack_type = /obj/item/stack/material/leather - stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) - flags = MATERIAL_PADDING - ignition_point = T0C+300 - melting_point = T0C+300 - protectiveness = 3 // 13% - conductive = 0 - integrity = 40 - supply_conversion_value = 3 - -/datum/material/carpet - name = "carpet" - display_name = "comfy" - use_name = "red upholstery" - icon_colour = "#DA020A" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - sheet_singular_name = "tile" - sheet_plural_name = "tiles" - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cotton - name = "cotton" - display_name ="cotton" - icon_colour = "#FFFFFF" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -// This all needs to be OOP'd and use inheritence if its ever used in the future. -/datum/material/cloth_teal - name = "teal" - display_name ="teal" - use_name = "teal cloth" - icon_colour = "#00EAFA" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_black - name = "black" - display_name = "black" - use_name = "black cloth" - icon_colour = "#505050" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_green - name = "green" - display_name = "green" - use_name = "green cloth" - icon_colour = "#01C608" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_puple - name = "purple" - display_name = "purple" - use_name = "purple cloth" - icon_colour = "#9C56C4" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_blue - name = "blue" - display_name = "blue" - use_name = "blue cloth" - icon_colour = "#6B6FE3" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_beige - name = "beige" - display_name = "beige" - use_name = "beige cloth" - icon_colour = "#E8E7C8" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_lime - name = "lime" - display_name = "lime" - use_name = "lime cloth" - icon_colour = "#62E36C" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_yellow - name = "yellow" - display_name = "yellow" - use_name = "yellow cloth" - icon_colour = "#EEF573" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/cloth_orange - name = "orange" - display_name = "orange" - use_name = "orange cloth" - icon_colour = "#E3BF49" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - protectiveness = 1 // 4% - conductive = 0 - -/datum/material/toy_foam - name = "foam" - display_name = "foam" - use_name = "foam" - flags = MATERIAL_PADDING - ignition_point = T0C+232 - melting_point = T0C+300 - icon_colour = "#ff9900" - hardness = 1 - weight = 1 - protectiveness = 0 // 0% - conductive = 0 - -/datum/material/void_opal - name = "void opal" - display_name = "void opal" - use_name = "void opal" - icon_colour = "#0f0f0f" - stack_type = /obj/item/stack/material/void_opal - flags = MATERIAL_UNMELTABLE - cut_delay = 60 - reflectivity = 0 - conductivity = 1 - shard_type = SHARD_SHARD - tableslam_noise = 'sound/effects/Glasshit.ogg' - hardness = 100 - stack_origin_tech = list(TECH_ARCANE = 1, TECH_MATERIAL = 6) - sheet_singular_name = "gem" - sheet_plural_name = "gems" - supply_conversion_value = 30 // These are hilariously rare. - -/datum/material/painite - name = "painite" - display_name = "painite" - use_name = "painite" - icon_colour = "#6b4947" - stack_type = /obj/item/stack/material/painite - flags = MATERIAL_UNMELTABLE - reflectivity = 0.3 - tableslam_noise = 'sound/effects/Glasshit.ogg' - sheet_singular_name = "gem" - sheet_plural_name = "gems" - supply_conversion_value = 4 - -/datum/material/tin - name = "tin" - display_name = "tin" - use_name = "tin" - stack_type = /obj/item/stack/material/tin - icon_colour = "#b2afaf" - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - supply_conversion_value = 1 - hardness = 50 - weight = 13 - -/datum/material/copper - name = "copper" - display_name = "copper" - use_name = "copper" - stack_type = /obj/item/stack/material/copper - conductivity = 52 - icon_colour = "#af633e" - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - supply_conversion_value = 1 - weight = 13 - hardness = 50 - -/datum/material/quartz - name = "quartz" - display_name = "quartz" - use_name = "quartz" - icon_colour = "#e6d7df" - stack_type = /obj/item/stack/material/quartz - tableslam_noise = 'sound/effects/Glasshit.ogg' - sheet_singular_name = "crystal" - sheet_plural_name = "crystals" - supply_conversion_value = 4 - -/datum/material/aluminium - name = "aluminium" - display_name = "aluminium" - use_name = "aluminium" - icon_colour = "#e5e2d0" - stack_type = /obj/item/stack/material/aluminium - sheet_singular_name = "ingot" - sheet_plural_name = "ingots" - supply_conversion_value = 2 - weight = 10 diff --git a/code/modules/materials/materials/_materials_vr.dm b/code/modules/materials/materials/_materials_vr.dm new file mode 100644 index 00000000000..8c91622fb35 --- /dev/null +++ b/code/modules/materials/materials/_materials_vr.dm @@ -0,0 +1,9 @@ +/obj/item/stack/material/attack(mob/living/M as mob, mob/living/user as mob) + if(M.handle_eat_minerals(src, user)) + return + ..() + +/obj/item/stack/material/attack_generic(var/mob/living/user) //Allow adminbussed mobs to eat ore if they click it while NOT on help intent. + if(user.handle_eat_minerals(src)) + return + ..() diff --git a/code/modules/materials/materials/glass_vr.dm b/code/modules/materials/materials/glass_vr.dm new file mode 100644 index 00000000000..9d7cd818796 --- /dev/null +++ b/code/modules/materials/materials/glass_vr.dm @@ -0,0 +1,33 @@ +/datum/material/glass/titaniumglass + name = MAT_TITANIUMGLASS + display_name = "titanium glass" + stack_type = /obj/item/stack/material/glass/titanium + integrity = 150 + hardness = 50 + weight = 50 + flags = MATERIAL_BRITTLE + icon_colour = "#A7A3A6" + stack_origin_tech = list(TECH_MATERIAL = 5) + window_options = list("One Direction" = 1, "Full Window" = 4) + created_window = /obj/structure/window/titanium + created_fulltile_window = /obj/structure/window/titanium/full + wire_product = null + rod_product = /obj/item/stack/material/glass/titanium + composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT) + +/datum/material/glass/plastaniumglass + name = MAT_PLASTITANIUMGLASS + display_name = "plas-titanium glass" + stack_type = /obj/item/stack/material/glass/plastitanium + integrity = 200 + hardness = 60 + weight = 80 + flags = MATERIAL_BRITTLE + icon_colour = "#676366" + stack_origin_tech = list(TECH_MATERIAL = 6) + window_options = list("One Direction" = 1, "Full Window" = 4) + created_window = /obj/structure/window/plastitanium + created_fulltile_window = /obj/structure/window/plastitanium/full + wire_product = null + rod_product = /obj/item/stack/material/glass/plastitanium + composite_material = list(MAT_PLASTITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT) diff --git a/code/modules/materials/materials/metals/hull_vr.dm b/code/modules/materials/materials/metals/hull_vr.dm new file mode 100644 index 00000000000..3c35b3cf398 --- /dev/null +++ b/code/modules/materials/materials/metals/hull_vr.dm @@ -0,0 +1,20 @@ +/datum/material/plastitanium/hull + name = MAT_PLASTITANIUMHULL + stack_type = /obj/item/stack/material/plastitanium/hull + icon_base = "hull" + icon_reinf = "reinf_mesh" + icon_colour = "#585658" + explosion_resistance = 50 + +/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. + new /obj/item/stack/material/plastitanium(target) + +/datum/material/gold/hull + name = MAT_GOLDHULL + stack_type = /obj/item/stack/material/gold/hull + icon_base = "hull" + icon_reinf = "reinf_mesh" + explosion_resistance = 50 + +/datum/material/gold/hull/place_sheet(var/turf/target) //Deconstructed into normal gold sheets. + new /obj/item/stack/material/gold(target) diff --git a/code/modules/materials/materials/metals/metals_vr.dm b/code/modules/materials/materials/metals/metals_vr.dm new file mode 100644 index 00000000000..f600b2fe025 --- /dev/null +++ b/code/modules/materials/materials/metals/metals_vr.dm @@ -0,0 +1,6 @@ +/datum/material/durasteel/generate_recipes() + . = ..() + recipes += list( + new /datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2), + new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30), + ) diff --git a/code/modules/materials/materials/metals/plasteel_vr.dm b/code/modules/materials/materials/metals/plasteel_vr.dm new file mode 100644 index 00000000000..bca3fdf27b8 --- /dev/null +++ b/code/modules/materials/materials/metals/plasteel_vr.dm @@ -0,0 +1,22 @@ +/datum/material/plastitanium + name = MAT_PLASTITANIUM + stack_type = /obj/item/stack/material/plastitanium + integrity = 600 + melting_point = 9000 + icon_base = "solid" + icon_reinf = "reinf_over" + icon_colour = "#585658" + explosion_resistance = 35 + hardness = 90 + weight = 40 + protectiveness = 30 + conductivity = 7 + stack_origin_tech = list(TECH_MATERIAL = 5) + composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT) + supply_conversion_value = 8 + +/datum/material/plastitanium/generate_recipes() + ..() + recipes += list( + new /datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20), + ) diff --git a/code/modules/materials/materials/metals/steel.dm b/code/modules/materials/materials/metals/steel.dm index 606c3e70377..ca323c81374 100644 --- a/code/modules/materials/materials/metals/steel.dm +++ b/code/modules/materials/materials/metals/steel.dm @@ -74,7 +74,8 @@ new /datum/stack_recipe("fire extinguisher cabinet frame", /obj/item/frame/extinguisher_cabinet, 4, time = 5, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), new /datum/stack_recipe("railing", /obj/structure/railing, 2, time = 50, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), new /datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), - new /datum/stack_recipe("IV drip", /obj/machinery/iv_drip, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), + //new /datum/stack_recipe("IV drip", /obj/machinery/iv_drip, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), //VOREStation Removal + new /datum/stack_recipe("medical stand", /obj/structure/medical_stand, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), //VOREStation Replacement, new /datum/stack_recipe("conveyor switch", /obj/machinery/conveyor_switch, 2, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]"), new /datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade, recycle_material = "[name]"), new /datum/stack_recipe("light fixture frame", /obj/item/frame/light, 2, recycle_material = "[name]"), diff --git a/code/modules/materials/materials/metals/steel_vr.dm b/code/modules/materials/materials/metals/steel_vr.dm new file mode 100644 index 00000000000..b112f362171 --- /dev/null +++ b/code/modules/materials/materials/metals/steel_vr.dm @@ -0,0 +1,82 @@ +/datum/material/steel/generate_recipes() + . = ..() + recipes += list( + new /datum/stack_recipe_list("mounted chairs",list( + new /datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("red mounted chair", /obj/structure/bed/chair/bay/chair/padded/red, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("brown mounted chair", /obj/structure/bed/chair/bay/chair/padded/brown, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("teal mounted chair", /obj/structure/bed/chair/bay/chair/padded/teal, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("black mounted chair", /obj/structure/bed/chair/bay/chair/padded/black, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("green mounted chair", /obj/structure/bed/chair/bay/chair/padded/green, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("purple mounted chair", /obj/structure/bed/chair/bay/chair/padded/purple, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("blue mounted chair", /obj/structure/bed/chair/bay/chair/padded/blue, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("beige mounted chair", /obj/structure/bed/chair/bay/chair/padded/beige, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("lime mounted chair", /obj/structure/bed/chair/bay/chair/padded/lime, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("yellow mounted chair", /obj/structure/bed/chair/bay/chair/padded/yellow, 2, one_per_turf = 1, on_floor = 1, time = 10) + )), + new /datum/stack_recipe_list("mounted comfy chairs",list( + new /datum/stack_recipe("mounted comfy chair", /obj/structure/bed/chair/bay/comfy, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("red mounted comfy chair", /obj/structure/bed/chair/bay/comfy/red, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("brown mounted comfy chair", /obj/structure/bed/chair/bay/comfy/brown, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("teal mounted comfy chair", /obj/structure/bed/chair/bay/comfy/teal, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("black mounted comfy chair", /obj/structure/bed/chair/bay/comfy/black, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("green mounted comfy chair", /obj/structure/bed/chair/bay/comfy/green, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("purple mounted comfy chair", /obj/structure/bed/chair/bay/comfy/purple, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("blue mounted comfy chair", /obj/structure/bed/chair/bay/comfy/blue, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("beige mounted comfy chair", /obj/structure/bed/chair/bay/comfy/beige, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("lime mounted comfy chair", /obj/structure/bed/chair/bay/comfy/lime, 3, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("yellow mounted comfy chair", /obj/structure/bed/chair/bay/comfy/yellow, 3, one_per_turf = 1, on_floor = 1, time = 20) + )), + new /datum/stack_recipe("mounted captain's chair", /obj/structure/bed/chair/bay/comfy/captain, 4, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("dropship seat", /obj/structure/bed/chair/bay/shuttle, 4, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("small teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/smallnest, 2, one_per_turf = 1, on_floor = 1, time = 10), + new /datum/stack_recipe("large teshari nest", /obj/structure/bed/chair/bay/chair/padded/red/bignest, 4, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("dance pole", /obj/structure/dancepole, 2, one_per_turf = 1, on_floor = 1, time = 20), + new /datum/stack_recipe("light switch frame", /obj/item/frame/lightswitch, 2), + new /datum/stack_recipe_list("sofas",list( + new /datum/stack_recipe("red sofa middle", /obj/structure/bed/chair/sofa, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("red sofa left", /obj/structure/bed/chair/sofa/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("red sofa right", /obj/structure/bed/chair/sofa/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("red sofa corner", /obj/structure/bed/chair/sofa/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("brown sofa middle", /obj/structure/bed/chair/sofa/brown, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("brown sofa left", /obj/structure/bed/chair/sofa/brown/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("brown sofa right", /obj/structure/bed/chair/sofa/brown/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("brown sofa corner", /obj/structure/bed/chair/sofa/brown/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("teal sofa middle", /obj/structure/bed/chair/sofa/teal, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("teal sofa left", /obj/structure/bed/chair/sofa/teal/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("teal sofa right", /obj/structure/bed/chair/sofa/teal/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("teal sofa corner", /obj/structure/bed/chair/sofa/teal/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("black sofa middle", /obj/structure/bed/chair/sofa/black, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("black sofa left", /obj/structure/bed/chair/sofa/black/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("black sofa right", /obj/structure/bed/chair/sofa/black/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("black sofa corner", /obj/structure/bed/chair/sofa/black/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("green sofa middle", /obj/structure/bed/chair/sofa/green, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("green sofa left", /obj/structure/bed/chair/sofa/green/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("green sofa right", /obj/structure/bed/chair/sofa/green/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("green sofa corner", /obj/structure/bed/chair/sofa/green/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("purple sofa middle", /obj/structure/bed/chair/sofa/purp, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("purple sofa left", /obj/structure/bed/chair/sofa/purp/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("purple sofa right", /obj/structure/bed/chair/sofa/purp/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("purple sofa corner", /obj/structure/bed/chair/sofa/purp/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("blue sofa middle", /obj/structure/bed/chair/sofa/blue, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("blue sofa left", /obj/structure/bed/chair/sofa/blue/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("blue sofa right", /obj/structure/bed/chair/sofa/blue/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("blue sofa corner", /obj/structure/bed/chair/sofa/blue/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("beige sofa middle", /obj/structure/bed/chair/sofa/beige, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("beige sofa left", /obj/structure/bed/chair/sofa/beige/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("beige sofa right", /obj/structure/bed/chair/sofa/beige/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("beige sofa corner", /obj/structure/bed/chair/sofa/beige/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("lime sofa middle", /obj/structure/bed/chair/sofa/lime, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("lime sofa left", /obj/structure/bed/chair/sofa/lime/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("lime sofa right", /obj/structure/bed/chair/sofa/lime/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("lime sofa corner", /obj/structure/bed/chair/sofa/lime/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("yellow sofa middle", /obj/structure/bed/chair/sofa/yellow, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("yellow sofa left", /obj/structure/bed/chair/sofa/yellow/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("yellow sofa right", /obj/structure/bed/chair/sofa/yellow/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("yellow sofa corner", /obj/structure/bed/chair/sofa/yellow/corner, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("orange sofa middle", /obj/structure/bed/chair/sofa/orange, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("orange sofa left", /obj/structure/bed/chair/sofa/orange/left, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("orange sofa right", /obj/structure/bed/chair/sofa/orange/right, 1, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \ + )), + ) diff --git a/code/modules/materials/materials/organic/wood.dm b/code/modules/materials/materials/organic/wood.dm index 2f44607e8b6..ecdad547ca5 100644 --- a/code/modules/materials/materials/organic/wood.dm +++ b/code/modules/materials/materials/organic/wood.dm @@ -41,6 +41,7 @@ new /datum/stack_recipe("wooden bucket", /obj/item/weapon/reagent_containers/glass/bucket/wood, 2, time = 4, one_per_turf = 0, on_floor = 0, pass_stack_color = TRUE, recycle_material = "[name]"), new /datum/stack_recipe("coilgun stock", /obj/item/weapon/coilgun_assembly, 5, pass_stack_color = TRUE, recycle_material = "[name]"), new /datum/stack_recipe("crude fishing rod", /obj/item/weapon/material/fishing_rod/built, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), + new /datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]"), //VOREStation Add new /datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1, recycle_material = "[name]"), new /datum/stack_recipe("tanning rack", /obj/structure/tanning_rack, 3, one_per_turf = TRUE, time = 20, on_floor = TRUE, supplied_material = "[name]") ) diff --git a/code/modules/materials/materials/other_vr.dm b/code/modules/materials/materials/other_vr.dm new file mode 100644 index 00000000000..d54dd4f726e --- /dev/null +++ b/code/modules/materials/materials/other_vr.dm @@ -0,0 +1,32 @@ +/datum/material/flesh + name = "flesh" + display_name = "chunk of flesh" + icon_colour = "#dd90aa" + sheet_singular_name = "meat" + sheet_plural_name = "meats" + integrity = 1200 + melting_point = 6000 + explosion_resistance = 200 + hardness = 500 + weight = 500 + +/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix. + name = " " + display_name = "" + icon_colour = "#000000" + sheet_singular_name = "fluff" + sheet_plural_name = "fluffs" + hardness = 60 + weight = 20 //Strong as iron. + +/datum/material/darkglass + name = "darkglass" + display_name = "darkglass" + icon_base = "darkglass" + icon_colour = "#FFFFFF" + +/datum/material/fancyblack + name = "fancyblack" + display_name = "fancyblack" + icon_base = "fancyblack" + icon_colour = "#FFFFFF" diff --git a/code/modules/materials/materials/stone.dm b/code/modules/materials/materials/stone.dm index b716fb4c616..823dd19914c 100644 --- a/code/modules/materials/materials/stone.dm +++ b/code/modules/materials/materials/stone.dm @@ -22,7 +22,7 @@ name = "marble" icon_colour = "#AAAAAA" weight = 26 - hardness = 70 + hardness = 30 //VOREStation Edit - Please. integrity = 201 //hack to stop kitchen benches being flippable, todo: refactor into weight system stack_type = /obj/item/stack/material/marble supply_conversion_value = 2 diff --git a/code/modules/materials/materials_vr.dm b/code/modules/materials/materials_vr.dm deleted file mode 100644 index e66f1ebfa85..00000000000 --- a/code/modules/materials/materials_vr.dm +++ /dev/null @@ -1,104 +0,0 @@ -/datum/material/flesh - name = "flesh" - display_name = "chunk of flesh" - icon_colour = "#dd90aa" - sheet_singular_name = "meat" - sheet_plural_name = "meats" - integrity = 1200 - melting_point = 6000 - explosion_resistance = 200 - hardness = 500 - weight = 500 - -/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix. - name = " " - display_name = "" - icon_colour = "#000000" - sheet_singular_name = "fluff" - sheet_plural_name = "fluffs" - hardness = 60 - weight = 20 //Strong as iron. - -/datum/material/darkglass - name = "darkglass" - display_name = "darkglass" - icon_base = "darkglass" - icon_colour = "#FFFFFF" - -/datum/material/fancyblack - name = "fancyblack" - display_name = "fancyblack" - icon_base = "fancyblack" - icon_colour = "#FFFFFF" - -/datum/material/glass/titaniumglass - name = MAT_TITANIUMGLASS - display_name = "titanium glass" - stack_type = /obj/item/stack/material/glass/titanium - integrity = 150 - hardness = 50 - weight = 50 - flags = MATERIAL_BRITTLE - icon_colour = "#A7A3A6" - stack_origin_tech = list(TECH_MATERIAL = 5) - window_options = list("One Direction" = 1, "Full Window" = 4) - created_window = /obj/structure/window/titanium - created_fulltile_window = /obj/structure/window/titanium/full - wire_product = null - rod_product = /obj/item/stack/material/glass/titanium - composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT) - -/datum/material/plastitanium - name = MAT_PLASTITANIUM - stack_type = /obj/item/stack/material/plastitanium - integrity = 600 - melting_point = 9000 - icon_base = "solid" - icon_reinf = "reinf_over" - icon_colour = "#585658" - explosion_resistance = 35 - hardness = 90 - weight = 40 - protectiveness = 30 - conductivity = 7 - stack_origin_tech = list(TECH_MATERIAL = 5) - composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT) - supply_conversion_value = 8 - -/datum/material/plastitanium/hull - name = MAT_PLASTITANIUMHULL - stack_type = /obj/item/stack/material/plastitanium/hull - icon_base = "hull" - icon_reinf = "reinf_mesh" - icon_colour = "#585658" - explosion_resistance = 50 - -/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. - new /obj/item/stack/material/plastitanium(target) - -/datum/material/glass/plastaniumglass - name = MAT_PLASTITANIUMGLASS - display_name = "plas-titanium glass" - stack_type = /obj/item/stack/material/glass/plastitanium - integrity = 200 - hardness = 60 - weight = 80 - flags = MATERIAL_BRITTLE - icon_colour = "#676366" - stack_origin_tech = list(TECH_MATERIAL = 6) - window_options = list("One Direction" = 1, "Full Window" = 4) - created_window = /obj/structure/window/plastitanium - created_fulltile_window = /obj/structure/window/plastitanium/full - wire_product = null - rod_product = /obj/item/stack/material/glass/plastitanium - composite_material = list(MAT_PLASTITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT) - -/datum/material/gold/hull - name = MAT_GOLDHULL - stack_type = /obj/item/stack/material/gold/hull - icon_base = "hull" - icon_reinf = "reinf_mesh" - explosion_resistance = 50 - -/datum/material/gold/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets. - new /obj/item/stack/material/gold(target) \ No newline at end of file diff --git a/code/modules/materials/sheets/glass_vr.dm b/code/modules/materials/sheets/glass_vr.dm new file mode 100644 index 00000000000..23aad9c0cc2 --- /dev/null +++ b/code/modules/materials/sheets/glass_vr.dm @@ -0,0 +1,17 @@ +/obj/item/stack/material/glass/titanium + name = "ti-glass sheets" + icon = 'icons/obj/stacks_vr.dmi' + icon_state = "sheet-titaniumglass" + item_state = "sheet-silver" + no_variants = FALSE + drop_sound = 'sound/items/drop/glass.ogg' + default_type = MAT_TITANIUMGLASS + +/obj/item/stack/material/glass/plastitanium + name = "plastitanium glass sheets" + icon = 'icons/obj/stacks_vr.dmi' + icon_state = "sheet-plastitaniumglass" + item_state = "sheet-silver" + no_variants = FALSE + drop_sound = 'sound/items/drop/glass.ogg' + default_type = MAT_PLASTITANIUMGLASS diff --git a/code/modules/materials/sheets/metals/hull_vr.dm b/code/modules/materials/sheets/metals/hull_vr.dm new file mode 100644 index 00000000000..29e267ab818 --- /dev/null +++ b/code/modules/materials/sheets/metals/hull_vr.dm @@ -0,0 +1,15 @@ +/obj/item/stack/material/plastitanium/hull + name = "plastitanium hull sheets" + icon = 'icons/obj/stacks_vr.dmi' + icon_state = "sheet-plastitanium" + item_state = "sheet-silver" + no_variants = FALSE + default_type = MAT_PLASTITANIUMHULL + +/obj/item/stack/material/gold/hull + name = "gold hull sheets" + icon = 'icons/obj/stacks_vr.dmi' + icon_state = "sheet-plastitanium" + item_state = "sheet-silver" + no_variants = FALSE + default_type = MAT_GOLDHULL diff --git a/code/modules/materials/sheets/metals/metal_vr.dm b/code/modules/materials/sheets/metals/metal_vr.dm new file mode 100644 index 00000000000..1a867ea9578 --- /dev/null +++ b/code/modules/materials/sheets/metals/metal_vr.dm @@ -0,0 +1,12 @@ +/obj/item/stack/material/titanium + icon = 'icons/obj/stacks_vr.dmi' + icon_state = "sheet-titanium" + no_variants = FALSE + +/obj/item/stack/material/plastitanium + name = "plastitanium sheets" + icon = 'icons/obj/stacks_vr.dmi' + icon_state = "sheet-plastitanium" + item_state = "sheet-silver" + no_variants = FALSE + default_type = MAT_PLASTITANIUM diff --git a/vorestation.dme b/vorestation.dme index 3c3e174c25e..6983228d6ec 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -853,13 +853,8 @@ #include "code\game\machinery\teleporter.dm" #include "code\game\machinery\transportpod.dm" #include "code\game\machinery\turret_control.dm" -<<<<<<< HEAD:vorestation.dme -#include "code\game\machinery\vending.dm" -#include "code\game\machinery\vending_machines.dm" #include "code\game\machinery\vending_machines_vr.dm" #include "code\game\machinery\vitals_monitor.dm" -======= ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\game\machinery\wall_frames.dm" #include "code\game\machinery\washing_machine.dm" #include "code\game\machinery\wishgranter.dm" @@ -1201,21 +1196,13 @@ #include "code\game\objects\items\robot\robot_items.dm" #include "code\game\objects\items\robot\robot_parts.dm" #include "code\game\objects\items\robot\robot_upgrades.dm" -<<<<<<< HEAD:vorestation.dme #include "code\game\objects\items\robot\robot_upgrades_vr.dm" -#include "code\game\objects\items\stacks\fifty_spawner.dm" -======= ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\game\objects\items\stacks\marker_beacons.dm" #include "code\game\objects\items\stacks\matter_synth.dm" #include "code\game\objects\items\stacks\medical.dm" #include "code\game\objects\items\stacks\medical_vr.dm" #include "code\game\objects\items\stacks\nanopaste.dm" -<<<<<<< HEAD:vorestation.dme #include "code\game\objects\items\stacks\nanopaste_vr.dm" -#include "code\game\objects\items\stacks\rods.dm" -======= ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\game\objects\items\stacks\sandbags.dm" #include "code\game\objects\items\stacks\stack.dm" #include "code\game\objects\items\stacks\telecrystal.dm" @@ -2080,31 +2067,10 @@ #include "code\modules\economy\price_list.dm" #include "code\modules\economy\retail_scanner.dm" #include "code\modules\economy\TradeDestinations.dm" -<<<<<<< HEAD:vorestation.dme -#include "code\modules\entopics_vr\alternate_appearance.dm" -#include "code\modules\entopics_vr\entopics.dm" -======= #include "code\modules\economy\vending.dm" #include "code\modules\economy\vending_machines.dm" -#include "code\modules\emotes\emote_define.dm" -#include "code\modules\emotes\emote_mob.dm" -#include "code\modules\emotes\definitions\_mob.dm" -#include "code\modules\emotes\definitions\_species.dm" -#include "code\modules\emotes\definitions\audible.dm" -#include "code\modules\emotes\definitions\audible_cough.dm" -#include "code\modules\emotes\definitions\audible_scream.dm" -#include "code\modules\emotes\definitions\audible_slap.dm" -#include "code\modules\emotes\definitions\audible_snap.dm" -#include "code\modules\emotes\definitions\audible_sneeze.dm" -#include "code\modules\emotes\definitions\audible_whistle.dm" -#include "code\modules\emotes\definitions\exertion.dm" -#include "code\modules\emotes\definitions\human.dm" -#include "code\modules\emotes\definitions\slimes.dm" -#include "code\modules\emotes\definitions\synthetics.dm" -#include "code\modules\emotes\definitions\visible.dm" -#include "code\modules\emotes\definitions\visible_animated.dm" -#include "code\modules\emotes\definitions\visible_vomit.dm" ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme +#include "code\modules\entopics_vr\alternate_appearance.dm" +#include "code\modules\entopics_vr\entopics.dm" #include "code\modules\error_handler\_defines.dm" #include "code\modules\error_handler\error_handler.dm" #include "code\modules\error_handler\error_viewer.dm" @@ -2445,36 +2411,29 @@ #include "code\modules\maps\tg\reader.dm" #include "code\modules\materials\fifty_spawner.dm" #include "code\modules\materials\fifty_spawner_mats.dm" -<<<<<<< HEAD:vorestation.dme -#include "code\modules\materials\material_recipes.dm" -#include "code\modules\materials\material_recipes_vr.dm" -#include "code\modules\materials\material_sheets.dm" -#include "code\modules\materials\material_sheets_vr.dm" -#include "code\modules\materials\material_synth.dm" -#include "code\modules\materials\materials.dm" -#include "code\modules\materials\materials_vr.dm" -#include "code\modules\media\media_machinery.dm" -#include "code\modules\media\media_player_html5.dm" -#include "code\modules\media\media_player_vlc.dm" -#include "code\modules\media\media_player_wmp.dm" -#include "code\modules\media\media_tracks.dm" -#include "code\modules\media\mediamanager.dm" -======= +#include "code\modules\materials\fifty_spawner_mats_vr.dm" #include "code\modules\materials\material_synth.dm" #include "code\modules\materials\materials\_materials.dm" +#include "code\modules\materials\materials\_materials_vr.dm" #include "code\modules\materials\materials\alien_alloy.dm" #include "code\modules\materials\materials\cult.dm" #include "code\modules\materials\materials\gems.dm" #include "code\modules\materials\materials\glass.dm" +#include "code\modules\materials\materials\glass_vr.dm" #include "code\modules\materials\materials\holographic.dm" +#include "code\modules\materials\materials\other_vr.dm" #include "code\modules\materials\materials\plastic.dm" #include "code\modules\materials\materials\snow.dm" #include "code\modules\materials\materials\stone.dm" #include "code\modules\materials\materials\supermatter.dm" #include "code\modules\materials\materials\metals\hull.dm" +#include "code\modules\materials\materials\metals\hull_vr.dm" #include "code\modules\materials\materials\metals\metals.dm" +#include "code\modules\materials\materials\metals\metals_vr.dm" #include "code\modules\materials\materials\metals\plasteel.dm" +#include "code\modules\materials\materials\metals\plasteel_vr.dm" #include "code\modules\materials\materials\metals\steel.dm" +#include "code\modules\materials\materials\metals\steel_vr.dm" #include "code\modules\materials\materials\organic\animal_products.dm" #include "code\modules\materials\materials\organic\cloth.dm" #include "code\modules\materials\materials\organic\leather.dm" @@ -2483,12 +2442,15 @@ #include "code\modules\materials\sheets\_sheets.dm" #include "code\modules\materials\sheets\gems.dm" #include "code\modules\materials\sheets\glass.dm" +#include "code\modules\materials\sheets\glass_vr.dm" #include "code\modules\materials\sheets\plastic.dm" #include "code\modules\materials\sheets\snow.dm" #include "code\modules\materials\sheets\stone.dm" #include "code\modules\materials\sheets\supermatter.dm" #include "code\modules\materials\sheets\metals\hull.dm" +#include "code\modules\materials\sheets\metals\hull_vr.dm" #include "code\modules\materials\sheets\metals\metal.dm" +#include "code\modules\materials\sheets\metals\metal_vr.dm" #include "code\modules\materials\sheets\metals\rods.dm" #include "code\modules\materials\sheets\organic\animal_products.dm" #include "code\modules\materials\sheets\organic\resin.dm" @@ -2498,7 +2460,12 @@ #include "code\modules\materials\sheets\organic\tanning\hide_hairless.dm" #include "code\modules\materials\sheets\organic\tanning\leather_wet.dm" #include "code\modules\materials\sheets\organic\tanning\tanning_rack.dm" ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme +#include "code\modules\media\media_machinery.dm" +#include "code\modules\media\media_player_html5.dm" +#include "code\modules\media\media_player_vlc.dm" +#include "code\modules\media\media_player_wmp.dm" +#include "code\modules\media\media_tracks.dm" +#include "code\modules\media\mediamanager.dm" #include "code\modules\metric\activity.dm" #include "code\modules\metric\count.dm" #include "code\modules\metric\department.dm" @@ -2506,11 +2473,7 @@ #include "code\modules\mining\abandonedcrates.dm" #include "code\modules\mining\abandonedcrates_vr.dm" #include "code\modules\mining\alloys.dm" -<<<<<<< HEAD:vorestation.dme #include "code\modules\mining\alloys_vr.dm" -#include "code\modules\mining\coins.dm" -======= ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:polaris.dme #include "code\modules\mining\fulton.dm" #include "code\modules\mining\mine_items.dm" #include "code\modules\mining\mine_items_vr.dm" From 5a7fa5e104a48e9a0b7dd8ae4313bddf931cbbee Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 28 Apr 2021 12:28:13 -0400 Subject: [PATCH 11/15] Compatibility Part 2 --- code/modules/economy/vending.dm | 723 -------------------------------- 1 file changed, 723 deletions(-) diff --git a/code/modules/economy/vending.dm b/code/modules/economy/vending.dm index f48afa07797..9c2106adc01 100644 --- a/code/modules/economy/vending.dm +++ b/code/modules/economy/vending.dm @@ -1,725 +1,3 @@ -<<<<<<< HEAD:code/game/machinery/vending.dm -/// -/// A vending machine -/// - -// -// ALL THE VENDING MACHINES ARE IN vending_machines.dm now! -// - -/obj/machinery/vending - name = "Vendomat" - desc = "A generic vending machine." - icon = 'icons/obj/vending.dmi' - icon_state = "generic" - anchored = 1 - density = 1 - clicksound = "button" - - // Power - use_power = USE_POWER_IDLE - idle_power_usage = 10 - var/vend_power_usage = 150 //actuators and stuff - - // Vending-related - var/active = 1 //No sales pitches if off! - var/vend_ready = 1 //Are we ready to vend?? Is it time?? - var/vend_delay = 10 //How long does it take to vend? - var/categories = CAT_NORMAL // Bitmask of cats we're currently showing - var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now - var/vending_sound = "machines/vending/vending_drop.ogg" - - /* - Variables used to initialize the product list - These are used for initialization only, and so are optional if - product_records is specified - */ - var/list/products = list() // For each, use the following pattern: - var/list/contraband = list() // list(/type/path = amount,/type/path2 = amount2) - var/list/premium = list() // No specified amount = only one in stock - var/list/prices = list() // Prices for each item, list(/type/path = price), items not in the list don't have a price. - - // List of vending_product items available. - var/list/product_records = list() - - - // Variables used to initialize advertising - var/product_slogans = "" //String of slogans spoken out loud, separated by semicolons - var/product_ads = "" //String of small ad messages in the vending screen - - var/list/ads_list = list() - - // Stuff relating vocalizations - var/list/slogan_list = list() - var/shut_up = 1 //Stop spouting those godawful pitches! - var/vend_reply //Thank you for shopping! - var/last_reply = 0 - var/last_slogan = 0 //When did we last pitch? - var/slogan_delay = 6000 //How long until we can pitch again? - - // Things that can go wrong - emagged = 0 //Ignores if somebody doesn't have card access to that machine. - var/seconds_electrified = 0 //Shock customers like an airlock. - var/shoot_inventory = 0 //Fire items at customers! We're broken! - - var/scan_id = 1 - var/obj/item/weapon/coin/coin - var/datum/wires/vending/wires = null - - var/list/log = list() - var/req_log_access = access_cargo //default access for checking logs is cargo - var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs - var/can_rotate = 1 //Defaults to yes, can be set to 0 for vendors without or with unwanted directionals. - - -/obj/machinery/vending/Initialize() - . = ..() - wires = new(src) - if(product_slogans) - slogan_list += splittext(product_slogans, ";") - - // So not all machines speak at the exact same time. - // The first time this machine says something will be at slogantime + this random value, - // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. - last_slogan = world.time + rand(0, slogan_delay) - - if(product_ads) - ads_list += splittext(product_ads, ";") - - build_inventory() - power_change() - -GLOBAL_LIST_EMPTY(vending_products) -/** - * Build produdct_records from the products lists - * - * products, contraband, premium, and prices allow specifying - * products that the vending machine is to carry without manually populating - * product_records. - */ -/obj/machinery/vending/proc/build_inventory() - var/list/all_products = list( - list(products, CAT_NORMAL), - list(contraband, CAT_HIDDEN), - list(premium, CAT_COIN)) - - for(var/current_list in all_products) - var/category = current_list[2] - - for(var/entry in current_list[1]) - var/datum/stored_item/vending_product/product = new/datum/stored_item/vending_product(src, entry) - - product.price = (entry in prices) ? prices[entry] : 0 - product.amount = (current_list[1][entry]) ? current_list[1][entry] : 1 - product.category = category - - product_records.Add(product) - GLOB.vending_products[entry] = 1 - -/obj/machinery/vending/Destroy() - qdel(wires) - wires = null - qdel(coin) - coin = null - for(var/datum/stored_item/vending_product/R in product_records) - qdel(R) - product_records = null - return ..() - -/obj/machinery/vending/ex_act(severity) - switch(severity) - if(1.0) - qdel(src) - return - if(2.0) - if(prob(50)) - qdel(src) - return - if(3.0) - if(prob(25)) - spawn(0) - malfunction() - return - return - else - return - -/obj/machinery/vending/emag_act(var/remaining_charges, var/mob/user) - if(!emagged) - emagged = 1 - to_chat(user, "You short out \the [src]'s product lock.") - return 1 - -/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob) - var/obj/item/weapon/card/id/I = W.GetID() - - if(I || istype(W, /obj/item/weapon/spacecash)) - attack_hand(user) - return - else if(W.is_screwdriver()) - panel_open = !panel_open - to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") - playsound(src, W.usesound, 50, 1) - if(panel_open) - wires.Interact(user) - add_overlay("[initial(icon_state)]-panel") - else - cut_overlay("[initial(icon_state)]-panel") - - SStgui.update_uis(src) // Speaker switch is on the main UI, not wires UI - return - else if(istype(W, /obj/item/device/multitool) || W.is_wirecutter()) - if(panel_open) - attack_hand(user) - return - else if(istype(W, /obj/item/weapon/coin) && premium.len > 0) - user.drop_item() - W.forceMove(src) - coin = W - categories |= CAT_COIN - to_chat(user, "You insert \the [W] into \the [src].") - SStgui.update_uis(src) - return - else if(W.is_wrench()) - playsound(src, W.usesound, 100, 1) - if(anchored) - user.visible_message("[user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.") - else - user.visible_message("[user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.") - - if(do_after(user, 20 * W.toolspeed)) - if(!src) return - to_chat(user, "You [anchored? "un" : ""]secured \the [src]!") - anchored = !anchored - return - else - - for(var/datum/stored_item/vending_product/R in product_records) - if(istype(W, R.item_path) && (W.name == R.item_name)) - stock(W, R, user) - return - ..() - -/** - * Receive payment with cashmoney. - * - * usr is the mob who gets the change. - */ -/obj/machinery/vending/proc/pay_with_cash(var/obj/item/weapon/spacecash/cashmoney, mob/user) - if(currently_vending.price > cashmoney.worth) - - // This is not a status display message, since it's something the character - // themselves is meant to see BEFORE putting the money in - to_chat(usr, "[bicon(cashmoney)] That is not enough money.") - return 0 - - if(istype(cashmoney, /obj/item/weapon/spacecash)) - - visible_message("\The [usr] inserts some cash into \the [src].") - cashmoney.worth -= currently_vending.price - - if(cashmoney.worth <= 0) - usr.drop_from_inventory(cashmoney) - qdel(cashmoney) - else - cashmoney.update_icon() - - // Vending machines have no idea who paid with cash - credit_purchase("(cash)") - return 1 - -/** - * Scan a chargecard and deduct payment from it. - * - * Takes payment for whatever is the currently_vending item. Returns 1 if - * successful, 0 if failed. - */ -/obj/machinery/vending/proc/pay_with_ewallet(var/obj/item/weapon/spacecash/ewallet/wallet) - visible_message("\The [usr] swipes \the [wallet] through \the [src].") - playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) - if(currently_vending.price > wallet.worth) - to_chat(usr, "Insufficient funds on chargecard.") - return 0 - else - wallet.worth -= currently_vending.price - credit_purchase("[wallet.owner_name] (chargecard)") - return 1 - -/** - * Scan a card and attempt to transfer payment from associated account. - * - * Takes payment for whatever is the currently_vending item. Returns 1 if - * successful, 0 if failed - */ -/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M) - visible_message("[M] swipes a card through [src].") - playsound(src, 'sound/machines/id_swipe.ogg', 50, 1) - - var/datum/money_account/customer_account = get_account(I.associated_account_number) - if(!customer_account) - to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.") - return FALSE - - if(customer_account.suspended) - to_chat(M, "Unable to access account: account suspended.") - return FALSE - - // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is - // empty at high security levels - if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) - var/attempt_pin = input("Enter pin code", "Vendor transaction") as num - customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) - - if(!customer_account) - to_chat(M, "Unable to access account: incorrect credentials.") - return FALSE - - if(currently_vending.price > customer_account.money) - to_chat(M, "Insufficient funds in account.") - return FALSE - - // Okay to move the money at this point - - // debit money from the purchaser's account - customer_account.money -= currently_vending.price - - // create entry in the purchaser's account log - var/datum/transaction/T = new() - T.target_name = "[vendor_account.owner_name] (via [name])" - T.purpose = "Purchase of [currently_vending.item_name]" - if(currently_vending.price > 0) - T.amount = "([currently_vending.price])" - else - T.amount = "[currently_vending.price]" - T.source_terminal = name - T.date = current_date_string - T.time = stationtime2text() - customer_account.transaction_log.Add(T) - - // Give the vendor the money. We use the account owner name, which means - // that purchases made with stolen/borrowed card will look like the card - // owner made them - credit_purchase(customer_account.owner_name) - return 1 - -/** - * Add money for current purchase to the vendor account. - * - * Called after the money has already been taken from the customer. - */ -/obj/machinery/vending/proc/credit_purchase(var/target as text) - vendor_account.money += currently_vending.price - - var/datum/transaction/T = new() - T.target_name = target - T.purpose = "Purchase of [currently_vending.item_name]" - T.amount = "[currently_vending.price]" - T.source_terminal = name - T.date = current_date_string - T.time = stationtime2text() - vendor_account.transaction_log.Add(T) - -/obj/machinery/vending/attack_ghost(mob/user) - return attack_hand(user) - -/obj/machinery/vending/attack_ai(mob/user as mob) - return attack_hand(user) - -/obj/machinery/vending/attack_hand(mob/user as mob) - if(stat & (BROKEN|NOPOWER)) - return - - if(seconds_electrified != 0) - if(shock(user, 100)) - return - - wires.Interact(user) - tgui_interact(user) - -/obj/machinery/vending/ui_assets(mob/user) - return list( - get_asset_datum(/datum/asset/spritesheet/vending), - ) - -/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "Vending", name) - ui.open() - -/obj/machinery/vending/tgui_data(mob/user) - var/list/data = list() - var/list/listed_products = list() - - data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE - for(var/key = 1 to product_records.len) - var/datum/stored_item/vending_product/I = product_records[key] - - if(!(I.category & categories)) - continue - - listed_products.Add(list(list( - "key" = key, - "name" = I.item_name, - "price" = I.price, - "color" = I.display_color, - "isatom" = ispath(I.item_path, /atom), - "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"), - "amount" = I.get_amount() - ))) - - data["products"] = listed_products - - if(coin) - data["coin"] = coin.name - else - data["coin"] = FALSE - - if(currently_vending) - data["actively_vending"] = currently_vending.item_name - else - data["actively_vending"] = null - - if(panel_open) - data["panel"] = 1 - data["speaker"] = shut_up ? 0 : 1 - else - data["panel"] = 0 - - var/mob/living/carbon/human/H - var/obj/item/weapon/card/id/C - - data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash."; - data["userMoney"] = 0 - data["user"] = null - if(ishuman(user)) - H = user - C = H.GetIdCard() - var/obj/item/weapon/spacecash/S = H.get_active_hand() - if(istype(S)) - data["userMoney"] = S.worth - data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]₮." - else if(istype(C)) - var/datum/money_account/A = get_account(C.associated_account_number) - if(istype(A)) - data["user"] = list() - data["user"]["name"] = A.owner_name - data["userMoney"] = A.money - data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job" - else - data["guestNotice"] = "Unlinked ID detected. Present cash to pay."; - - return data - -/obj/machinery/vending/tgui_act(action, params) - if(stat & (BROKEN|NOPOWER)) - return - if(usr.stat || usr.restrained()) - return - if(..()) - return TRUE - - . = TRUE - switch(action) - if("remove_coin") - if(issilicon(usr)) - return FALSE - - if(!coin) - to_chat(usr, "There is no coin in this machine.") - return - - coin.forceMove(src.loc) - if(!usr.get_active_hand()) - usr.put_in_hands(coin) - - to_chat(usr, "You remove \the [coin] from \the [src].") - coin = null - categories &= ~CAT_COIN - return TRUE - if("vend") - if(!vend_ready) - to_chat(usr, "[src] is busy!") - return - if(!allowed(usr) && !emagged && scan_id) - to_chat(usr, "Access denied.") //Unless emagged of course - flick("[icon_state]-deny",src) - playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) - return - if(panel_open) - to_chat(usr, "[src] cannot dispense products while its service panel is open!") - return - - var/key = text2num(params["vend"]) - var/datum/stored_item/vending_product/R = product_records[key] - - // This should not happen unless the request from NanoUI was bad - if(!(R.category & categories)) - return - - if(!can_buy(R, usr)) - return - if(R.price <= 0) - vend(R, usr) - add_fingerprint(usr) - return TRUE - - if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something. - to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.") - return - if(!ishuman(usr)) - return - - - vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved. - - var/mob/living/carbon/human/H = usr - var/obj/item/weapon/card/id/C = H.GetIdCard() - - if(!vendor_account || vendor_account.suspended) - to_chat(usr, "Vendor account offline. Unable to process transaction.") - flick("[icon_state]-deny",src) - vend_ready = TRUE - return - - currently_vending = R - - var/paid = FALSE - - if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash)) - var/obj/item/weapon/spacecash/cash = usr.get_active_hand() - paid = pay_with_cash(cash, usr) - else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet)) - var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand() - paid = pay_with_ewallet(wallet) - else if(istype(C, /obj/item/weapon/card)) - paid = pay_with_card(C, usr) - /*else if(usr.can_advanced_admin_interact()) - to_chat(usr, "Vending object due to admin interaction.") - paid = TRUE*/ - else - to_chat(usr, "Payment failure: you have no ID or other method of payment.") - vend_ready = TRUE - flick("[icon_state]-deny",src) - return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update. - if(paid) - vend(currently_vending, usr) // vend will handle vend_ready - . = TRUE - else - to_chat(usr, "Payment failure: unable to process payment.") - vend_ready = TRUE - - if("togglevoice") - if(!panel_open) - return FALSE - shut_up = !shut_up - -/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user) - if(!allowed(user) && !emagged && scan_id) - to_chat(user, "Access denied.") //Unless emagged of course - flick("[icon_state]-deny",src) - playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0) - return FALSE - return TRUE - -/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user) - if(!can_buy(R, user)) - return - - if(!R.amount) - to_chat(user, "[src] has ran out of that product.") - vend_ready = TRUE - return - - vend_ready = FALSE //One thing at a time!! - SStgui.update_uis(src) - - if(R.category & CAT_COIN) - if(!coin) - to_chat(user, "You need to insert a coin to get this item.") - return - if(coin.string_attached) - if(prob(50)) - to_chat(user, "You successfully pull the coin out before \the [src] could swallow it.") - else - to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.") - qdel(coin) - coin = null - categories &= ~CAT_COIN - else - qdel(coin) - coin = null - categories &= ~CAT_COIN - - if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply) - spawn(0) - speak(vend_reply) - last_reply = world.time - - use_power(vend_power_usage) //actuators and stuff - flick("[icon_state]-vend",src) - addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay) - -/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user) - R.get_product(get_turf(src)) - if(has_logs) - do_logging(R, user, 1) - if(prob(1)) - sleep(3) - if(R.get_product(get_turf(src))) - visible_message("\The [src] clunks as it vends an additional item.") - playsound(src, "sound/[vending_sound]", 100, 1, 1) - - vend_ready = 1 - currently_vending = null - SStgui.update_uis(src) - GLOB.items_sold_shift_roundstat++ - -/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0) - if(user.GetIdCard()) - var/obj/item/weapon/card/id/tempid = user.GetIdCard() - var/list/list_item = list() - if(vending) - list_item += "vend" - else - list_item += "stock" - list_item += tempid.registered_name - list_item += stationtime2text() - list_item += R.item_name - log[++log.len] = list_item - -/obj/machinery/vending/proc/show_log(mob/user as mob) - if(user.GetIdCard()) - var/obj/item/weapon/card/id/tempid = user.GetIdCard() - if(req_log_access in tempid.GetAccess()) - var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500) - var/dat = "" - dat += "
[name] Vending Log
" - dat += "
Welcome [user.name]!

" - dat += "Below are the recent vending logs for your vending machine.
" - for(var/i in log) - dat += json_encode(i) - dat += ";
" - popup.set_content(dat) - popup.open() - else - to_chat(user,"You do not have the required access to view the vending logs for this machine.") - - -/obj/machinery/vending/verb/rotate_clockwise() - set name = "Rotate Vending Machine Clockwise" - set category = "Object" - set src in oview(1) - - if (src.can_rotate == 0) - to_chat(usr, "\The [src] cannot be rotated.") - return 0 - - if (src.anchored || usr:stat) - to_chat(usr, "It is bolted down!") - return 0 - src.set_dir(turn(src.dir, 270)) - return 1 - -/obj/machinery/vending/verb/check_logs() - set name = "Check Vending Logs" - set category = "Object" - set src in oview(1) - - show_log(usr) - -/** - * Add item to the machine - * - * Checks if item is vendable in this machine should be performed before - * calling. W is the item being inserted, R is the associated vending_product entry. - */ -/obj/machinery/vending/proc/stock(obj/item/weapon/W, var/datum/stored_item/vending_product/R, var/mob/user) - if(!user.unEquip(W)) - return - - to_chat(user, "You insert \the [W] in the product receptor.") - R.add_product(W) - if(has_logs) - do_logging(R, user) - - SStgui.update_uis(src) - -/obj/machinery/vending/process() - if(stat & (BROKEN|NOPOWER)) - return - - if(!active) - return - - if(seconds_electrified > 0) - seconds_electrified-- - - //Pitch to the people! Really sell it! - if(((last_slogan + slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5)) - var/slogan = pick(slogan_list) - speak(slogan) - last_slogan = world.time - - if(shoot_inventory && prob(2)) - throw_item() - - return - -/obj/machinery/vending/proc/speak(var/message) - if(stat & NOPOWER) - return - - if(!message) - return - - for(var/mob/O in hearers(src, null)) - O.show_message("\The [src] beeps, \"[message]\"",2) - return - -/obj/machinery/vending/power_change() - ..() - if(stat & BROKEN) - icon_state = "[initial(icon_state)]-broken" - else - if(!(stat & NOPOWER)) - icon_state = initial(icon_state) - else - spawn(rand(0, 15)) - icon_state = "[initial(icon_state)]-off" - -//Oh no we're malfunctioning! Dump out some product and break. -/obj/machinery/vending/proc/malfunction() - for(var/datum/stored_item/vending_product/R in product_records) - while(R.get_amount()>0) - R.get_product(loc) - break - - stat |= BROKEN - icon_state = "[initial(icon_state)]-broken" - return - -//Somebody cut an important wire and now we're following a new definition of "pitch." -/obj/machinery/vending/proc/throw_item() - var/obj/throw_item = null - var/mob/living/target = locate() in view(7,src) - if(!target) - return 0 - - for(var/datum/stored_item/vending_product/R in product_records) - throw_item = R.get_product(loc) - if(!throw_item) - continue - break - if(!throw_item) - return 0 - spawn(0) - throw_item.throw_at(target, 16, 3, src) - visible_message("\The [src] launches \a [throw_item] at \the [target]!") - return 1 - -//Actual machines are in vending_machines.dm -======= /// /// A vending machine /// @@ -1442,4 +720,3 @@ GLOBAL_LIST_EMPTY(vending_products) return 1 //Actual machines are in vending_machines.dm ->>>>>>> 33c51d9... Merge pull request #8022 from Atermonera/materials_refactor:code/modules/economy/vending.dm From 7137e0aa8497109c57953171ec8d0aff4a34985b Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 28 Apr 2021 12:36:31 -0400 Subject: [PATCH 12/15] Compile fix --- code/modules/client/preference_setup/loadout/loadout.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm index 6d16e08aa5d..e5822353990 100644 --- a/code/modules/client/preference_setup/loadout/loadout.dm +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -62,6 +62,7 @@ var/list/gear_datums = list() /datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost) . = list() + var/mob/preference_mob = preference_mob() //VOREStation Add for(var/gear_name in gear_datums) var/datum/gear/G = gear_datums[gear_name] From c1c418fefde3558e2bcf3dd31cf41cece7fbc054 Mon Sep 17 00:00:00 2001 From: TheFurryFeline <38586851+TheFurryFeline@users.noreply.github.com> Date: Wed, 28 Apr 2021 16:56:32 -0400 Subject: [PATCH 13/15] Brig Flashes :cl: maptweak - Adds mounted flashers to both brigs and in the visiting rooms brig-side. /:cl: Resolve #10014 Note, am fine if this ain't wanted. Another note, on testing, there's a substantial cooldown on the button so ya can't spam it too much. --- maps/tether/tether-01-surface1.dmm | 308 ++++++++++++++++++----------- maps/tether/tether-06-station2.dmm | 283 ++++++++++++++------------ 2 files changed, 350 insertions(+), 241 deletions(-) diff --git a/maps/tether/tether-01-surface1.dmm b/maps/tether/tether-01-surface1.dmm index 3d0af89fe7b..a92a06dc5aa 100644 --- a/maps/tether/tether-01-surface1.dmm +++ b/maps/tether/tether-01-surface1.dmm @@ -24363,6 +24363,13 @@ }, /turf/simulated/floor/wood, /area/crew_quarters/sleep/Dorm_6) +"aOO" = ( +/obj/machinery/flasher{ + id = "SurfaceBrigFlash"; + pixel_y = -20 + }, +/turf/simulated/floor/tiled/dark, +/area/tether/surfacebase/security/brig) "aOP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -24669,6 +24676,30 @@ /obj/item/weapon/towel/random, /turf/simulated/floor/wood, /area/crew_quarters/sleep/Dorm_6) +"aPj" = ( +/obj/structure/cable/green{ + d1 = 1; + d2 = 2; + icon_state = "1-2" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 4; + icon_state = "2-4" + }, +/obj/effect/floor_decal/corner/lightorange{ + dir = 5 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 6 + }, +/obj/machinery/flasher{ + id = "SurfaceBrigFlash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled, +/area/tether/surfacebase/security/brig) "aPk" = ( /obj/machinery/shower{ dir = 1 @@ -25527,6 +25558,21 @@ }, /turf/simulated/floor/wood, /area/crew_quarters/sleep/Dorm_4) +"aQO" = ( +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/machinery/flasher{ + id = "SurfaceBrigFlash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled, +/area/tether/surfacebase/security/brig) "aQP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -25834,6 +25880,20 @@ /obj/item/weapon/towel/random, /turf/simulated/floor/wood, /area/crew_quarters/sleep/Dorm_4) +"aRs" = ( +/obj/structure/cable/green{ + d1 = 1; + d2 = 2; + icon_state = "1-2" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/machinery/atmospherics/pipe/simple/hidden/supply, +/obj/machinery/flasher{ + id = "SurfaceBrigFlash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled, +/area/tether/surfacebase/security/brig) "aRt" = ( /obj/machinery/shower{ dir = 1 @@ -26553,6 +26613,13 @@ }, /turf/simulated/floor/wood, /area/crew_quarters/sleep/Dorm_2) +"aSZ" = ( +/obj/machinery/flasher{ + id = "SurfaceBrigFlash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled, +/area/tether/surfacebase/security/brig) "aTa" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 4 @@ -26891,6 +26958,19 @@ /obj/item/weapon/towel/random, /turf/simulated/floor/wood, /area/crew_quarters/sleep/Dorm_2) +"aTH" = ( +/obj/effect/floor_decal/steeldecal/steel_decals4{ + dir = 1 + }, +/obj/effect/floor_decal/steeldecal/steel_decals4{ + dir = 6 + }, +/obj/machinery/button/flasher{ + id = "SurfaceVisitFlash"; + pixel_y = -20 + }, +/turf/simulated/floor/tiled/dark, +/area/tether/surfacebase/security/brig) "aTI" = ( /obj/machinery/shower{ dir = 1 @@ -28389,6 +28469,17 @@ }, /turf/simulated/floor/tiled, /area/crew_quarters/visitor_laundry) +"aWp" = ( +/obj/effect/floor_decal/steeldecal/steel_decals4, +/obj/effect/floor_decal/steeldecal/steel_decals4{ + dir = 10 + }, +/obj/machinery/flasher{ + id = "SurfaceVisitFlash"; + pixel_y = -20 + }, +/turf/simulated/floor/tiled/dark, +/area/tether/surfacebase/security/brig) "aWq" = ( /obj/machinery/atmospherics/pipe/simple/visible/yellow{ dir = 4 @@ -28837,6 +28928,92 @@ /obj/random/junk, /turf/simulated/floor/wood, /area/crew_quarters/sleep/maintDorm2) +"aXo" = ( +/obj/machinery/button/remote/airlock{ + id = "brigouter"; + name = "Outer Brig Doors"; + pixel_x = 24; + pixel_y = -4; + req_access = list(2) + }, +/obj/machinery/button/remote/airlock{ + id = "briginner"; + name = "Inner Brig Doors"; + pixel_x = 34; + pixel_y = -4; + req_access = list(2) + }, +/obj/effect/floor_decal/borderfloor{ + dir = 4 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 6 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 5 + }, +/obj/effect/floor_decal/corner/lightorange/bordercorner2{ + dir = 5 + }, +/obj/effect/floor_decal/corner/lightorange/bordercorner2{ + dir = 6 + }, +/obj/machinery/button/flasher{ + id = "SurfaceBrigFlash"; + pixel_x = 30; + pixel_y = 5 + }, +/turf/simulated/floor/tiled, +/area/tether/surfacebase/security/lowerhall) +"aXp" = ( +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 4 + }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 8 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 + }, +/obj/effect/floor_decal/steeldecal/steel_decals6{ + dir = 9 + }, +/obj/machinery/flasher{ + id = "SurfaceBrigFlash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled, +/area/tether/surfacebase/security/brig) +"aXq" = ( +/obj/structure/cable/green{ + icon_state = "1-8" + }, +/obj/structure/cable/green{ + d1 = 2; + d2 = 8; + icon_state = "2-8" + }, +/obj/effect/floor_decal/corner/lightorange{ + dir = 6 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/manifold/hidden/supply, +/obj/machinery/flasher{ + id = "SurfaceBrigFlash" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/turf/simulated/floor/tiled, +/area/tether/surfacebase/security/brig) "aXr" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -31619,15 +31796,6 @@ "cGJ" = ( /turf/simulated/floor/plating, /area/maintenance/lower/mining_eva) -"cGU" = ( -/obj/effect/floor_decal/steeldecal/steel_decals4{ - dir = 1 - }, -/obj/effect/floor_decal/steeldecal/steel_decals4{ - dir = 6 - }, -/turf/simulated/floor/tiled/dark, -/area/tether/surfacebase/security/brig) "cHW" = ( /obj/effect/floor_decal/steeldecal/steel_decals6{ dir = 10 @@ -33005,13 +33173,6 @@ }, /turf/simulated/floor/tiled, /area/crew_quarters/locker/laundry_arrival) -"hzx" = ( -/obj/effect/floor_decal/steeldecal/steel_decals4, -/obj/effect/floor_decal/steeldecal/steel_decals4{ - dir = 10 - }, -/turf/simulated/floor/tiled/dark, -/area/tether/surfacebase/security/brig) "hAe" = ( /turf/simulated/floor/looking_glass{ dir = 5 @@ -35005,29 +35166,6 @@ /obj/structure/closet/crate/bin, /turf/simulated/floor/carpet/bcarpet, /area/tether/surfacebase/funny/mimeoffice) -"nmf" = ( -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/machinery/atmospherics/pipe/simple/hidden/green{ - dir = 4 - }, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 8 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/effect/floor_decal/steeldecal/steel_decals6{ - dir = 9 - }, -/turf/simulated/floor/tiled, -/area/tether/surfacebase/security/brig) "nmA" = ( /obj/machinery/door/airlock/silver{ name = "Mime's Office"; @@ -36233,26 +36371,6 @@ }, /turf/simulated/floor/plating, /area/tether/surfacebase/funny/hideyhole) -"rzZ" = ( -/obj/structure/cable/green{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, -/obj/structure/cable/green{ - d1 = 2; - d2 = 4; - icon_state = "2-4" - }, -/obj/effect/floor_decal/corner/lightorange{ - dir = 5 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 6 - }, -/turf/simulated/floor/tiled, -/area/tether/surfacebase/security/brig) "rBG" = ( /obj/structure/closet, /obj/item/weapon/material/minihoe, @@ -37089,38 +37207,6 @@ }, /turf/simulated/floor/tiled, /area/rnd/hallway) -"uDQ" = ( -/obj/machinery/button/remote/airlock{ - id = "brigouter"; - name = "Outer Brig Doors"; - pixel_x = 24; - pixel_y = -4; - req_access = list(2) - }, -/obj/machinery/button/remote/airlock{ - id = "briginner"; - name = "Inner Brig Doors"; - pixel_x = 34; - pixel_y = -4; - req_access = list(2) - }, -/obj/effect/floor_decal/borderfloor{ - dir = 4 - }, -/obj/effect/floor_decal/borderfloor/corner2{ - dir = 6 - }, -/obj/effect/floor_decal/borderfloor/corner2{ - dir = 5 - }, -/obj/effect/floor_decal/corner/lightorange/bordercorner2{ - dir = 5 - }, -/obj/effect/floor_decal/corner/lightorange/bordercorner2{ - dir = 6 - }, -/turf/simulated/floor/tiled, -/area/tether/surfacebase/security/lowerhall) "uEK" = ( /obj/effect/floor_decal/borderfloor, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ @@ -37609,24 +37695,6 @@ }, /turf/simulated/floor/tiled, /area/tether/surfacebase/surface_one_hall) -"wxV" = ( -/obj/structure/cable/green{ - icon_state = "1-8" - }, -/obj/structure/cable/green{ - d1 = 2; - d2 = 8; - icon_state = "2-8" - }, -/obj/effect/floor_decal/corner/lightorange{ - dir = 6 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/manifold/hidden/supply, -/turf/simulated/floor/tiled, -/area/tether/surfacebase/security/brig) "wzA" = ( /obj/structure/catwalk, /obj/machinery/alarm{ @@ -45915,7 +45983,7 @@ vRL hFq neZ diq -uDQ +aXo mvM fLB dMu @@ -46198,9 +46266,9 @@ tiJ kmb pCj kUN -cGU +aTH qwV -nmf +aXp hMu abT bbd @@ -46476,13 +46544,13 @@ wwm jio pCj dju -kmb +aOO pCj dju -kmb +aOO pCj jzW -hzx +aWp qwV wtD wQS @@ -46902,15 +46970,15 @@ aad mYf rQe ybc -rzZ -hTw +aPj hTw hTw hTw +aRs hTw uFs ddU -wxV +aXq nID iKy anp @@ -47470,11 +47538,11 @@ aad pCj wjq wjq -pKE +aQO pmV loj plW -tdh +aSZ fqa fOy eAd diff --git a/maps/tether/tether-06-station2.dmm b/maps/tether/tether-06-station2.dmm index 73f88da06cf..09d88b445ba 100644 --- a/maps/tether/tether-06-station2.dmm +++ b/maps/tether/tether-06-station2.dmm @@ -144,30 +144,18 @@ /turf/simulated/floor/tiled, /area/security/brig/visitation) "ap" = ( -/obj/effect/floor_decal/borderfloor/shifted{ - dir = 4 +/obj/effect/floor_decal/corner/white/border{ + dir = 8 }, -/obj/effect/floor_decal/corner/red/border/shifted{ - dir = 4 +/obj/item/weapon/paper/crumpled{ + name = "basketball" }, -/obj/effect/floor_decal/corner/red{ - dir = 6 +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/flasher{ + id = "AsteroidSecFlash" }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1 - }, -/obj/machinery/button/remote/airlock{ - id = "visitdoor"; - name = "Visitation Access"; - pixel_y = -24 - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/turf/simulated/floor/tiled, -/area/security/brig/visitation) +/turf/simulated/floor/tiled/monotile, +/area/security/brig) "aq" = ( /obj/machinery/light{ dir = 4 @@ -388,13 +376,11 @@ /turf/simulated/floor/tiled/dark, /area/security/brig) "aO" = ( -/obj/effect/floor_decal/corner/white/border{ - dir = 8 +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/flasher{ + id = "AsteroidSecFlash" }, -/obj/item/weapon/paper/crumpled{ - name = "basketball" - }, -/turf/simulated/floor/tiled/monotile, +/turf/simulated/floor/tiled, /area/security/brig) "aP" = ( /turf/simulated/mineral/floor/vacuum, @@ -1833,16 +1819,35 @@ /turf/simulated/floor/tiled/steel_dirty, /area/security/brig) "cO" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 5 +/obj/effect/floor_decal/borderfloor/shifted{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/border/shifted{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red{ + dir = 6 + }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/button/remote/airlock{ + id = "visitdoor"; + name = "Visitation Access"; + pixel_y = -24 }, /obj/structure/cable/green{ d1 = 4; d2 = 8; icon_state = "4-8" }, -/turf/simulated/floor/tiled/dark, -/area/security/brig) +/obj/machinery/button/flasher{ + id = "AsteroidVisitingFlash"; + pixel_x = -10; + pixel_y = -20 + }, +/turf/simulated/floor/tiled, +/area/security/brig/visitation) "cP" = ( /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /obj/structure/cable/green{ @@ -1948,12 +1953,24 @@ /turf/simulated/floor/tiled/dark, /area/security/recstorage) "cW" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/green, -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ +/obj/effect/floor_decal/borderfloor/shifted{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red/border/shifted{ + dir = 8 + }, +/obj/effect/floor_decal/corner/red{ dir = 9 }, +/obj/machinery/atmospherics/unary/vent_pump/on{ + dir = 1 + }, +/obj/machinery/flasher{ + id = "AsteroidVisitingFlash"; + pixel_y = -20 + }, /turf/simulated/floor/tiled, -/area/security/brig) +/area/security/brig/visitation) "cX" = ( /obj/machinery/door/firedoor/glass, /obj/structure/cable/green{ @@ -2260,20 +2277,20 @@ /turf/simulated/floor/tiled, /area/security/security_cell_hallway) "dt" = ( -/obj/effect/floor_decal/borderfloor/shifted{ - dir = 8 +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 5 }, -/obj/effect/floor_decal/corner/red/border/shifted{ - dir = 8 +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" }, -/obj/effect/floor_decal/corner/red{ - dir = 9 +/obj/machinery/flasher{ + id = "AsteroidSecFlash"; + pixel_y = -20 }, -/obj/machinery/atmospherics/unary/vent_pump/on{ - dir = 1 - }, -/turf/simulated/floor/tiled, -/area/security/brig/visitation) +/turf/simulated/floor/tiled/dark, +/area/security/brig) "du" = ( /obj/effect/floor_decal/borderfloorblack{ dir = 8 @@ -2513,12 +2530,14 @@ /turf/simulated/floor/tiled/steel_dirty, /area/security/brig) "dQ" = ( -/obj/effect/floor_decal/industrial/warning, /obj/machinery/atmospherics/pipe/simple/hidden/green, -/obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/flasher{ + id = "AsteroidSecFlash" + }, /turf/simulated/floor/tiled, /area/security/brig) "dR" = ( @@ -7775,20 +7794,38 @@ /turf/simulated/floor/tiled, /area/hallway/station/starboard) "lU" = ( -/obj/structure/shuttle/engine/propulsion{ - dir = 8; - icon_state = "propulsion_l" +/obj/effect/floor_decal/industrial/warning, +/obj/machinery/atmospherics/pipe/simple/hidden/green, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 9 }, -/turf/space, -/turf/simulated/shuttle/plating/airless/carry, -/area/shuttle/large_escape_pod1) +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/flasher{ + id = "AsteroidSecFlash" + }, +/turf/simulated/floor/tiled, +/area/security/brig) "lV" = ( -/obj/structure/shuttle/engine/propulsion{ - dir = 8 +/obj/effect/floor_decal/borderfloor{ + dir = 1 }, -/turf/space, -/turf/simulated/shuttle/plating/airless/carry, -/area/shuttle/large_escape_pod1) +/obj/effect/floor_decal/corner/red/border{ + dir = 1 + }, +/obj/effect/floor_decal/borderfloor/corner2{ + dir = 4 + }, +/obj/effect/floor_decal/corner/red/bordercorner2{ + dir = 4 + }, +/obj/machinery/button/flasher{ + id = "AsteroidSecFlash"; + pixel_x = 20; + pixel_y = 20 + }, +/turf/simulated/floor/tiled, +/area/security/security_cell_hallway) "lW" = ( /obj/structure/cable/green{ d1 = 4; @@ -9557,13 +9594,30 @@ /turf/simulated/floor/tiled, /area/hallway/station/starboard) "oB" = ( -/obj/structure/shuttle/engine/propulsion{ - dir = 8; - icon_state = "propulsion_r" +/obj/machinery/atmospherics/pipe/simple/hidden/supply{ + dir = 4 }, -/turf/space, -/turf/simulated/shuttle/plating/airless/carry, -/area/shuttle/large_escape_pod1) +/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/simple/hidden/green{ + dir = 5 + }, +/obj/structure/cable/green{ + d1 = 4; + d2 = 8; + icon_state = "4-8" + }, +/obj/structure/disposalpipe/segment{ + dir = 1; + icon_state = "pipe-c" + }, +/obj/effect/floor_decal/industrial/outline/yellow, +/obj/machinery/flasher{ + id = "AsteroidSecFlash" + }, +/turf/simulated/floor/tiled, +/area/security/brig) "oC" = ( /obj/effect/floor_decal/borderfloor{ dir = 1 @@ -9586,10 +9640,13 @@ /turf/simulated/floor/tiled, /area/hallway/station/starboard) "oD" = ( -/obj/structure/stairs/spawner/west, -/turf/simulated/sky/virgo3b/west, -/turf/simulated/floor/tiled/white, -/area/medical/biostorage) +/obj/structure/shuttle/engine/propulsion{ + dir = 8; + icon_state = "propulsion_l" + }, +/turf/space, +/turf/simulated/shuttle/plating/airless/carry, +/area/shuttle/large_escape_pod1) "oE" = ( /obj/structure/toilet{ pixel_y = 6 @@ -9614,6 +9671,26 @@ }, /turf/simulated/floor/tiled/white, /area/medical/recoveryrestroom) +"oG" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 8 + }, +/turf/space, +/turf/simulated/shuttle/plating/airless/carry, +/area/shuttle/large_escape_pod1) +"oH" = ( +/obj/structure/shuttle/engine/propulsion{ + dir = 8; + icon_state = "propulsion_r" + }, +/turf/space, +/turf/simulated/shuttle/plating/airless/carry, +/area/shuttle/large_escape_pod1) +"oI" = ( +/obj/structure/stairs/spawner/west, +/turf/simulated/sky/virgo3b/west, +/turf/simulated/floor/tiled/white, +/area/medical/biostorage) "oM" = ( /turf/simulated/open, /area/engineering/foyer_mezzenine) @@ -18720,27 +18797,6 @@ /obj/item/weapon/book/manual/medical_diagnostics_manual, /turf/simulated/floor/tiled/white, /area/maintenance/station/sec_lower) -"Nc" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/simple/hidden/green{ - dir = 5 - }, -/obj/structure/cable/green{ - d1 = 4; - d2 = 8; - icon_state = "4-8" - }, -/obj/structure/disposalpipe/segment{ - dir = 1; - icon_state = "pipe-c" - }, -/turf/simulated/floor/tiled, -/area/security/brig) "Nf" = ( /obj/effect/floor_decal/borderfloor{ dir = 8 @@ -18756,21 +18812,6 @@ }, /turf/simulated/floor/tiled, /area/engineering/locker_room) -"Ng" = ( -/obj/effect/floor_decal/borderfloor{ - dir = 1 - }, -/obj/effect/floor_decal/corner/red/border{ - dir = 1 - }, -/obj/effect/floor_decal/borderfloor/corner2{ - dir = 4 - }, -/obj/effect/floor_decal/corner/red/bordercorner2{ - dir = 4 - }, -/turf/simulated/floor/tiled, -/area/security/security_cell_hallway) "Nm" = ( /obj/structure/bed/chair{ dir = 8 @@ -27169,7 +27210,7 @@ bh af ao dk -ap +cO dj dL Tk @@ -27453,7 +27494,7 @@ Fq af cG do -dt +cW af XR UT @@ -28157,22 +28198,22 @@ UO Hc aS EE -aO +ap ak bm -DF +aO ar bb bt -cW +dQ bv bB es -dQ +lU Ye cn YK -Nc +oB hQ YN jf @@ -28487,7 +28528,7 @@ vE wm ws xj -oD +oI vT aP aP @@ -28597,7 +28638,7 @@ cd ce bK Zu -Ng +lV JD TY aE @@ -28873,13 +28914,13 @@ XT GM aS aY -cO +dt aS aY -cO +dt aS aY -cO +dt aS PJ Ph @@ -35426,11 +35467,11 @@ hl DI RX DL -lU -lV -lV -lV -oB +oD +oG +oG +oG +oH oY sW ef From ca5d20f9cfff6173caa711b0f2522d48ba1ee1de Mon Sep 17 00:00:00 2001 From: Novacat <35587478+Novacat@users.noreply.github.com> Date: Wed, 28 Apr 2021 22:55:26 -0400 Subject: [PATCH 14/15] Fixes Stunrevolver PATH (#8053) It seems like the description assumed the stunrevolver was a subtype of /gun/ when it is not! --- code/modules/examine/descriptions/weapons.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/examine/descriptions/weapons.dm b/code/modules/examine/descriptions/weapons.dm index 8acb089a4c6..747fa0f75f6 100644 --- a/code/modules/examine/descriptions/weapons.dm +++ b/code/modules/examine/descriptions/weapons.dm @@ -30,7 +30,7 @@ description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger." -/obj/item/weapon/gun/energy/gun/stunrevolver +/obj/item/weapon/gun/energy/stunrevolver description_info = "This is an energy weapon. To fire the weapon, ensure your intent is *not* set to 'help', have your gun mode set to 'fire', \ then click where you want to fire. Most energy weapons can fire through windows harmlessly. To recharge this weapon, use a weapon recharger."