diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index c48f98fc33..eff908c898 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -67,9 +67,8 @@
//Tanning!
for(var/obj/item/stack/hairlesshide/HH in washing)
- var/obj/item/stack/WL = new HH.wet_type(src)
- if(istype(WL))
- WL.amount = HH.amount
+ var/obj/item/stack/wetleather/WL = new(src)
+ WL.amount = HH.amount
washing -= HH
HH.forceMove(get_turf(src))
HH.use(HH.amount)
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index 3076d2dfb8..c48f57e693 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -1,14 +1,18 @@
/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
-
- var/process_type = /obj/item/stack/hairlesshide
+// 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"
@@ -18,7 +22,6 @@
no_variants = FALSE
drop_sound = 'sound/items/drop/leather.ogg'
pickup_sound = 'sound/items/pickup/leather.ogg'
- amount = 1
stacktype = "hide-human"
/obj/item/stack/animalhide/corgi
@@ -26,7 +29,6 @@
desc = "The by-product of corgi farming."
singular_name = "corgi hide piece"
icon_state = "sheet-corgi"
- amount = 1
stacktype = "hide-corgi"
/obj/item/stack/animalhide/cat
@@ -34,7 +36,6 @@
desc = "The by-product of cat farming."
singular_name = "cat hide piece"
icon_state = "sheet-cat"
- amount = 1
stacktype = "hide-cat"
/obj/item/stack/animalhide/monkey
@@ -42,7 +43,6 @@
desc = "The by-product of monkey farming."
singular_name = "monkey hide piece"
icon_state = "sheet-monkey"
- amount = 1
stacktype = "hide-monkey"
/obj/item/stack/animalhide/lizard
@@ -50,7 +50,6 @@
desc = "Sssssss..."
singular_name = "lizard skin piece"
icon_state = "sheet-lizard"
- amount = 1
stacktype = "hide-lizard"
/obj/item/stack/animalhide/xeno
@@ -58,7 +57,6 @@
desc = "The skin of a terrible creature."
singular_name = "alien hide piece"
icon_state = "sheet-xeno"
- amount = 1
stacktype = "hide-xeno"
//don't see anywhere else to put these, maybe together they could be used to make the xenos suit?
@@ -68,7 +66,6 @@
singular_name = "alien chitin piece"
icon = 'icons/mob/alien.dmi'
icon_state = "chitin"
- amount = 1
stacktype = "hide-chitin"
/obj/item/xenos_claw
@@ -88,19 +85,28 @@
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")
- if(do_after(user,50))
- to_chat(user, "You cut the hair from this [src.singular_name]")
+ 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
- for(var/obj/item/stack/hairlesshide/HS in user.loc)
- if(HS.amount < 50 && istype(HS, process_type))
- HS.amount++
- src.use(1)
- return
- //If it gets to here it means it did not find a suitable stack on the tile.
- var/obj/item/stack/HS = new process_type(usr.loc)
- if(istype(HS))
- HS.amount = 1
+ 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
..()
@@ -110,31 +116,43 @@
/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
- amount = 1
+ max_amount = 20
stacktype = "hairlesshide"
- var/cleaning = FALSE // Can we be water_acted, or are we busy? To prevent accidental hide duplication and the collapse of causality.
- var/wet_type = /obj/item/stack/wetleather
+/obj/item/stack/hairlesshide/examine(var/mob/user)
+ . = ..()
+ . += description_info
/obj/item/stack/hairlesshide/water_act(var/wateramount)
- ..()
- cleaning = TRUE
- while(amount > 0 && wateramount > 0)
- use(1)
- wateramount--
- new wet_type(get_turf(src))
- cleaning = FALSE
+ . = ..()
+ 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))
- return
+ // 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 wet_type(get_turf(src))
+ var/obj/item/stack/wetleather/I = new /obj/item/stack/wetleather(get_turf(src))
if(istype(I))
I.dry()
@@ -146,16 +164,34 @@
/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
- amount = 1
+ 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)
@@ -164,17 +200,87 @@
dry()
/obj/item/stack/wetleather/proc/dry()
- //Try locating an exisitng stack on the tile and add to there if possible
- for(var/obj/item/stack/material/leather/HS in src.loc)
- if(HS.amount < 50)
- HS.amount++
- wetness = initial(wetness)
- src.use(1)
- return
- //If it gets to here it means it did not find a suitable stack on the tile.
- var/obj/item/stack/HS = new dry_type(src.loc)
+ var/obj/item/stack/material/leather/L = new(src.loc)
+ L.amount = amount
+ use(amount)
+ return L
- if(istype(HS))
- HS.amount = 1
- wetness = initial(wetness)
- src.use(1)
+/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/food/kitchen/smartfridge.dm b/code/modules/food/kitchen/smartfridge.dm
index d776e45296..a6def6bd2b 100644
--- a/code/modules/food/kitchen/smartfridge.dm
+++ b/code/modules/food/kitchen/smartfridge.dm
@@ -187,10 +187,10 @@
for(var/obj/item/stack/wetleather/WL in I.instances)
if(!WL.wetness)
- if(WL.amount == 1)
+ if(WL.amount)
WL.forceMove(get_turf(src))
+ WL.dry()
I.instances -= WL
- WL.dry()
break
WL.wetness = max(0, WL.wetness - rand(1, 3))
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index bc6b382ae2..8b71551656 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -106,6 +106,7 @@
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()
..()
@@ -144,7 +145,6 @@
recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]")
recipes += new/datum/stack_recipe("Feeder", /obj/machinery/feeder, 4, time = 20, one_per_turf = 1, on_floor = 1, recycle_material = "[name]") //CHOMP Addition
-
/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)
@@ -166,6 +166,7 @@
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()
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index 797ffc4371..b987f608b5 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -314,7 +314,8 @@
if(spill)
splash(target.loc, spill, multiplier, copy, min_spill, max_spill)
- trans_to(target, amount, multiplier, copy)
+ if(!trans_to(target, amount, multiplier, copy))
+ touch(target, amount)
/datum/reagents/proc/trans_type_to(var/target, var/rtype, var/amount = 1)
if (!target)
diff --git a/icons/obj/kitchen.dmi b/icons/obj/kitchen.dmi
index 6c5a251283..f558d3fd49 100644
Binary files a/icons/obj/kitchen.dmi and b/icons/obj/kitchen.dmi differ