diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index bcff3b23e3b..011da504991 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -901,6 +901,8 @@ GLOBAL_LIST_INIT(plastic_recipes, list( new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \ new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, crafting_flags = NONE, category = CAT_FURNITURE), \ + new /datum/stack_recipe("liquid cooler jug", /obj/item/reagent_containers/cooler_jug, 4, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CONTAINERS), \ + new /datum/stack_recipe("liquid cooler", /obj/structure/reagent_dispensers/water_cooler/jugless, 25, time = 10 SECONDS, crafting_flags = NONE, category = CAT_STRUCTURE), \ new /datum/stack_recipe("rebellion mask", /obj/item/clothing/mask/rebellion, 1, crafting_flags = NONE, category = CAT_CLOTHING))) /obj/item/stack/sheet/plastic @@ -909,7 +911,7 @@ GLOBAL_LIST_INIT(plastic_recipes, list( singular_name = "plastic sheet" icon_state = "sheet-plastic" inhand_icon_state = "sheet-plastic" - mats_per_unit = list(/datum/material/plastic=SHEET_MATERIAL_AMOUNT) + mats_per_unit = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT) throwforce = 7 material_type = /datum/material/plastic merge_type = /obj/item/stack/sheet/plastic diff --git a/code/modules/cargo/packs/general.dm b/code/modules/cargo/packs/general.dm index 5d183a5bbb9..ca70a167428 100644 --- a/code/modules/cargo/packs/general.dm +++ b/code/modules/cargo/packs/general.dm @@ -257,3 +257,17 @@ /obj/item/hatchet/cutterblade = 1, ) crate_name = "paper cutters crate" + +/datum/supply_pack/misc/water_cooler + name = "Liquid Cooler - Water" + desc = "A liquid cooler, stocked with the freshest water in all the Periphery. Perfect for wasting time at the office!" + cost = CARGO_CRATE_VALUE * 2 + contains = list(/obj/structure/reagent_dispensers/water_cooler/jugless = 1, /obj/item/reagent_containers/cooler_jug/water = 1) + crate_name = "water cooler crate" + +/datum/supply_pack/misc/punch_cooler + name = "Liquid Cooler - Fruit Punch" + desc = "A liquid cooler, stocked with exotic fruit punch that can heal injuries! Be sure to remain near the liquid cooler while drinking, for your own health and safety. Seriously, do NOT drink this stuff away from the cooler." + cost = CARGO_CRATE_VALUE * 6 + contains = list(/obj/structure/reagent_dispensers/water_cooler/jugless = 1, /obj/item/reagent_containers/cooler_jug/punch = 1) + crate_name = "punch cooler crate" diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index 0be0ca2b75f..1b13ee77cca 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -1309,3 +1309,60 @@ var/obj/item/organ/stomach/ethereal/stomach = exposed_carbon.get_organ_slot(ORGAN_SLOT_STOMACH) if(istype(stomach)) stomach.adjust_charge(reac_volume * 20 * ETHEREAL_DISCHARGE_RATE) + +/datum/reagent/consumable/fruit_punch + name = "fruit punch" + description = "Impossibly sweet fruit punch. Nobody knows what fruits were used to make it, not even it's creators... \ + It's unique recipe heals and rejuvinates the drinker, but is unsafe to consume without the support of a nearby watercooler." + color = "#f7b2e3" + taste_description = "dangerously sweet fruit" + chemical_flags = REAGENT_CAN_BE_SYNTHESIZED + quality = DRINK_VERYGOOD + +/datum/reagent/consumable/fruit_punch/on_mob_life(mob/living/affected_mob, seconds_per_tick) + . = ..() + var/need_mob_update + var/found_valid_cooler = FALSE + for(var/obj/structure/reagent_dispensers/water_cooler/found_cooler in range(4, affected_mob)) + if(found_cooler.anchored) + found_valid_cooler = TRUE + var/obj/effect/temp_visual/heal/heal_effect = new /obj/effect/temp_visual/heal(get_turf(found_cooler)) + heal_effect.color = "#f7b2e3" + break + + if(found_valid_cooler) + affected_mob.clear_alert("punch_bad") + affected_mob.throw_alert("punch_good", /atom/movable/screen/alert/fruit_punch_good) + need_mob_update = affected_mob.adjustToxLoss(-0.6 * REM * seconds_per_tick, updating_health = FALSE) + need_mob_update = affected_mob.adjustBruteLoss(-0.6 * REM * seconds_per_tick, updating_health = FALSE) + need_mob_update = affected_mob.adjustFireLoss(-0.6 * REM * seconds_per_tick, updating_health = FALSE) + affected_mob.remove_movespeed_modifier(/datum/movespeed_modifier/punch_punishment) + else + affected_mob.clear_alert("punch_good") + affected_mob.throw_alert("punch_bad", /atom/movable/screen/alert/fruit_punch_bad) + need_mob_update = affected_mob.apply_damage(1.5 * REM * seconds_per_tick, TOX) + affected_mob.add_movespeed_modifier(/datum/movespeed_modifier/punch_punishment) + if(SPT_PROB(10, seconds_per_tick)) + affected_mob.Knockdown(3 SECONDS, 6 SECONDS) //Gives daze effect. Using the cooler is a commitment and if you get jumped during it or have to run away to fight something, you should be vulnerable. + to_chat(affected_mob, span_warning("The overwhelming sweetness of the fruit punch disorients and confounds you!")) + if(need_mob_update) + return UPDATE_MOB_HEALTH + +/datum/movespeed_modifier/punch_punishment + multiplicative_slowdown = 0.30 + +/datum/reagent/consumable/fruit_punch/on_mob_end_metabolize(mob/living/affected_mob) + . = ..() + affected_mob.clear_alert("punch_bad") + affected_mob.clear_alert("punch_good") + affected_mob.remove_movespeed_modifier(/datum/movespeed_modifier/punch_punishment) + +/atom/movable/screen/alert/fruit_punch_good + name = "Fruit Punch Blessing" + desc = "The sweetness of the fruit punch and the friendly company of the liquid cooler are slowly restoring your health..." + icon_state = "punch_blessing" + +/atom/movable/screen/alert/fruit_punch_bad + name = "Fruit Punishment" + desc = "The unbearable sweetness of the fruit punch is too much to bear without the soothing aura of a liquid cooler! Your body is going into shock!" + icon_state = "punch_punishment" diff --git a/code/modules/reagents/reagent_containers/cooler_jug.dm b/code/modules/reagents/reagent_containers/cooler_jug.dm new file mode 100644 index 00000000000..89fc7f1ea2a --- /dev/null +++ b/code/modules/reagents/reagent_containers/cooler_jug.dm @@ -0,0 +1,25 @@ +/obj/item/reagent_containers/cooler_jug + name = "cooler jug" + desc = "A huge, unwieldy jug. Serves as the life force for liquid coolers. It smells like freshly cooled plastic." + icon = 'icons/obj/medical/chemical_tanks.dmi' + icon_state = "cooler_jug" + volume = 200 + custom_materials = list(/datum/material/plastic = SHEET_MATERIAL_AMOUNT * 4) + reagent_flags = REFILLABLE | DRAINABLE | INJECTABLE | DRAWABLE | TRANSPARENT | SMART_CAP + spillable = TRUE + has_variable_transfer_amount = FALSE + interaction_flags_click = NEED_DEXTERITY + fill_icon_state = "cooler_jug_overlay" + fill_icon_thresholds = list(25, 50, 75, 100) + obj_flags = UNIQUE_RENAME + w_class = WEIGHT_CLASS_BULKY + +/obj/item/reagent_containers/cooler_jug/water + name = "water jug" + desc = "An elegant-looking water cooler jug. There's a water cooler out there, somewhere, waiting to be reunited with this. The jug's mouth smells intoxicatingly stale and metallic." + list_reagents = list(/datum/reagent/water = 200) + +/obj/item/reagent_containers/cooler_jug/punch + name = "punch jug" + desc = "A jug meant for storing fruit punch. It's covered in dozens of warning labels and scary-looking symbols you don't recognize. The smell of sweet punch sticks to the mouth of the jug." + list_reagents = list(/datum/reagent/consumable/fruit_punch = 200) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 1aeb8fff1ff..e7aeb07e093 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -1,4 +1,5 @@ #define REAGENT_SPILL_DIVISOR 200 +#define COOLER_JUG_EJECT_TIME (8 SECONDS) /obj/structure/reagent_dispensers name = "Dispenser" @@ -370,13 +371,30 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/peppertank, 3 find_and_hang_on_wall() /obj/structure/reagent_dispensers/water_cooler - name = "liquid cooler" - desc = "A machine that dispenses liquid to drink." - icon = 'icons/obj/machines/vending.dmi' //SKYRAT EDIT - ICON OVERRIDDEN BY AESTHETICS - SEE MODULE + name = "water cooler" + desc = "A machine that cools and dispenses liquids to drink. The 'hot' handle doesn't seem to do anything." icon_state = "water_cooler" anchored = TRUE - tank_volume = 500 - var/paper_cups = 25 //Paper cups left from the cooler + tank_volume = 200 + can_be_tanked = FALSE + max_integrity = 150 + ///Paper cups left from the cooler. + var/paper_cups = 25 + ///Reference to our jug. + var/obj/item/reagent_containers/cooler_jug/our_jug + ///Have we been tipped? + var/tipped = FALSE + +/obj/structure/reagent_dispensers/water_cooler/Initialize(mapload) + . = ..() + if(prob(2) && mapload) + reagents.convert_reagent(/datum/reagent/water, /datum/reagent/consumable/fruit_punch) + create_jug() + refresh_appearance() + +/obj/structure/reagent_dispensers/water_cooler/Destroy() + . = ..() + our_jug = null /obj/structure/reagent_dispensers/water_cooler/examine(mob/user) . = ..() @@ -391,14 +409,202 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/peppertank, 3 . = ..() if(.) return + + + if(tipped) + balloon_alert(user, "un-tipping...") + if(!do_after(user, 5 SECONDS, src)) + return + tipped = FALSE + refresh_appearance() + return + + + if(user.combat_mode && our_jug) + balloon_alert(user, "removing jug...") + if(!do_after(user, COOLER_JUG_EJECT_TIME, src)) + return + eject_jug(user) + return + if(!paper_cups) to_chat(user, span_warning("There aren't any cups left!")) return user.visible_message(span_notice("[user] takes a cup from [src]."), span_notice("You take a paper cup from [src].")) - var/obj/item/reagent_containers/cup/glass/sillycup/S = new(get_turf(src)) - user.put_in_hands(S) + var/obj/item/reagent_containers/cup/glass/sillycup/new_cup = new(get_turf(src)) + user.put_in_hands(new_cup) paper_cups-- +/obj/structure/reagent_dispensers/water_cooler/update_overlays() + . = ..() + if(!reagents) + return + + if(!reagents.total_volume) + return + + var/mixcolor + var/vol_counter = 0 + var/vol_temp + + for(var/datum/reagent/stored_reagent as anything in reagents.reagent_list) + vol_temp = stored_reagent.volume + vol_counter += vol_temp + + var/chosen_color = stored_reagent.color + if(istype(stored_reagent, /datum/reagent/water)) + if(!mixcolor) + mixcolor = "#2694D6" //Override the water to be a nice blue + continue + else + chosen_color = "#2694D6" + else + if(!mixcolor) + mixcolor = stored_reagent.color + continue + else + chosen_color = stored_reagent.color + + if (length(mixcolor) >= length(chosen_color)) + mixcolor = BlendRGB(mixcolor, chosen_color, vol_temp/vol_counter) + else + mixcolor = BlendRGB(chosen_color, mixcolor, vol_temp/vol_counter) + + if(mixcolor) + var/overlay_tag + if(vol_counter > 100) + overlay_tag = "100" + else + overlay_tag = "50" //Can't be 0, because there'd be no mixcolor + var/mutable_appearance/tank_overlay = mutable_appearance('icons/obj/medical/chemical_tanks.dmi', "water_cooler_overlay[overlay_tag]") + tank_overlay.color = mixcolor + . += tank_overlay + +/obj/structure/reagent_dispensers/water_cooler/wrench_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + + . = ITEM_INTERACT_BLOCKING + if(default_unfasten_wrench(user, tool, time = 6 SECONDS) == SUCCESSFUL_UNFASTEN) + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_dispensers/water_cooler/attack_hand_secondary(mob/user, modifiers) + if(tipped) + balloon_alert(user, "it's already tipped!") + return + + if(anchored) + balloon_alert(user, "it's anchored!") + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + if(!do_after(user, 1.5 SECONDS, src)) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + INVOKE_ASYNC(src, PROC_REF(boom), user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +/obj/structure/reagent_dispensers/water_cooler/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(!istype(tool, /obj/item/reagent_containers/cooler_jug)) + return + + if(tipped) + balloon_alert(user, "it's tipped!") + return + + var/obj/item/reagent_containers/cooler_jug/new_jug = tool + balloon_alert(user, "replacing jug...") + if(!do_after(user, COOLER_JUG_EJECT_TIME, src)) + return + + if(!user.transferItemToLoc(new_jug, src)) + return ITEM_INTERACT_BLOCKING + + eject_jug(user, our_jug) + our_jug = new_jug + our_jug.reagents.trans_to(reagents, tank_volume) + balloon_alert(user, "attached") + user.log_message("attached a [new_jug] to [src] at [AREACOORD(src)] containing ([new_jug.reagents.get_reagent_log_string()])", LOG_ATTACK) + add_fingerprint(user) + refresh_appearance() + return ITEM_INTERACT_SUCCESS + +/obj/structure/reagent_dispensers/water_cooler/boom() + if(QDELETED(src)) + return + var/liquid_amount = 0 + if(reagents.total_volume) + visible_message(span_danger("\The [src] flips on it's side and spills everywhere!")) + chem_splash(get_turf(src), null, 2 + (reagents.total_volume + liquid_amount) / 1000, list(reagents), extra_heat=(liquid_amount / 50), adminlog=(liquid_amount<25)) + eject_jug(throw_away = TRUE) + playsound(src, 'sound/effects/glass/glassbash.ogg', 100) + tip_over() + +/obj/structure/reagent_dispensers/water_cooler/proc/refresh_appearance() + if(tipped) + icon_state = "water_cooler_disgraced" + else + if(!our_jug) + icon_state = "water_cooler_forlorn" + else + icon_state = "water_cooler" + + update_overlays() + update_appearance() + +///Creates an empty jug inside of the cooler. Doesn't need to be filled bc it absorbs the cooler's reagent on eject. +/obj/structure/reagent_dispensers/water_cooler/proc/create_jug() + our_jug = new /obj/item/reagent_containers/cooler_jug(src) + +///Eject the jug in a variety of ways. If there is a user, the jug goes into their hands. throw_away is passed on tip, to empty and throw the jug away. We delete the reagents since we create a splash before this is called. +/obj/structure/reagent_dispensers/water_cooler/proc/eject_jug(mob/living/user, throw_away = FALSE) + if(!our_jug) + return + + if(user) + user.put_in_hands(our_jug) + else + our_jug.forceMove(drop_location()) + + if(throw_away) + var/turf/turf_to_throw_at = get_ranged_target_turf(src, pick(GLOB.alldirs), 2) + our_jug.throw_at(turf_to_throw_at, 2, 3) + reagents.remove_all(tank_volume) //Gets spilled on floor during boom() + else + reagents.trans_to(our_jug.reagents, tank_volume) + + our_jug = null + refresh_appearance() + +///Handles the visual stuff related to the cooler itself tipping. +/obj/structure/reagent_dispensers/water_cooler/proc/tip_over() + tipped = TRUE + refresh_appearance() + +///Pre-tipped version for mapping. +/obj/structure/reagent_dispensers/water_cooler/fallen + tipped = TRUE + reagent_id = null + anchored = FALSE + +/obj/structure/reagent_dispensers/water_cooler/fallen/Initialize(mapload) + . = ..() + tip_over() + +/obj/structure/reagent_dispensers/water_cooler/fallen/create_jug() + return + +/obj/structure/reagent_dispensers/water_cooler/jugless + reagent_id = null + anchored = FALSE + +/obj/structure/reagent_dispensers/water_cooler/jugless/create_jug() + return + +///Punch cooler. Starts full of healing juice. In case anyone wants to map one somewhere as a healing station. +/obj/structure/reagent_dispensers/water_cooler/punch_cooler + name = "punch cooler" + desc = "A machine that dispenses fruit punch to drink. This juice is unbearably sweet, and can only be safely consumed in the presence of a liquid cooler. Engage with caution." + reagent_id = /datum/reagent/consumable/fruit_punch + /obj/structure/reagent_dispensers/beerkeg name = "beer keg" desc = "Beer is liquid bread, it's good for you..." @@ -485,3 +691,4 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/virusfood, 30 accepts_rig = TRUE #undef REAGENT_SPILL_DIVISOR +#undef COOLER_JUG_EJECT_TIME diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi index 1d1f3ff79c0..2d8ab5c7d04 100755 Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ diff --git a/icons/obj/machines/vending.dmi b/icons/obj/machines/vending.dmi index 8c39296a155..f8f1f80cdce 100644 Binary files a/icons/obj/machines/vending.dmi and b/icons/obj/machines/vending.dmi differ diff --git a/icons/obj/medical/chemical_tanks.dmi b/icons/obj/medical/chemical_tanks.dmi index 41f859b1d9e..96582c2ae29 100644 Binary files a/icons/obj/medical/chemical_tanks.dmi and b/icons/obj/medical/chemical_tanks.dmi differ diff --git a/icons/obj/medical/reagent_fillings.dmi b/icons/obj/medical/reagent_fillings.dmi index f3477820dbe..20c760de6da 100644 Binary files a/icons/obj/medical/reagent_fillings.dmi and b/icons/obj/medical/reagent_fillings.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 2a83c1c6c05..3de603a953f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6106,6 +6106,7 @@ #include "code\modules\reagents\reagent_containers\blood_pack.dm" #include "code\modules\reagents\reagent_containers\chem_pack.dm" #include "code\modules\reagents\reagent_containers\condiment.dm" +#include "code\modules\reagents\reagent_containers\cooler_jug.dm" #include "code\modules\reagents\reagent_containers\dropper.dm" #include "code\modules\reagents\reagent_containers\hypospray.dm" #include "code\modules\reagents\reagent_containers\jerrycan.dm"