/obj/structure/chemkit name = "makeshift workstation" icon = 'icons/obj/makeshift_workstation.dmi' icon_state = "workstation" desc = "It's a makeshift workstation for grinding, chopping, and heating." density = 1 anchored = 1 throwpass = 1 var/obj/item/device/analyzer/analyzer var/transfer_out = 0 var/phase_filter var/list/forbidden = list(/obj/item/reagent_containers/inhaler, /obj/item/reagent_containers/hypospray, /obj/item/reagent_containers/glass, /obj/item/extinguisher) // duplicate from blender code, since it's not really worth a define. also, it has fewer things. var/list/sheet_reagents = list( //have a number of reagents which is a factor of REAGENTS_PER_SHEET (default 20) unless you like decimals /obj/item/stack/material/iron = list(/datum/reagent/iron), /obj/item/stack/material/uranium = list(/datum/reagent/uranium), /obj/item/stack/material/phoron = list(/datum/reagent/toxin/phoron), /obj/item/stack/material/gold = list(/datum/reagent/gold), /obj/item/stack/material/silver = list(/datum/reagent/silver), /obj/item/stack/material/steel = list(/datum/reagent/iron, /datum/reagent/carbon), /obj/item/stack/material/sandstone = list(/datum/reagent/silicon, /datum/reagent/acetone), /obj/item/stack/material/glass = list(/datum/reagent/silicate), ) // removed borosilicate glass, platinum, and plasteel, too tough. just steal a grinder if you need it /obj/structure/chemkit/Initialize() . = ..() create_reagents(180) /obj/structure/chemkit/examine(mob/user) . = ..() if(analyzer) to_chat(user, SPAN_NOTICE("The analyzer displays that the temperature is [round(reagents.get_temperature() - T0C,0.1)]C.")) /obj/structure/chemkit/verb/phase_filter() set name = "Set Phase Filter" set category = "Object" set src in view(1) if(use_check_and_message(usr)) return 0 phase_filter = input("Which phase do you want to filter?", "Phase Filter", null) as null|anything in list("solid", "liquid", "gas", "none") if(phase_filter) to_chat(usr, SPAN_NOTICE("You switch to a [phase_filter] filter.")) if(phase_filter == "none") phase_filter = FALSE /obj/structure/chemkit/verb/eject_contents() set name = "Remove Contents" set category = "Object" set src in view(1) if (use_check_and_message(usr)) return for(var/atom/movable/A in contents) if(A == analyzer) continue A.forceMove(loc) /obj/structure/chemkit/attack_hand(mob/user) transfer_out = !transfer_out to_chat(user, SPAN_NOTICE("You are now [transfer_out ? "removing from" : "adding to"] \the [src].")) /obj/structure/chemkit/proc/heat_item(obj/item/W, mob/user) var/joules = 0 if(istype(W, /obj/item/flame)) joules = 1000 // 1 kJ per match, and we're assuming lighters give as much per use else if(W.iswelder()) joules = 10000 // we'll just have it be ten times stronger else if(istype(W, /obj/item/device/assembly/igniter)) joules = 5000 // half as strong as a welder; this thing has to set off bombs and such else joules = 500 // we're assuming it's some kind of novelty toy like lunea's gloves, etc; not exactly a match but it still works reagents.add_thermal_energy(joules) user.visible_message(SPAN_WARNING("[user] holds \the [W] up to \the [src]!"), SPAN_NOTICE("You use \the [W] to heat \the [src]'s contents."), SPAN_NOTICE("You hear something sizzle.")) user.setClickCooldown(joules/5000) // two seconds for welder, 1/5 second for matches but they run out /obj/structure/chemkit/proc/trans_item(obj/item/I, mob/user) if(transfer_out) var/amt = 0 switch(phase_filter) if("solid") amt = reagents.trans_ids_to(I.reagents, reagents.get_ids_by_phase(SOLID), reagents.get_free_space()) if("liquid") amt = reagents.trans_ids_to(I.reagents, reagents.get_ids_by_phase(LIQUID), reagents.get_free_space()) if("gas") amt = reagents.trans_ids_to(I.reagents, reagents.get_ids_by_phase(GAS), reagents.get_free_space()) else amt = reagents.trans_to_holder(I.reagents, reagents.get_free_space()) if(amt) to_chat(user, SPAN_NOTICE("You fill \the [I] with [amt] units from \the [src].")) else if(I.reagents && I.reagents.total_volume) var/amt = I.reagents.trans_to_holder(reagents, I.reagents.total_volume) // just pour it if you can to_chat(user, SPAN_NOTICE("You pour [amt] units from \the [I] into \the [src].")) /obj/structure/chemkit/proc/smash_sheet(obj/item/stack/stack, mob/user) if(!istype(stack)) return var/list/sheet_components = sheet_reagents[stack.type] var/amount_to_take = max(0,min(stack.amount,round(reagents.get_free_space()/REAGENTS_PER_SHEET))) if(!amount_to_take) return stack.use(amount_to_take) if(islist(sheet_components)) amount_to_take = (amount_to_take/(sheet_components.len)) for(var/n in sheet_components) reagents.add_reagent(n, (amount_to_take*REAGENTS_PER_SHEET)*rand(6,8)/10) else reagents.add_reagent(sheet_components, (amount_to_take*REAGENTS_PER_SHEET)*rand(6,8)/10) // 60% to 80% efficiency when crushing sheets to_chat(user, SPAN_NOTICE("You [pick("crush","smash","grind")] [stack] into a fine powder.")) return /obj/structure/chemkit/proc/smash(obj/item/I, mob/user) if(sheet_reagents[I.type]) smash_sheet(I, user) return to_chat(user, SPAN_NOTICE("You [pick("crush","smash","grind")] [I] into a fine [pick("paste","powder","pulp")].")) I.reagents.trans_to_holder(reagents, I.reagents.total_volume, rand(7, 10)/10) // 70% to 100% from smashing, since it's pretty thorough qdel(I) /obj/structure/chemkit/proc/chop(obj/item/I, mob/user) to_chat(user, SPAN_NOTICE("You [pick("chop","cut","slice")] [I] into [pick("small","tiny")] [pick("pieces","chunks","bits","slices")].")) I.reagents.trans_to_holder(reagents, I.reagents.total_volume, rand(4, 8)/10) // 40% to 80% from chopping, since it's not very efficient qdel(I) /obj/structure/chemkit/dismantle() new /obj/structure/table(loc) new /obj/item/reagent_containers/cooking_container/plate/bowl(loc) if(analyzer) analyzer.forceMove(loc) analyzer = null qdel(src) /obj/structure/chemkit/attackby(obj/item/W, mob/user) if(W.iscrowbar()) dismantle() return if(!istype(W, /obj/item/reagent_containers/food/snacks) && W.is_open_container()) trans_item(W, user) return if(W.isFlameSource()) heat_item(W, user) return if(istype(W) && W.force >= 5 && !has_edge(W) && LAZYLEN(contents - analyzer)) var/obj/item/smashed = pick(contents - analyzer) if(!smashed.reagents && !sheet_reagents[smashed.type]) return // should never happen anyway, but still to_chat(user, SPAN_NOTICE("You begin to [pick("crush","smash","grind")] [smashed].")) if(!do_after(user, 15 SECONDS)) return smash(smashed, user) return if(has_edge(W) && LAZYLEN(contents - analyzer)) var/obj/item/chopped = pick(contents - analyzer) if(!chopped.reagents) return if(!do_after(user, 5 SECONDS)) return chop(chopped, user) return if(!analyzer && istype(W, /obj/item/device/analyzer)) user.drop_from_inventory(W) analyzer = W W.forceMove(src) return if(!is_type_in_list(W, forbidden) && (W.w_class <= 3.0) && (W.reagents || sheet_reagents[W.type])) user.drop_from_inventory(W) W.forceMove(src) return . = ..() /* Makeshift Still */ /obj/structure/distillery name = "makeshift still" icon = 'icons/obj/makeshift_workstation.dmi' icon_state = "distillery-empty" desc = "It's a makeshift still for purifying alcohol." density = 1 anchored = 1 // we don't have it as an opencontainer because it's handled directly var/transfer_out = FALSE var/obj/item/weldingtool/welder /obj/structure/distillery/dismantle() var/obj/structure/reagent_dispensers/keg/keg = new (loc) if (src.reagents && src.reagents.total_volume) src.reagents.trans_to_holder(keg.reagents, src.reagents.total_volume) new /obj/item/stack/rods(get_turf(src), 3) if(welder) welder.forceMove(loc) welder = null qdel(src) /obj/structure/distillery/proc/trans_item(obj/item/W, mob/user) if(transfer_out) if(!reagents.total_volume) to_chat(user, SPAN_NOTICE("\The [src] is empty.")) return var/amt = reagents.trans_to_holder(W.reagents, reagents.total_volume) to_chat(user, SPAN_NOTICE("You fill \the [W] with [amt] units from \the [src].")) return else if(!W.reagents || !W.reagents.total_volume) to_chat(user, SPAN_NOTICE("\The [W] is empty.")) return var/amt = min(10, W.reagents.total_volume) W.reagents.trans_to_holder(src.reagents, amt) // just pour it if you can to_chat(user, SPAN_NOTICE("You pour [amt] units from \the [W] into \the [src].")) return /obj/structure/distillery/proc/distill() if(!reagents || !reagents.total_volume) // can't distill nothing return for(var/datum/reagent/R in src.reagents.reagent_list) if(!istype(R, /datum/reagent/alcohol)) return var/datum/reagent/alcohol/AR = R reagents.add_reagent(/datum/reagent/water, (1-(AR.strength/100))*AR.volume) if(istype(AR, /datum/reagent/alcohol/ethanol)) reagents.add_reagent(/datum/reagent/alcohol/ethanol, (AR.strength/100)*AR.volume) if(istype(AR, /datum/reagent/alcohol/butanol)) reagents.add_reagent(/datum/reagent/alcohol/butanol, (AR.strength/100)*AR.volume) reagents.remove_reagent(AR.type, AR.volume) src.icon_state = "distillery-off" /obj/structure/distillery/attackby(obj/item/W, mob/user) if(W.iscrowbar()) dismantle() return if(!welder && istype(W, /obj/item/weldingtool)) user.drop_from_inventory(W) src.welder = W W.forceMove(src) icon_state = "distillery-off" return if(!istype(W, /obj/item/reagent_containers/food/snacks) && W.is_open_container()) trans_item(W, user) return if(W.isscrewdriver()) transfer_out = !transfer_out to_chat(user, SPAN_NOTICE("You [transfer_out ? "open" : "close"] the spigot on the keg, ready to [transfer_out ? "remove" : "add"] reagents.")) return if(W.isFlameSource() && istype(welder)) to_chat(user, SPAN_NOTICE("You light \the [src] and begin the distillation process.")) addtimer(CALLBACK(src, .proc/distill), 60 SECONDS) src.icon_state = "distillery-active" return . = ..() /obj/structure/distillery/Initialize() . = ..() create_reagents(1000) // same as a keg