mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
Merge branch 'master' of https://github.com/Skyrat-SS13/Skyrat-tg into upstream-2406a
This commit is contained in:
@@ -276,6 +276,10 @@
|
||||
//we are the parent node
|
||||
parent_node = src
|
||||
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
// we do this in LateInitialize() because weeds on the same loc may not be done initializing yet (as in create_and_destroy)
|
||||
/obj/structure/alien/weeds/node/LateInitialize()
|
||||
//destroy any non-node weeds on turf
|
||||
var/obj/structure/alien/weeds/check_weed = locate(/obj/structure/alien/weeds) in loc
|
||||
if(check_weed && check_weed != src)
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Shower Curtains
|
||||
*/
|
||||
/obj/structure/curtain
|
||||
name = "curtain"
|
||||
desc = "Contains less than 1% mercury."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "bathroom-open"
|
||||
color = "#ACD1E9" //Default color, didn't bother hardcoding other colors, mappers can and should easily change it.
|
||||
alpha = 200 //Mappers can also just set this to 255 if they want curtains that can't be seen through
|
||||
layer = SIGN_LAYER
|
||||
anchored = TRUE
|
||||
opacity = FALSE
|
||||
density = FALSE
|
||||
/// used in making the icon state
|
||||
var/icon_type = "bathroom"
|
||||
var/open = TRUE
|
||||
/// if it can be seen through when closed
|
||||
var/opaque_closed = FALSE
|
||||
|
||||
/obj/structure/curtain/Initialize(mapload)
|
||||
// see-through curtains should let emissives shine through
|
||||
if(!opaque_closed)
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/proc/toggle()
|
||||
open = !open
|
||||
if(open)
|
||||
layer = SIGN_LAYER
|
||||
set_opacity(FALSE)
|
||||
else
|
||||
layer = WALL_OBJ_LAYER
|
||||
if(opaque_closed)
|
||||
set_opacity(TRUE)
|
||||
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/curtain/update_icon_state()
|
||||
icon_state = "[icon_type]-[open ? "open" : "closed"]"
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/attackby(obj/item/W, mob/user)
|
||||
if (istype(W, /obj/item/toy/crayon))
|
||||
color = input(user,"","Choose Color",color) as color
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/wrench_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
default_unfasten_wrench(user, tool, time = 5 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/curtain/wirecutter_act(mob/living/user, obj/item/I)
|
||||
..()
|
||||
if(anchored)
|
||||
return TRUE
|
||||
|
||||
user.visible_message(span_warning("[user] cuts apart [src]."),
|
||||
span_notice("You start to cut apart [src]."), span_hear("You hear cutting."))
|
||||
if(I.use_tool(src, user, 50, volume=100) && !anchored)
|
||||
to_chat(user, span_notice("You cut apart [src]."))
|
||||
deconstruct()
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/structure/curtain/attack_hand(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
playsound(loc, 'sound/effects/curtain.ogg', 50, TRUE)
|
||||
toggle()
|
||||
|
||||
/obj/structure/curtain/atom_deconstruct(disassembled = TRUE)
|
||||
new /obj/item/stack/sheet/cloth (loc, 2)
|
||||
new /obj/item/stack/sheet/plastic (loc, 2)
|
||||
new /obj/item/stack/rods (loc, 1)
|
||||
|
||||
/obj/structure/curtain/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(damage_amount)
|
||||
playsound(src.loc, 'sound/weapons/slash.ogg', 80, TRUE)
|
||||
else
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, TRUE)
|
||||
if(BURN)
|
||||
playsound(loc, 'sound/items/welder.ogg', 80, TRUE)
|
||||
|
||||
/obj/structure/curtain/bounty
|
||||
icon_type = "bounty"
|
||||
icon_state = "bounty-open"
|
||||
color = null
|
||||
alpha = 255
|
||||
opaque_closed = TRUE
|
||||
|
||||
/obj/structure/curtain/bounty/start_closed
|
||||
icon_state = "bounty-closed"
|
||||
|
||||
/obj/structure/curtain/bounty/start_closed/Initialize(mapload)
|
||||
. = ..()
|
||||
if(open)
|
||||
toggle()
|
||||
|
||||
/obj/structure/curtain/cloth
|
||||
color = null
|
||||
alpha = 255
|
||||
opaque_closed = TRUE
|
||||
|
||||
/obj/structure/curtain/cloth/atom_deconstruct(disassembled = TRUE)
|
||||
new /obj/item/stack/sheet/cloth (loc, 4)
|
||||
new /obj/item/stack/rods (loc, 1)
|
||||
|
||||
/obj/structure/curtain/cloth/fancy
|
||||
icon_type = "cur_fancy"
|
||||
icon_state = "cur_fancy-open"
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical
|
||||
var/id = null
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/Destroy()
|
||||
GLOB.curtains -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/Initialize(mapload)
|
||||
. = ..()
|
||||
GLOB.curtains += src
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
||||
id = "[port.shuttle_id]_[id]"
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/proc/open()
|
||||
icon_state = "[icon_type]-open"
|
||||
layer = SIGN_LAYER
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE)
|
||||
set_density(FALSE)
|
||||
open = TRUE
|
||||
set_opacity(FALSE)
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/proc/close()
|
||||
icon_state = "[icon_type]-closed"
|
||||
layer = WALL_OBJ_LAYER
|
||||
set_density(TRUE)
|
||||
open = FALSE
|
||||
if(opaque_closed)
|
||||
set_opacity(TRUE)
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/attack_hand(mob/user, list/modifiers)
|
||||
return
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/start_closed
|
||||
icon_state = "cur_fancy-closed"
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/start_closed/Initialize(mapload)
|
||||
. = ..()
|
||||
close()
|
||||
@@ -213,7 +213,7 @@
|
||||
|
||||
/obj/machinery/deployable_turret/hmg
|
||||
name = "heavy machine gun turret"
|
||||
desc = "A heavy calibre machine gun commonly used by Nanotrasen forces, famed for it's ability to give people on the recieving end more holes than normal."
|
||||
desc = "A heavy caliber machine gun commonly used by Nanotrasen forces, famed for it's ability to give people on the receiving end more holes than normal."
|
||||
icon_state = "hmg"
|
||||
max_integrity = 250
|
||||
projectile_type = /obj/projectile/bullet/manned_turret/hmg
|
||||
|
||||
@@ -61,9 +61,6 @@
|
||||
|
||||
/obj/structure/door_assembly/examine(mob/user)
|
||||
. = ..()
|
||||
var/doorname = ""
|
||||
if(created_name)
|
||||
doorname = ", written on it is '[created_name]'"
|
||||
switch(state)
|
||||
if(AIRLOCK_ASSEMBLY_NEEDS_WIRES)
|
||||
if(anchored)
|
||||
@@ -80,8 +77,8 @@
|
||||
. += span_notice("There are <i>empty</i> slots for mineral covers.")
|
||||
else if(!glass && !noglass)
|
||||
. += span_notice("There are <i>empty</i> slots for glass windows.")
|
||||
if(doorname)
|
||||
. += span_notice("There is a small <i>paper</i> placard on the assembly labelled \"[doorname]\".")
|
||||
if(created_name)
|
||||
. += span_notice("There is a small <i>paper</i> placard on the assembly, written on it is '[created_name]'.")
|
||||
|
||||
/obj/structure/door_assembly/attackby(obj/item/W, mob/living/user, params)
|
||||
if(istype(W, /obj/item/pen) && !user.combat_mode)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//THIS FILE HAS BEEN EDITED BY SKYRAT EDIT
|
||||
|
||||
/obj/structure/dresser//SKYRAT EDIT - ICON OVERRIDEN BY AESTHETICS - SEE MODULE
|
||||
/obj/structure/dresser//SKYRAT EDIT - ICON OVERRIDDEN BY AESTHETICS - SEE MODULE
|
||||
name = "dresser"
|
||||
desc = "A nicely-crafted wooden dresser. It's filled with lots of undies."
|
||||
icon = 'icons/obj/fluff/general.dmi'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/structure/extinguisher_cabinet
|
||||
name = "extinguisher cabinet"
|
||||
desc = "A small wall mounted cabinet designed to hold a fire extinguisher."
|
||||
icon = 'icons/obj/wallmounts.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon = 'icons/obj/wallmounts.dmi' //ICON OVERRIDDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon_state = "extinguisher_closed"
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#define MEATSPIKE_IRONROD_REQUIREMENT 4
|
||||
|
||||
/obj/structure/kitchenspike_frame//SKYRAT EDIT - ICON OVERRIDEN BY AESTHETICS - SEE MODULE
|
||||
/obj/structure/kitchenspike_frame//SKYRAT EDIT - ICON OVERRIDDEN BY AESTHETICS - SEE MODULE
|
||||
name = "meatspike frame"
|
||||
icon = 'icons/obj/service/kitchen.dmi'
|
||||
icon_state = "spikeframe"
|
||||
@@ -64,7 +64,7 @@
|
||||
return
|
||||
balloon_alert(user, "[MEATSPIKE_IRONROD_REQUIREMENT] rods needed!")
|
||||
|
||||
/obj/structure/kitchenspike//SKYRAT EDIT - ICON OVERRIDEN BY AESTHETICS - SEE MODULE
|
||||
/obj/structure/kitchenspike//SKYRAT EDIT - ICON OVERRIDDEN BY AESTHETICS - SEE MODULE
|
||||
name = "meat spike"
|
||||
icon = 'icons/obj/service/kitchen.dmi'
|
||||
icon_state = "spike"
|
||||
|
||||
@@ -82,6 +82,8 @@
|
||||
icon_state = icon_state_tapped
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
add_overlay(mutable_appearance('icons/obj/mining_zones/terrain.dmi', "well", ABOVE_MOB_LAYER))
|
||||
|
||||
RegisterSignal(src, COMSIG_SPAWNER_SPAWNED_DEFAULT, PROC_REF(anti_cheese))
|
||||
return ..()
|
||||
|
||||
/obj/structure/ore_vent/Destroy()
|
||||
@@ -214,6 +216,7 @@
|
||||
node = new /mob/living/basic/node_drone(loc)
|
||||
node.arrive(src)
|
||||
RegisterSignal(node, COMSIG_QDELETING, PROC_REF(handle_wave_conclusion))
|
||||
RegisterSignal(node, COMSIG_MOVABLE_MOVED, PROC_REF(handle_wave_conclusion))
|
||||
particles = new /particles/smoke/ash()
|
||||
for(var/i in 1 to 5) // Clears the surroundings of the ore vent before starting wave defense.
|
||||
for(var/turf/closed/mineral/rock in oview(i))
|
||||
@@ -266,8 +269,18 @@
|
||||
SEND_SIGNAL(src, COMSIG_VENT_WAVE_CONCLUDED)
|
||||
COOLDOWN_RESET(src, wave_cooldown)
|
||||
particles = null
|
||||
if(!QDELETED(node)) ///The Node Drone has survived the wave defense, and the ore vent is tapped.
|
||||
tapped = TRUE
|
||||
|
||||
if(!QDELETED(node))
|
||||
if(get_turf(node) != get_turf(src))
|
||||
visible_message(span_danger("The [node] detaches from the [src], and the vent closes back up!"))
|
||||
icon_state = initial(icon_state)
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
UnregisterSignal(node, COMSIG_MOVABLE_MOVED)
|
||||
node.pre_escape(success = FALSE)
|
||||
node = null
|
||||
return //Start over!
|
||||
|
||||
tapped = TRUE //The Node Drone has survived the wave defense, and the ore vent is tapped.
|
||||
SSore_generation.processed_vents += src
|
||||
balloon_alert_to_viewers("vent tapped!")
|
||||
icon_state = icon_state_tapped
|
||||
@@ -407,6 +420,13 @@
|
||||
COOLDOWN_START(src, manual_vent_cooldown, 10 SECONDS)
|
||||
return new_rock
|
||||
|
||||
/**
|
||||
* When the ore vent cannot spawn a mob due to being blocked from all sides, we cause some MILD, MILD explosions.
|
||||
* Explosion matches a gibtonite light explosion, as a way to clear neartby solid structures, with a high likelyhood of breaking the NODE drone.
|
||||
*/
|
||||
/obj/structure/ore_vent/proc/anti_cheese()
|
||||
explosion(src, heavy_impact_range = 1, light_impact_range = 3, flame_range = 0, flash_range = 0, adminlog = FALSE)
|
||||
|
||||
//comes with the station, and is already tapped.
|
||||
/obj/structure/ore_vent/starter_resources
|
||||
name = "active ore vent"
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
GLOBAL_LIST_EMPTY(bodycontainers) //Let them act as spawnpoints for revenants and other ghosties.
|
||||
|
||||
/obj/structure/bodycontainer
|
||||
icon = 'icons/obj/structures.dmi'//ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon = 'icons/obj/structures.dmi'//ICON OVERRIDDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon_state = "morgue1"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "airtight plastic flaps"
|
||||
desc = "Heavy duty, airtight, plastic flaps. Definitely can't get past those. No way."
|
||||
gender = PLURAL
|
||||
icon = 'icons/obj/structures.dmi'//ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon = 'icons/obj/structures.dmi'//ICON OVERRIDDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon_state = "plasticflaps"
|
||||
armor_type = /datum/armor/structure_plasticflaps
|
||||
density = FALSE
|
||||
|
||||
@@ -8,14 +8,13 @@
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
pass_flags_self = LETPASSTHROW|PASSSTRUCTURE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
layer = ABOVE_TREE_LAYER
|
||||
plane = ABOVE_GAME_PLANE
|
||||
/// armor is a little bit less than a grille. max_integrity about half that of a grille.
|
||||
armor_type = /datum/armor/structure_railing
|
||||
max_integrity = 25
|
||||
|
||||
var/climbable = TRUE
|
||||
///Initial direction of the railing.
|
||||
var/ini_dir
|
||||
///item released when deconstructed
|
||||
var/item_deconstruct = /obj/item/stack/rods
|
||||
|
||||
@@ -39,7 +38,6 @@
|
||||
|
||||
/obj/structure/railing/Initialize(mapload)
|
||||
. = ..()
|
||||
ini_dir = dir
|
||||
if(climbable)
|
||||
AddElement(/datum/element/climbable)
|
||||
|
||||
@@ -168,8 +166,8 @@
|
||||
adjust_dir_layer(new_dir)
|
||||
|
||||
/obj/structure/railing/wooden_fence/proc/adjust_dir_layer(direction)
|
||||
var/new_layer = (direction & NORTH) ? MOB_LAYER : ABOVE_MOB_LAYER
|
||||
layer = new_layer
|
||||
layer = (direction & NORTH) ? MOB_LAYER : initial(layer)
|
||||
plane = (direction & NORTH) ? GAME_PLANE : initial(plane)
|
||||
|
||||
|
||||
/obj/structure/railing/corner/end/wooden_fence
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/obj/structure/sign/departments/med
|
||||
name = "\improper Medbay sign"
|
||||
sign_change_name = "Department - Medbay"
|
||||
desc = "A sign labeling an area of medical department."
|
||||
desc = "A sign labelling an area of the medical department."
|
||||
icon_state = "med"
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/departments/med, 32)
|
||||
@@ -23,7 +23,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/departments/med_alt, 32)
|
||||
/obj/structure/sign/departments/medbay
|
||||
name = "\improper Medbay sign"
|
||||
sign_change_name = "Generic Medical"
|
||||
desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here."
|
||||
desc = "The intergalactic symbol of medical institutions. You'll probably get help here."
|
||||
icon_state = "bluecross"
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/departments/medbay, 32)
|
||||
@@ -84,7 +84,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/departments/virology, 32)
|
||||
/obj/structure/sign/departments/morgue
|
||||
name = "\improper Morgue sign"
|
||||
sign_change_name = "Department - Medbay: Morgue"
|
||||
desc = "A sign labelling an area where station stores its ever-piling bodies."
|
||||
desc = "A sign labelling an area where the station stores its ever-piling bodies."
|
||||
icon_state = "morgue"
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/departments/morgue, 32)
|
||||
|
||||
@@ -199,7 +199,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/warning/gas_mask, 32)
|
||||
/obj/structure/sign/warning/chem_diamond
|
||||
name = "\improper REACTIVE CHEMICALS sign"
|
||||
sign_change_name = "Warning - Hazardous Chemicals sign"
|
||||
desc = "A sign that warns of potentially reactive chemicals nearby, be they explosive, flamable, or acidic."
|
||||
desc = "A sign that warns of potentially reactive chemicals nearby, be they explosive, flammable, or acidic."
|
||||
icon_state = "chemdiamond"
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sign/warning/chem_diamond, 32)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
name = "suspicious beacon"
|
||||
icon = 'icons/obj/machines/telecomms.dmi'
|
||||
icon_state = "relay_traitor"
|
||||
desc = "This ramshackle device seems capable of recieving and sending signals for some nefarious purpose."
|
||||
desc = "This ramshackle device seems capable of receiving and sending signals for some nefarious purpose."
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
/// Traitor's code that they speak into the radio
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
/obj/structure/sink
|
||||
name = "sink"
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "sink"
|
||||
desc = "A sink used for washing one's hands and face. Passively reclaims water over time."
|
||||
anchored = TRUE
|
||||
layer = ABOVE_OBJ_LAYER
|
||||
pixel_z = 1
|
||||
///Something's being washed at the moment
|
||||
var/busy = FALSE
|
||||
///What kind of reagent is produced by this sink by default? (We now have actual plumbing, Arcane, August 2020)
|
||||
var/dispensedreagent = /datum/reagent/water
|
||||
///Material to drop when broken or deconstructed.
|
||||
var/buildstacktype = /obj/item/stack/sheet/iron
|
||||
///Number of sheets of material to drop when broken or deconstructed.
|
||||
var/buildstackamount = 1
|
||||
///Does the sink have a water recycler to recollect it's water supply?
|
||||
var/has_water_reclaimer = TRUE
|
||||
///Units of water to reclaim per second
|
||||
var/reclaim_rate = 0.5
|
||||
///Amount of shift the pixel for placement
|
||||
var/pixel_shift = 14
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14))
|
||||
|
||||
/obj/structure/sink/Initialize(mapload, ndir = 0, has_water_reclaimer = null)
|
||||
. = ..()
|
||||
|
||||
if(ndir)
|
||||
dir = ndir
|
||||
|
||||
if(has_water_reclaimer != null)
|
||||
src.has_water_reclaimer = has_water_reclaimer
|
||||
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
pixel_x = 0
|
||||
pixel_y = -pixel_shift
|
||||
if(SOUTH)
|
||||
pixel_x = 0
|
||||
pixel_y = pixel_shift
|
||||
if(EAST)
|
||||
pixel_x = -pixel_shift
|
||||
pixel_y = 0
|
||||
if(WEST)
|
||||
pixel_x = pixel_shift
|
||||
pixel_y = 0
|
||||
|
||||
create_reagents(100, NO_REACT)
|
||||
if(src.has_water_reclaimer)
|
||||
reagents.add_reagent(dispensedreagent, 100)
|
||||
AddComponent(/datum/component/plumbing/simple_demand, extend_pipe_to_edge = TRUE)
|
||||
|
||||
/obj/structure/sink/examine(mob/user)
|
||||
. = ..()
|
||||
if(has_water_reclaimer)
|
||||
. += span_notice("A water recycler is installed. It looks like you could pry it out.")
|
||||
. += span_notice("[reagents.total_volume]/[reagents.maximum_volume] liquids remaining.")
|
||||
|
||||
/obj/structure/sink/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!user || !istype(user))
|
||||
return
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
if(reagents.total_volume < 5)
|
||||
to_chat(user, span_warning("The sink has no more contents left!"))
|
||||
return
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
var/selected_area = user.parse_zone_with_bodypart(user.zone_selected)
|
||||
var/washing_face = 0
|
||||
if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES))
|
||||
washing_face = 1
|
||||
user.visible_message(span_notice("[user] starts washing [user.p_their()] [washing_face ? "face" : "hands"]..."), \
|
||||
span_notice("You start washing your [washing_face ? "face" : "hands"]..."))
|
||||
busy = TRUE
|
||||
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return
|
||||
|
||||
busy = FALSE
|
||||
reagents.remove_all(5)
|
||||
reagents.expose(user, TOUCH, 5 / max(reagents.total_volume, 5))
|
||||
begin_reclamation()
|
||||
if(washing_face)
|
||||
SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_FACE_ACT, CLEAN_WASH)
|
||||
else if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
if(!human_user.wash_hands(CLEAN_WASH))
|
||||
to_chat(user, span_warning("Your hands are covered by something!"))
|
||||
return
|
||||
else
|
||||
user.wash(CLEAN_WASH)
|
||||
|
||||
user.visible_message(span_notice("[user] washes [user.p_their()] [washing_face ? "face" : "hands"] using [src]."), \
|
||||
span_notice("You wash your [washing_face ? "face" : "hands"] using [src]."))
|
||||
|
||||
/obj/structure/sink/attackby(obj/item/O, mob/living/user, params)
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
|
||||
if(is_reagent_container(O))
|
||||
var/obj/item/reagent_containers/RG = O
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(user, span_notice("\The [src] is dry."))
|
||||
return FALSE
|
||||
if(RG.is_refillable())
|
||||
if(!RG.reagents.holder_full())
|
||||
reagents.trans_to(RG, RG.amount_per_transfer_from_this, transferred_by = user)
|
||||
begin_reclamation()
|
||||
to_chat(user, span_notice("You fill [RG] from [src]."))
|
||||
return TRUE
|
||||
to_chat(user, span_notice("\The [RG] is full."))
|
||||
return FALSE
|
||||
|
||||
if(istype(O, /obj/item/melee/baton/security))
|
||||
var/obj/item/melee/baton/security/baton = O
|
||||
if(baton.cell?.charge && baton.active)
|
||||
flick("baton_active", src)
|
||||
user.Paralyze(baton.knockdown_time)
|
||||
user.set_stutter(baton.knockdown_time)
|
||||
baton.cell.use(baton.cell_hit_cost)
|
||||
user.visible_message(span_warning("[user] shocks [user.p_them()]self while attempting to wash the active [baton.name]!"), \
|
||||
span_userdanger("You unwisely attempt to wash [baton] while it's still on."))
|
||||
playsound(src, baton.on_stun_sound, 50, TRUE)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/mop))
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(user, span_notice("\The [src] is dry."))
|
||||
return FALSE
|
||||
reagents.trans_to(O, 5, transferred_by = user)
|
||||
begin_reclamation()
|
||||
to_chat(user, span_notice("You wet [O] in [src]."))
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
|
||||
return
|
||||
|
||||
if(O.tool_behaviour == TOOL_WRENCH)
|
||||
O.play_tool_sound(src)
|
||||
deconstruct()
|
||||
return
|
||||
|
||||
if(O.tool_behaviour == TOOL_CROWBAR)
|
||||
if(!has_water_reclaimer)
|
||||
to_chat(user, span_warning("There isn't a water recycler to remove."))
|
||||
return
|
||||
|
||||
O.play_tool_sound(src)
|
||||
has_water_reclaimer = FALSE
|
||||
new/obj/item/stock_parts/water_recycler(get_turf(loc))
|
||||
to_chat(user, span_notice("You remove the water reclaimer from [src]"))
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/medical/gauze))
|
||||
var/obj/item/stack/medical/gauze/G = O
|
||||
new /obj/item/reagent_containers/cup/rag(src.loc)
|
||||
to_chat(user, span_notice("You tear off a strip of gauze and make a rag."))
|
||||
G.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/sheet/cloth))
|
||||
var/obj/item/stack/sheet/cloth/cloth = O
|
||||
new /obj/item/reagent_containers/cup/rag(loc)
|
||||
to_chat(user, span_notice("You tear off a strip of cloth and make a rag."))
|
||||
cloth.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/ore/glass))
|
||||
new /obj/item/stack/sheet/sandblock(loc)
|
||||
to_chat(user, span_notice("You wet the sand in the sink and form it into a block."))
|
||||
O.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stock_parts/water_recycler))
|
||||
if(has_water_reclaimer)
|
||||
to_chat(user, span_warning("There is already has a water recycler installed."))
|
||||
return
|
||||
|
||||
playsound(src, 'sound/machines/click.ogg', 20, TRUE)
|
||||
qdel(O)
|
||||
has_water_reclaimer = TRUE
|
||||
begin_reclamation()
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/storage/fancy/pickles_jar))
|
||||
if(O.contents.len)
|
||||
to_chat(user, span_notice("Looks like there's something left in the jar"))
|
||||
return
|
||||
new /obj/item/reagent_containers/cup/beaker/large(loc)
|
||||
to_chat(user, span_notice("You washed the jar, ridding it of the brine."))
|
||||
qdel(O)
|
||||
return
|
||||
|
||||
if(!istype(O))
|
||||
return
|
||||
if(O.item_flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand.
|
||||
return
|
||||
|
||||
if(!user.combat_mode)
|
||||
to_chat(user, span_notice("You start washing [O]..."))
|
||||
busy = TRUE
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return 1
|
||||
busy = FALSE
|
||||
O.wash(CLEAN_WASH)
|
||||
reagents.expose(O, TOUCH, 5 / max(reagents.total_volume, 5))
|
||||
user.visible_message(span_notice("[user] washes [O] using [src]."), \
|
||||
span_notice("You wash [O] using [src]."))
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/sink/atom_deconstruct(dissambled = TRUE)
|
||||
drop_materials()
|
||||
if(has_water_reclaimer)
|
||||
new /obj/item/stock_parts/water_recycler(drop_location())
|
||||
|
||||
/obj/structure/sink/process(seconds_per_tick)
|
||||
// Water reclamation complete?
|
||||
if(!has_water_reclaimer || reagents.total_volume >= reagents.maximum_volume)
|
||||
return PROCESS_KILL
|
||||
|
||||
reagents.add_reagent(dispensedreagent, reclaim_rate * seconds_per_tick)
|
||||
|
||||
/obj/structure/sink/proc/drop_materials()
|
||||
if(buildstacktype)
|
||||
new buildstacktype(loc,buildstackamount)
|
||||
else
|
||||
for(var/i in custom_materials)
|
||||
var/datum/material/M = i
|
||||
new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1))
|
||||
|
||||
/obj/structure/sink/proc/begin_reclamation()
|
||||
START_PROCESSING(SSplumbing, src)
|
||||
|
||||
/obj/structure/sink/kitchen
|
||||
name = "kitchen sink"
|
||||
icon_state = "sink_alt"
|
||||
pixel_z = 4
|
||||
pixel_shift = 16
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16))
|
||||
|
||||
/obj/structure/sink/greyscale
|
||||
icon_state = "sink_greyscale"
|
||||
material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
|
||||
buildstacktype = null
|
||||
|
||||
/obj/structure/sinkframe
|
||||
name = "sink frame"
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "sink_frame"
|
||||
desc = "A sink frame, that needs a water recycler to finish construction."
|
||||
anchored = FALSE
|
||||
material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
|
||||
|
||||
/obj/structure/sinkframe/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/simple_rotation)
|
||||
|
||||
/obj/structure/sinkframe/attackby(obj/item/tool, mob/living/user, params)
|
||||
if(istype(tool, /obj/item/stock_parts/water_recycler))
|
||||
qdel(tool)
|
||||
var/obj/structure/sink/greyscale/new_sink = new(loc, REVERSE_DIR(dir), TRUE)
|
||||
new_sink.set_custom_materials(custom_materials)
|
||||
qdel(src)
|
||||
playsound(new_sink, 'sound/machines/click.ogg', 20, TRUE)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/sinkframe/wrench_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
var/obj/structure/sink/greyscale/new_sink = new(loc, REVERSE_DIR(dir), FALSE)
|
||||
new_sink.set_custom_materials(custom_materials)
|
||||
qdel(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/structure/sinkframe/wrench_act_secondary(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
tool.play_tool_sound(src)
|
||||
deconstruct()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/sinkframe/atom_deconstruct(dissambled = TRUE)
|
||||
drop_materials()
|
||||
|
||||
/obj/structure/sinkframe/proc/drop_materials()
|
||||
for(var/datum/material/material as anything in custom_materials)
|
||||
new material.sheet_type(loc, FLOOR(custom_materials[material] / SHEET_MATERIAL_AMOUNT, 1))
|
||||
@@ -0,0 +1,271 @@
|
||||
/obj/structure/toilet
|
||||
name = "toilet"
|
||||
desc = "The HT-451, a torque rotation-based, waste disposal unit for small matter. This one seems remarkably clean."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "toilet00" //The first number represents if the toilet lid is up, the second is if the cistern is open.
|
||||
base_icon_state = "toilet"
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
|
||||
///Boolean if whether the toilet is currently flushing.
|
||||
var/flushing = FALSE
|
||||
///Boolean if the toilet seat is up.
|
||||
var/cover_open = FALSE
|
||||
///Boolean if the cistern is up, allowing items to be put in/out.
|
||||
var/cistern_open = FALSE
|
||||
///The combined weight of all items in the cistern put together.
|
||||
var/w_items = 0
|
||||
///Reference to the mob being given a swirlie.
|
||||
var/mob/living/swirlie
|
||||
///The type of material used to build the toilet.
|
||||
var/buildstacktype = /obj/item/stack/sheet/iron
|
||||
///How much of the buildstacktype is needed to construct the toilet.
|
||||
var/buildstackamount = 1
|
||||
///Lazylist of items in the cistern.
|
||||
var/list/cistern_items
|
||||
///Lazylist of fish in the toilet, not to be mixed with the items in the cistern. Max of 3
|
||||
var/list/fishes
|
||||
///Static toilet water overlay given to toilets that are facing a direction we can see the water in.
|
||||
var/static/mutable_appearance/toilet_water_overlay
|
||||
|
||||
/obj/structure/toilet/Initialize(mapload)
|
||||
. = ..()
|
||||
if(isnull(toilet_water_overlay))
|
||||
toilet_water_overlay = mutable_appearance(icon, "[base_icon_state]-water")
|
||||
cover_open = round(rand(0, 1))
|
||||
update_appearance(UPDATE_ICON)
|
||||
if(mapload && SSmapping.level_trait(z, ZTRAIT_STATION))
|
||||
AddElement(/datum/element/lazy_fishing_spot, /datum/fish_source/toilet)
|
||||
register_context()
|
||||
|
||||
/obj/structure/toilet/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
||||
. = ..()
|
||||
if(user.pulling && isliving(user.pulling))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Give Swirlie"
|
||||
else if(cover_open && istype(held_item, /obj/item/fish))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Insert Fish"
|
||||
else if(cover_open && LAZYLEN(fishes))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Grab Fish"
|
||||
else if(cistern_open)
|
||||
if(isnull(held_item))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Check Cistern"
|
||||
else
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Insert Item"
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Flush"
|
||||
context[SCREENTIP_CONTEXT_ALT_LMB] = "[cover_open ? "Close" : "Open"] Lid"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
/obj/structure/toilet/examine(mob/user)
|
||||
. = ..()
|
||||
if(cover_open && LAZYLEN(fishes))
|
||||
. += span_notice("You can see fish in the toilet, you can probably take one out.")
|
||||
|
||||
/obj/structure/toilet/examine_more(mob/user)
|
||||
. = ..()
|
||||
if(cistern_open && LAZYLEN(cistern_items))
|
||||
. += span_notice("You can see [cistern_items.len] items inside of the cistern.")
|
||||
|
||||
/obj/structure/toilet/Destroy(force)
|
||||
. = ..()
|
||||
QDEL_LAZYLIST(fishes)
|
||||
QDEL_LAZYLIST(cistern_items)
|
||||
|
||||
/obj/structure/toilet/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if(gone in cistern_items)
|
||||
LAZYREMOVE(cistern_items, gone)
|
||||
return
|
||||
if(gone in fishes)
|
||||
LAZYREMOVE(fishes, gone)
|
||||
return
|
||||
|
||||
/obj/structure/toilet/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(swirlie)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
playsound(src.loc, SFX_SWING_HIT, 25, TRUE)
|
||||
swirlie.visible_message(span_danger("[user] slams the toilet seat onto [swirlie]'s head!"), span_userdanger("[user] slams the toilet seat onto your head!"), span_hear("You hear reverberating porcelain."))
|
||||
log_combat(user, swirlie, "swirlied (brute)")
|
||||
swirlie.adjustBruteLoss(5)
|
||||
return
|
||||
|
||||
if(user.pulling && isliving(user.pulling))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
var/mob/living/grabbed_mob = user.pulling
|
||||
if(user.grab_state < GRAB_AGGRESSIVE)
|
||||
to_chat(user, span_warning("You need a tighter grip!"))
|
||||
return
|
||||
if(grabbed_mob.loc != get_turf(src))
|
||||
to_chat(user, span_warning("[grabbed_mob] needs to be on [src]!"))
|
||||
return
|
||||
if(swirlie)
|
||||
return
|
||||
if(cover_open)
|
||||
grabbed_mob.visible_message(span_danger("[user] starts to give [grabbed_mob] a swirlie!"), span_userdanger("[user] starts to give you a swirlie..."))
|
||||
swirlie = grabbed_mob
|
||||
var/was_alive = (swirlie.stat != DEAD)
|
||||
if(!do_after(user, 3 SECONDS, target = src, timed_action_flags = IGNORE_HELD_ITEM))
|
||||
swirlie = null
|
||||
return
|
||||
grabbed_mob.visible_message(span_danger("[user] gives [grabbed_mob] a swirlie!"), span_userdanger("[user] gives you a swirlie!"), span_hear("You hear a toilet flushing."))
|
||||
if(iscarbon(grabbed_mob))
|
||||
var/mob/living/carbon/carbon_grabbed = grabbed_mob
|
||||
if(!carbon_grabbed.internal)
|
||||
log_combat(user, carbon_grabbed, "swirlied (oxy)")
|
||||
carbon_grabbed.adjustOxyLoss(5)
|
||||
else
|
||||
log_combat(user, grabbed_mob, "swirlied (oxy)")
|
||||
grabbed_mob.adjustOxyLoss(5)
|
||||
if(was_alive && swirlie.stat == DEAD && swirlie.client)
|
||||
swirlie.client.give_award(/datum/award/achievement/misc/swirlie, swirlie) // just like space high school all over again!
|
||||
swirlie = null
|
||||
else
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 25, TRUE)
|
||||
grabbed_mob.visible_message(span_danger("[user] slams [grabbed_mob.name] into [src]!"), span_userdanger("[user] slams you into [src]!"))
|
||||
log_combat(user, grabbed_mob, "toilet slammed")
|
||||
grabbed_mob.adjustBruteLoss(5)
|
||||
return
|
||||
|
||||
if(cistern_open && !cover_open && user.CanReach(src))
|
||||
if(!LAZYLEN(cistern_items))
|
||||
to_chat(user, span_notice("The cistern is empty."))
|
||||
return
|
||||
var/obj/item/random_cistern_item = pick(cistern_items)
|
||||
if(ishuman(user))
|
||||
user.put_in_hands(random_cistern_item)
|
||||
else
|
||||
random_cistern_item.forceMove(drop_location())
|
||||
to_chat(user, span_notice("You find [random_cistern_item] in the cistern."))
|
||||
w_items -= random_cistern_item.w_class
|
||||
return
|
||||
|
||||
if(!flushing && LAZYLEN(fishes) && cover_open)
|
||||
var/obj/item/random_fish = pick(fishes)
|
||||
if(ishuman(user))
|
||||
user.put_in_hands(random_fish)
|
||||
else
|
||||
random_fish.forceMove(drop_location())
|
||||
to_chat(user, span_notice("You take [random_fish] out of the toilet, poor thing."))
|
||||
|
||||
/obj/structure/toilet/click_alt(mob/living/user)
|
||||
if(flushing)
|
||||
return CLICK_ACTION_BLOCKING
|
||||
cover_open = !cover_open
|
||||
update_appearance(UPDATE_ICON)
|
||||
return CLICK_ACTION_SUCCESS
|
||||
|
||||
/obj/structure/toilet/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(flushing)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
flushing = TRUE
|
||||
playsound(src, "sound/machines/toilet_flush.ogg", cover_open ? 40 : 20, TRUE)
|
||||
if(cover_open && (dir & SOUTH))
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
flick_overlay_view(mutable_appearance(icon, "[base_icon_state]-water-flick"), 3 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(end_flushing)), 4 SECONDS)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/structure/toilet/update_icon_state()
|
||||
icon_state = "[base_icon_state][cover_open][cistern_open]"
|
||||
return ..()
|
||||
|
||||
/obj/structure/toilet/update_overlays()
|
||||
. = ..()
|
||||
if(!flushing && cover_open && (dir & SOUTH))
|
||||
. += toilet_water_overlay
|
||||
|
||||
/obj/structure/toilet/atom_deconstruct(dissambled = TRUE)
|
||||
for(var/obj/toilet_item in cistern_items)
|
||||
toilet_item.forceMove(drop_location())
|
||||
if(buildstacktype)
|
||||
new buildstacktype(loc,buildstackamount)
|
||||
else
|
||||
for(var/datum/material/M as anything in custom_materials)
|
||||
new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1))
|
||||
|
||||
/obj/structure/toilet/attackby(obj/item/attacking_item, mob/living/user, params)
|
||||
add_fingerprint(user)
|
||||
if(cover_open && istype(attacking_item, /obj/item/fish))
|
||||
if(fishes >= 3)
|
||||
to_chat(user, span_warning("There's too many fishes, flush them down first."))
|
||||
return
|
||||
if(!user.transferItemToLoc(attacking_item, src))
|
||||
to_chat(user, span_warning("\The [attacking_item] is stuck to your hand!"))
|
||||
return
|
||||
var/obj/item/fish/the_fish = attacking_item
|
||||
if(the_fish.status == FISH_DEAD)
|
||||
to_chat(user, span_warning("You place [attacking_item] into [src], may it rest in peace."))
|
||||
else
|
||||
to_chat(user, span_notice("You place [attacking_item] into [src], hopefully no one will miss it!"))
|
||||
LAZYADD(fishes, attacking_item)
|
||||
return
|
||||
|
||||
if(cistern_open && !user.combat_mode)
|
||||
if(attacking_item.w_class > WEIGHT_CLASS_NORMAL)
|
||||
to_chat(user, span_warning("[attacking_item] does not fit!"))
|
||||
return
|
||||
if(w_items + attacking_item.w_class > WEIGHT_CLASS_HUGE)
|
||||
to_chat(user, span_warning("The cistern is full!"))
|
||||
return
|
||||
if(!user.transferItemToLoc(attacking_item, src))
|
||||
to_chat(user, span_warning("\The [attacking_item] is stuck to your hand, you cannot put it in the cistern!"))
|
||||
return
|
||||
LAZYADD(cistern_items, attacking_item)
|
||||
w_items += attacking_item.w_class
|
||||
to_chat(user, span_notice("You carefully place [attacking_item] into the cistern."))
|
||||
return
|
||||
|
||||
if(is_reagent_container(attacking_item) && !user.combat_mode)
|
||||
if (!cover_open)
|
||||
return
|
||||
if(istype(attacking_item, /obj/item/food/monkeycube))
|
||||
var/obj/item/food/monkeycube/cube = attacking_item
|
||||
cube.Expand()
|
||||
return
|
||||
var/obj/item/reagent_containers/RG = attacking_item
|
||||
RG.reagents.add_reagent(/datum/reagent/water, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
|
||||
to_chat(user, span_notice("You fill [RG] from [src]. Gross."))
|
||||
return ..()
|
||||
|
||||
/obj/structure/toilet/crowbar_act(mob/living/user, obj/item/tool)
|
||||
to_chat(user, span_notice("You start to [cistern_open ? "replace the lid on" : "lift the lid off"] the cistern..."))
|
||||
playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, TRUE)
|
||||
if(tool.use_tool(src, user, 30))
|
||||
user.visible_message(
|
||||
span_notice("[user] [cistern_open ? "replaces the lid on" : "lifts the lid off"] the cistern!"),
|
||||
span_notice("You [cistern_open ? "replace the lid on" : "lift the lid off"] the cistern!"),
|
||||
span_hear("You hear grinding porcelain."))
|
||||
cistern_open = !cistern_open
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/toilet/wrench_act(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(src)
|
||||
deconstruct()
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
///Ends the flushing animation and updates overlays if necessary
|
||||
/obj/structure/toilet/proc/end_flushing()
|
||||
flushing = FALSE
|
||||
if(cover_open && (dir & SOUTH))
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
QDEL_LAZYLIST(fishes)
|
||||
|
||||
/obj/structure/toilet/greyscale
|
||||
material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
|
||||
buildstacktype = null
|
||||
|
||||
/obj/structure/toilet/secret
|
||||
var/secret_type = null
|
||||
|
||||
/obj/structure/toilet/secret/Initialize(mapload)
|
||||
. = ..()
|
||||
if(secret_type)
|
||||
var/obj/item/secret = new secret_type(src)
|
||||
secret.desc += " It's a secret!"
|
||||
w_items += secret.w_class
|
||||
LAZYADD(cistern_items, secret)
|
||||
@@ -0,0 +1,116 @@
|
||||
/obj/structure/urinal
|
||||
name = "urinal"
|
||||
desc = "The HU-452, an experimental urinal. Comes complete with experimental urinal cake."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "urinal"
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
/// Can you currently put an item inside
|
||||
var/exposed = FALSE
|
||||
/// What's in the urinal
|
||||
var/obj/item/hidden_item
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32)
|
||||
|
||||
/obj/structure/urinal/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload)
|
||||
hidden_item = new /obj/item/food/urinalcake(src)
|
||||
find_and_hang_on_wall()
|
||||
|
||||
/obj/structure/urinal/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if(gone == hidden_item)
|
||||
hidden_item = null
|
||||
|
||||
/obj/structure/urinal/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
if(user.pulling && isliving(user.pulling))
|
||||
var/mob/living/grabbed_mob = user.pulling
|
||||
if(user.grab_state >= GRAB_AGGRESSIVE)
|
||||
if(grabbed_mob.loc != get_turf(src))
|
||||
to_chat(user, span_notice("[grabbed_mob.name] needs to be on [src]."))
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.visible_message(span_danger("[user] slams [grabbed_mob] into [src]!"), span_danger("You slam [grabbed_mob] into [src]!"))
|
||||
grabbed_mob.emote("scream")
|
||||
grabbed_mob.adjustBruteLoss(8)
|
||||
else
|
||||
to_chat(user, span_warning("You need a tighter grip!"))
|
||||
return
|
||||
|
||||
if(exposed)
|
||||
if(hidden_item)
|
||||
to_chat(user, span_notice("You fish [hidden_item] out of the drain enclosure."))
|
||||
user.put_in_hands(hidden_item)
|
||||
else
|
||||
to_chat(user, span_warning("There is nothing in the drain holder!"))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/urinal/attackby(obj/item/attacking_item, mob/user, params)
|
||||
if(exposed)
|
||||
if(hidden_item)
|
||||
to_chat(user, span_warning("There is already something in the drain enclosure!"))
|
||||
return
|
||||
if(attacking_item.w_class > WEIGHT_CLASS_TINY)
|
||||
to_chat(user, span_warning("[attacking_item] is too large for the drain enclosure."))
|
||||
return
|
||||
if(!user.transferItemToLoc(attacking_item, src))
|
||||
to_chat(user, span_warning("[attacking_item] is stuck to your hand, you cannot put it in the drain enclosure!"))
|
||||
return
|
||||
hidden_item = attacking_item
|
||||
to_chat(user, span_notice("You place [attacking_item] into the drain enclosure."))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/urinal/screwdriver_act(mob/living/user, obj/item/I)
|
||||
if(..())
|
||||
return TRUE
|
||||
to_chat(user, span_notice("You start to [exposed ? "screw the cap back into place" : "unscrew the cap to the drain protector"]..."))
|
||||
playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, TRUE)
|
||||
if(I.use_tool(src, user, 20))
|
||||
user.visible_message(span_notice("[user] [exposed ? "screws the cap back into place" : "unscrew the cap to the drain protector"]!"),
|
||||
span_notice("You [exposed ? "screw the cap back into place" : "unscrew the cap on the drain"]!"),
|
||||
span_hear("You hear metal and squishing noises."))
|
||||
exposed = !exposed
|
||||
return TRUE
|
||||
|
||||
/obj/structure/urinal/wrench_act_secondary(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(user)
|
||||
deconstruct(TRUE)
|
||||
balloon_alert(user, "removed urinal")
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/urinal/atom_deconstruct(disassembled = TRUE)
|
||||
new /obj/item/wallframe/urinal(loc)
|
||||
hidden_item?.forceMove(drop_location())
|
||||
|
||||
/obj/item/wallframe/urinal
|
||||
name = "urinal frame"
|
||||
desc = "An unmounted urinal. Attach it to a wall to use."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "urinal"
|
||||
result_path = /obj/structure/urinal
|
||||
pixel_shift = 32
|
||||
|
||||
/obj/item/food/urinalcake
|
||||
name = "urinal cake"
|
||||
desc = "The noble urinal cake, protecting the station's pipes from the station's pee. Do not eat."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "urinalcake"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
food_reagents = list(
|
||||
/datum/reagent/chlorine = 3,
|
||||
/datum/reagent/ammonia = 1,
|
||||
)
|
||||
foodtypes = TOXIC | GROSS
|
||||
preserved_food = TRUE
|
||||
|
||||
/obj/item/food/urinalcake/attack_self(mob/living/user)
|
||||
user.visible_message(span_notice("[user] squishes [src]!"), span_notice("You squish [src]."), "<i>You hear a squish.</i>")
|
||||
icon_state = "urinalcake_squish"
|
||||
addtimer(VARSET_CALLBACK(src, icon_state, "urinalcake"), 0.8 SECONDS)
|
||||
@@ -0,0 +1,149 @@
|
||||
//Water source, use the type water_source for unlimited water sources like classic sinks.
|
||||
/obj/structure/water_source
|
||||
name = "Water Source"
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "sink"
|
||||
desc = "A sink used for washing one's hands and face. This one seems to be infinite!"
|
||||
anchored = TRUE
|
||||
///Boolean on whether something is currently being washed, preventing multiple people from cleaning at once.
|
||||
var/busy = FALSE
|
||||
///The reagent that is dispensed from this source, by default it's water.
|
||||
var/datum/reagent/dispensedreagent = /datum/reagent/water
|
||||
|
||||
/obj/structure/water_source/Initialize(mapload)
|
||||
. = ..()
|
||||
create_reagents(INFINITY, NO_REACT)
|
||||
reagents.add_reagent(dispensedreagent, INFINITY)
|
||||
|
||||
/obj/structure/water_source/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
var/selected_area = user.parse_zone_with_bodypart(user.zone_selected)
|
||||
var/washing_face = FALSE
|
||||
if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES))
|
||||
washing_face = TRUE
|
||||
user.visible_message(
|
||||
span_notice("[user] starts washing [user.p_their()] [washing_face ? "face" : "hands"]..."),
|
||||
span_notice("You start washing your [washing_face ? "face" : "hands"]..."))
|
||||
busy = TRUE
|
||||
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return
|
||||
|
||||
busy = FALSE
|
||||
|
||||
if(washing_face)
|
||||
SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_FACE_ACT, CLEAN_WASH)
|
||||
else if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
if(!human_user.wash_hands(CLEAN_WASH))
|
||||
to_chat(user, span_warning("Your hands are covered by something!"))
|
||||
return
|
||||
else
|
||||
user.wash(CLEAN_WASH)
|
||||
|
||||
user.visible_message(
|
||||
span_notice("[user] washes [user.p_their()] [washing_face ? "face" : "hands"] using [src]."),
|
||||
span_notice("You wash your [washing_face ? "face" : "hands"] using [src]."),
|
||||
)
|
||||
|
||||
/obj/structure/water_source/attackby(obj/item/attacking_item, mob/living/user, params)
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
|
||||
if(attacking_item.item_flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand.
|
||||
return
|
||||
|
||||
if(is_reagent_container(attacking_item))
|
||||
var/obj/item/reagent_containers/container = attacking_item
|
||||
if(container.is_refillable())
|
||||
if(!container.reagents.holder_full())
|
||||
container.reagents.add_reagent(dispensedreagent, min(container.volume - container.reagents.total_volume, container.amount_per_transfer_from_this))
|
||||
to_chat(user, span_notice("You fill [container] from [src]."))
|
||||
return TRUE
|
||||
to_chat(user, span_notice("\The [container] is full."))
|
||||
return FALSE
|
||||
|
||||
if(istype(attacking_item, /obj/item/melee/baton/security))
|
||||
var/obj/item/melee/baton/security/baton = attacking_item
|
||||
if(baton.cell?.charge && baton.active)
|
||||
flick("baton_active", src)
|
||||
user.Paralyze(baton.knockdown_time)
|
||||
user.set_stutter(baton.knockdown_time)
|
||||
baton.cell.use(baton.cell_hit_cost)
|
||||
user.visible_message(
|
||||
span_warning("[user] shocks [user.p_them()]self while attempting to wash the active [baton.name]!"),
|
||||
span_userdanger("You unwisely attempt to wash [baton] while it's still on."))
|
||||
playsound(src, baton.on_stun_sound, 50, TRUE)
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/mop))
|
||||
attacking_item.reagents.add_reagent(dispensedreagent, 5)
|
||||
to_chat(user, span_notice("You wet [attacking_item] in [src]."))
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/stack/medical/gauze))
|
||||
var/obj/item/stack/medical/gauze/G = attacking_item
|
||||
new /obj/item/reagent_containers/cup/rag(loc)
|
||||
to_chat(user, span_notice("You tear off a strip of gauze and make a rag."))
|
||||
G.use(1)
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/stack/sheet/cloth))
|
||||
var/obj/item/stack/sheet/cloth/cloth = attacking_item
|
||||
new /obj/item/reagent_containers/cup/rag(loc)
|
||||
to_chat(user, span_notice("You tear off a strip of cloth and make a rag."))
|
||||
cloth.use(1)
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/stack/ore/glass))
|
||||
new /obj/item/stack/sheet/sandblock(loc)
|
||||
to_chat(user, span_notice("You wet the sand and form it into a block."))
|
||||
attacking_item.use(1)
|
||||
return
|
||||
|
||||
if(!user.combat_mode)
|
||||
to_chat(user, span_notice("You start washing [attacking_item]..."))
|
||||
busy = TRUE
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return TRUE
|
||||
busy = FALSE
|
||||
attacking_item.wash(CLEAN_WASH)
|
||||
reagents.expose(attacking_item, TOUCH, 5 / max(reagents.total_volume, 5))
|
||||
user.visible_message(
|
||||
span_notice("[user] washes [attacking_item] using [src]."),
|
||||
span_notice("You wash [attacking_item] using [src]."))
|
||||
return TRUE
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/structure/water_source/puddle //splishy splashy ^_^
|
||||
name = "puddle"
|
||||
desc = "A puddle used for washing one's hands and face."
|
||||
icon_state = "puddle"
|
||||
base_icon_state = "puddle"
|
||||
resistance_flags = UNACIDABLE
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/structure/water_source/puddle/attack_hand(mob/user, list/modifiers)
|
||||
icon_state = "[base_icon_state]-splash"
|
||||
. = ..()
|
||||
icon_state = base_icon_state
|
||||
|
||||
/obj/structure/water_source/puddle/attackby(obj/item/attacking_item, mob/user, params)
|
||||
icon_state = "[base_icon_state]-splash"
|
||||
. = ..()
|
||||
icon_state = base_icon_state
|
||||
@@ -1,877 +0,0 @@
|
||||
/obj/structure/toilet
|
||||
name = "toilet"
|
||||
desc = "The HT-451, a torque rotation-based, waste disposal unit for small matter. This one seems remarkably clean."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "toilet00"
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
var/open = FALSE //if the lid is up
|
||||
var/cistern = 0 //if the cistern bit is open
|
||||
var/w_items = 0 //the combined w_class of all the items in the cistern
|
||||
var/mob/living/swirlie = null //the mob being given a swirlie
|
||||
var/buildstacktype = /obj/item/stack/sheet/iron //they're iron now, shut up
|
||||
var/buildstackamount = 1
|
||||
|
||||
/obj/structure/toilet/Initialize(mapload)
|
||||
. = ..()
|
||||
open = round(rand(0, 1))
|
||||
update_appearance()
|
||||
if(mapload && SSmapping.level_trait(z, ZTRAIT_STATION))
|
||||
AddElement(/datum/element/lazy_fishing_spot, /datum/fish_source/toilet)
|
||||
|
||||
/obj/structure/toilet/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(swirlie)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
playsound(src.loc, SFX_SWING_HIT, 25, TRUE)
|
||||
swirlie.visible_message(span_danger("[user] slams the toilet seat onto [swirlie]'s head!"), span_userdanger("[user] slams the toilet seat onto your head!"), span_hear("You hear reverberating porcelain."))
|
||||
log_combat(user, swirlie, "swirlied (brute)")
|
||||
swirlie.adjustBruteLoss(5)
|
||||
|
||||
else if(user.pulling && isliving(user.pulling))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
var/mob/living/GM = user.pulling
|
||||
if(user.grab_state >= GRAB_AGGRESSIVE)
|
||||
if(GM.loc != get_turf(src))
|
||||
to_chat(user, span_warning("[GM] needs to be on [src]!"))
|
||||
return
|
||||
if(!swirlie)
|
||||
if(open)
|
||||
GM.visible_message(span_danger("[user] starts to give [GM] a swirlie!"), span_userdanger("[user] starts to give you a swirlie..."))
|
||||
swirlie = GM
|
||||
var/was_alive = (swirlie.stat != DEAD)
|
||||
if(do_after(user, 3 SECONDS, target = src, timed_action_flags = IGNORE_HELD_ITEM))
|
||||
GM.visible_message(span_danger("[user] gives [GM] a swirlie!"), span_userdanger("[user] gives you a swirlie!"), span_hear("You hear a toilet flushing."))
|
||||
if(iscarbon(GM))
|
||||
var/mob/living/carbon/C = GM
|
||||
if(!C.internal)
|
||||
log_combat(user, C, "swirlied (oxy)")
|
||||
C.adjustOxyLoss(5)
|
||||
else
|
||||
log_combat(user, GM, "swirlied (oxy)")
|
||||
GM.adjustOxyLoss(5)
|
||||
if(was_alive && swirlie.stat == DEAD && swirlie.client)
|
||||
swirlie.client.give_award(/datum/award/achievement/misc/swirlie, swirlie) // just like space high school all over again!
|
||||
swirlie = null
|
||||
else
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 25, TRUE)
|
||||
GM.visible_message(span_danger("[user] slams [GM.name] into [src]!"), span_userdanger("[user] slams you into [src]!"))
|
||||
log_combat(user, GM, "toilet slammed")
|
||||
GM.adjustBruteLoss(5)
|
||||
else
|
||||
to_chat(user, span_warning("You need a tighter grip!"))
|
||||
|
||||
else if(cistern && !open && user.CanReach(src))
|
||||
if(!contents.len)
|
||||
to_chat(user, span_notice("The cistern is empty."))
|
||||
else
|
||||
var/obj/item/I = pick(contents)
|
||||
if(ishuman(user))
|
||||
user.put_in_hands(I)
|
||||
else
|
||||
I.forceMove(drop_location())
|
||||
to_chat(user, span_notice("You find [I] in the cistern."))
|
||||
w_items -= I.w_class
|
||||
else
|
||||
open = !open
|
||||
update_appearance()
|
||||
|
||||
|
||||
/obj/structure/toilet/update_icon_state()
|
||||
icon_state = "toilet[open][cistern]"
|
||||
return ..()
|
||||
|
||||
/obj/structure/toilet/atom_deconstruct(dissambled = TRUE)
|
||||
for(var/obj/toilet_item in contents)
|
||||
toilet_item.forceMove(drop_location())
|
||||
if(buildstacktype)
|
||||
new buildstacktype(loc,buildstackamount)
|
||||
else
|
||||
for(var/i in custom_materials)
|
||||
var/datum/material/M = i
|
||||
new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1))
|
||||
|
||||
/obj/structure/toilet/attackby(obj/item/I, mob/living/user, params)
|
||||
add_fingerprint(user)
|
||||
if(I.tool_behaviour == TOOL_CROWBAR)
|
||||
to_chat(user, span_notice("You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]..."))
|
||||
playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, TRUE)
|
||||
if(I.use_tool(src, user, 30))
|
||||
user.visible_message(span_notice("[user] [cistern ? "replaces the lid on the cistern" : "lifts the lid off the cistern"]!"), span_notice("You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!"), span_hear("You hear grinding porcelain."))
|
||||
cistern = !cistern
|
||||
update_appearance()
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
else if(I.tool_behaviour == TOOL_WRENCH)
|
||||
I.play_tool_sound(src)
|
||||
deconstruct()
|
||||
return TRUE
|
||||
else if(cistern && !user.combat_mode)
|
||||
if(I.w_class > WEIGHT_CLASS_NORMAL)
|
||||
to_chat(user, span_warning("[I] does not fit!"))
|
||||
return
|
||||
if(w_items + I.w_class > WEIGHT_CLASS_HUGE)
|
||||
to_chat(user, span_warning("The cistern is full!"))
|
||||
return
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
to_chat(user, span_warning("\The [I] is stuck to your hand, you cannot put it in the cistern!"))
|
||||
return
|
||||
w_items += I.w_class
|
||||
to_chat(user, span_notice("You carefully place [I] into the cistern."))
|
||||
return
|
||||
|
||||
if(is_reagent_container(I) && !user.combat_mode)
|
||||
if (!open)
|
||||
return
|
||||
if(istype(I, /obj/item/food/monkeycube))
|
||||
var/obj/item/food/monkeycube/cube = I
|
||||
cube.Expand()
|
||||
return
|
||||
var/obj/item/reagent_containers/RG = I
|
||||
RG.reagents.add_reagent(/datum/reagent/water, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
|
||||
to_chat(user, span_notice("You fill [RG] from [src]. Gross."))
|
||||
. = ..()
|
||||
|
||||
/obj/structure/toilet/secret
|
||||
var/obj/item/secret
|
||||
var/secret_type = null
|
||||
|
||||
/obj/structure/toilet/secret/Initialize(mapload)
|
||||
. = ..()
|
||||
if (secret_type)
|
||||
secret = new secret_type(src)
|
||||
secret.desc += " It's a secret!"
|
||||
w_items += secret.w_class
|
||||
contents += secret
|
||||
|
||||
/obj/structure/toilet/greyscale
|
||||
material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
|
||||
buildstacktype = null
|
||||
|
||||
/obj/structure/urinal
|
||||
name = "urinal"
|
||||
desc = "The HU-452, an experimental urinal. Comes complete with experimental urinal cake."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "urinal"
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
/// Can you currently put an item inside
|
||||
var/exposed = FALSE
|
||||
/// What's in the urinal
|
||||
var/obj/item/hidden_item
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32)
|
||||
|
||||
/obj/structure/urinal/Initialize(mapload)
|
||||
. = ..()
|
||||
hidden_item = new /obj/item/food/urinalcake
|
||||
find_and_hang_on_wall()
|
||||
|
||||
/obj/structure/urinal/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(user.pulling && isliving(user.pulling))
|
||||
var/mob/living/GM = user.pulling
|
||||
if(user.grab_state >= GRAB_AGGRESSIVE)
|
||||
if(GM.loc != get_turf(src))
|
||||
to_chat(user, span_notice("[GM.name] needs to be on [src]."))
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.visible_message(span_danger("[user] slams [GM] into [src]!"), span_danger("You slam [GM] into [src]!"))
|
||||
GM.adjustBruteLoss(8)
|
||||
else
|
||||
to_chat(user, span_warning("You need a tighter grip!"))
|
||||
|
||||
else if(exposed)
|
||||
if(!hidden_item)
|
||||
to_chat(user, span_warning("There is nothing in the drain holder!"))
|
||||
else
|
||||
if(ishuman(user))
|
||||
user.put_in_hands(hidden_item)
|
||||
else
|
||||
hidden_item.forceMove(get_turf(src))
|
||||
to_chat(user, span_notice("You fish [hidden_item] out of the drain enclosure."))
|
||||
hidden_item = null
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/structure/urinal/attackby(obj/item/I, mob/living/user, params)
|
||||
if(exposed)
|
||||
if (hidden_item)
|
||||
to_chat(user, span_warning("There is already something in the drain enclosure!"))
|
||||
return
|
||||
if(I.w_class > 1)
|
||||
to_chat(user, span_warning("[I] is too large for the drain enclosure."))
|
||||
return
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
to_chat(user, span_warning("[I] is stuck to your hand, you cannot put it in the drain enclosure!"))
|
||||
return
|
||||
hidden_item = I
|
||||
to_chat(user, span_notice("You place [I] into the drain enclosure."))
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/urinal/screwdriver_act(mob/living/user, obj/item/I)
|
||||
if(..())
|
||||
return TRUE
|
||||
to_chat(user, span_notice("You start to [exposed ? "screw the cap back into place" : "unscrew the cap to the drain protector"]..."))
|
||||
playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 50, TRUE)
|
||||
if(I.use_tool(src, user, 20))
|
||||
user.visible_message(span_notice("[user] [exposed ? "screws the cap back into place" : "unscrew the cap to the drain protector"]!"),
|
||||
span_notice("You [exposed ? "screw the cap back into place" : "unscrew the cap on the drain"]!"),
|
||||
span_hear("You hear metal and squishing noises."))
|
||||
exposed = !exposed
|
||||
return TRUE
|
||||
|
||||
/obj/structure/urinal/atom_deconstruct(disassembled = TRUE)
|
||||
new /obj/item/wallframe/urinal(loc)
|
||||
|
||||
/obj/item/wallframe/urinal
|
||||
name = "urinal frame"
|
||||
desc = "An unmounted urinal. Attach it to a wall to use."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "urinal"
|
||||
result_path = /obj/structure/urinal
|
||||
pixel_shift = 32
|
||||
|
||||
/obj/item/food/urinalcake
|
||||
name = "urinal cake"
|
||||
desc = "The noble urinal cake, protecting the station's pipes from the station's pee. Do not eat."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "urinalcake"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
food_reagents = list(
|
||||
/datum/reagent/chlorine = 3,
|
||||
/datum/reagent/ammonia = 1,
|
||||
)
|
||||
foodtypes = TOXIC | GROSS
|
||||
preserved_food = TRUE
|
||||
|
||||
/obj/item/food/urinalcake/attack_self(mob/living/user)
|
||||
user.visible_message(span_notice("[user] squishes [src]!"), span_notice("You squish [src]."), "<i>You hear a squish.</i>")
|
||||
icon_state = "urinalcake_squish"
|
||||
addtimer(VARSET_CALLBACK(src, icon_state, "urinalcake"), 0.8 SECONDS)
|
||||
|
||||
/obj/item/bikehorn/rubberducky/plasticducky
|
||||
name = "plastic ducky"
|
||||
desc = "It's a cheap plastic knockoff of a loveable bathtime toy."
|
||||
custom_materials = list(/datum/material/plastic =HALF_SHEET_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/item/bikehorn/rubberducky
|
||||
name = "rubber ducky"
|
||||
desc = "Rubber ducky you're so fine, you make bathtime lots of fuuun. Rubber ducky I'm awfully fooooond of yooooouuuu~" //thanks doohl
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "rubberducky"
|
||||
inhand_icon_state = "rubberducky"
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
worn_icon_state = "duck"
|
||||
sound_file = 'sound/effects/quack.ogg'
|
||||
|
||||
/obj/structure/sink
|
||||
name = "sink"
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "sink"
|
||||
desc = "A sink used for washing one's hands and face. Passively reclaims water over time."
|
||||
anchored = TRUE
|
||||
layer = ABOVE_OBJ_LAYER
|
||||
pixel_z = 1
|
||||
///Something's being washed at the moment
|
||||
var/busy = FALSE
|
||||
///What kind of reagent is produced by this sink by default? (We now have actual plumbing, Arcane, August 2020)
|
||||
var/dispensedreagent = /datum/reagent/water
|
||||
///Material to drop when broken or deconstructed.
|
||||
var/buildstacktype = /obj/item/stack/sheet/iron
|
||||
///Number of sheets of material to drop when broken or deconstructed.
|
||||
var/buildstackamount = 1
|
||||
///Does the sink have a water recycler to recollect it's water supply?
|
||||
var/has_water_reclaimer = TRUE
|
||||
///Units of water to reclaim per second
|
||||
var/reclaim_rate = 0.5
|
||||
///Amount of shift the pixel for placement
|
||||
var/pixel_shift = 14
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14))
|
||||
|
||||
/obj/structure/sink/Initialize(mapload, ndir = 0, has_water_reclaimer = null)
|
||||
. = ..()
|
||||
|
||||
if(ndir)
|
||||
dir = ndir
|
||||
|
||||
if(has_water_reclaimer != null)
|
||||
src.has_water_reclaimer = has_water_reclaimer
|
||||
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
pixel_x = 0
|
||||
pixel_y = -pixel_shift
|
||||
if(SOUTH)
|
||||
pixel_x = 0
|
||||
pixel_y = pixel_shift
|
||||
if(EAST)
|
||||
pixel_x = -pixel_shift
|
||||
pixel_y = 0
|
||||
if(WEST)
|
||||
pixel_x = pixel_shift
|
||||
pixel_y = 0
|
||||
|
||||
create_reagents(100, NO_REACT)
|
||||
if(src.has_water_reclaimer)
|
||||
reagents.add_reagent(dispensedreagent, 100)
|
||||
AddComponent(/datum/component/plumbing/simple_demand, extend_pipe_to_edge = TRUE)
|
||||
|
||||
/obj/structure/sink/examine(mob/user)
|
||||
. = ..()
|
||||
if(has_water_reclaimer)
|
||||
. += span_notice("A water recycler is installed. It looks like you could pry it out.")
|
||||
. += span_notice("[reagents.total_volume]/[reagents.maximum_volume] liquids remaining.")
|
||||
|
||||
/obj/structure/sink/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!user || !istype(user))
|
||||
return
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
if(reagents.total_volume < 5)
|
||||
to_chat(user, span_warning("The sink has no more contents left!"))
|
||||
return
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
var/selected_area = user.parse_zone_with_bodypart(user.zone_selected)
|
||||
var/washing_face = 0
|
||||
if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES))
|
||||
washing_face = 1
|
||||
user.visible_message(span_notice("[user] starts washing [user.p_their()] [washing_face ? "face" : "hands"]..."), \
|
||||
span_notice("You start washing your [washing_face ? "face" : "hands"]..."))
|
||||
busy = TRUE
|
||||
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return
|
||||
|
||||
busy = FALSE
|
||||
reagents.remove_all(5)
|
||||
reagents.expose(user, TOUCH, 5 / max(reagents.total_volume, 5))
|
||||
begin_reclamation()
|
||||
if(washing_face)
|
||||
SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_FACE_ACT, CLEAN_WASH)
|
||||
else if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
if(!human_user.wash_hands(CLEAN_WASH))
|
||||
to_chat(user, span_warning("Your hands are covered by something!"))
|
||||
return
|
||||
else
|
||||
user.wash(CLEAN_WASH)
|
||||
|
||||
user.visible_message(span_notice("[user] washes [user.p_their()] [washing_face ? "face" : "hands"] using [src]."), \
|
||||
span_notice("You wash your [washing_face ? "face" : "hands"] using [src]."))
|
||||
|
||||
/obj/structure/sink/attackby(obj/item/O, mob/living/user, params)
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
|
||||
if(is_reagent_container(O))
|
||||
var/obj/item/reagent_containers/RG = O
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(user, span_notice("\The [src] is dry."))
|
||||
return FALSE
|
||||
if(RG.is_refillable())
|
||||
if(!RG.reagents.holder_full())
|
||||
reagents.trans_to(RG, RG.amount_per_transfer_from_this, transferred_by = user)
|
||||
begin_reclamation()
|
||||
to_chat(user, span_notice("You fill [RG] from [src]."))
|
||||
return TRUE
|
||||
to_chat(user, span_notice("\The [RG] is full."))
|
||||
return FALSE
|
||||
|
||||
if(istype(O, /obj/item/melee/baton/security))
|
||||
var/obj/item/melee/baton/security/baton = O
|
||||
if(baton.cell?.charge && baton.active)
|
||||
flick("baton_active", src)
|
||||
user.Paralyze(baton.knockdown_time)
|
||||
user.set_stutter(baton.knockdown_time)
|
||||
baton.cell.use(baton.cell_hit_cost)
|
||||
user.visible_message(span_warning("[user] shocks [user.p_them()]self while attempting to wash the active [baton.name]!"), \
|
||||
span_userdanger("You unwisely attempt to wash [baton] while it's still on."))
|
||||
playsound(src, baton.on_stun_sound, 50, TRUE)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/mop))
|
||||
if(reagents.total_volume <= 0)
|
||||
to_chat(user, span_notice("\The [src] is dry."))
|
||||
return FALSE
|
||||
reagents.trans_to(O, 5, transferred_by = user)
|
||||
begin_reclamation()
|
||||
to_chat(user, span_notice("You wet [O] in [src]."))
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
|
||||
return
|
||||
|
||||
if(O.tool_behaviour == TOOL_WRENCH)
|
||||
O.play_tool_sound(src)
|
||||
deconstruct()
|
||||
return
|
||||
|
||||
if(O.tool_behaviour == TOOL_CROWBAR)
|
||||
if(!has_water_reclaimer)
|
||||
to_chat(user, span_warning("There isn't a water recycler to remove."))
|
||||
return
|
||||
|
||||
O.play_tool_sound(src)
|
||||
has_water_reclaimer = FALSE
|
||||
new/obj/item/stock_parts/water_recycler(get_turf(loc))
|
||||
to_chat(user, span_notice("You remove the water reclaimer from [src]"))
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/medical/gauze))
|
||||
var/obj/item/stack/medical/gauze/G = O
|
||||
new /obj/item/reagent_containers/cup/rag(src.loc)
|
||||
to_chat(user, span_notice("You tear off a strip of gauze and make a rag."))
|
||||
G.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/sheet/cloth))
|
||||
var/obj/item/stack/sheet/cloth/cloth = O
|
||||
new /obj/item/reagent_containers/cup/rag(loc)
|
||||
to_chat(user, span_notice("You tear off a strip of cloth and make a rag."))
|
||||
cloth.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/ore/glass))
|
||||
new /obj/item/stack/sheet/sandblock(loc)
|
||||
to_chat(user, span_notice("You wet the sand in the sink and form it into a block."))
|
||||
O.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stock_parts/water_recycler))
|
||||
if(has_water_reclaimer)
|
||||
to_chat(user, span_warning("There is already has a water recycler installed."))
|
||||
return
|
||||
|
||||
playsound(src, 'sound/machines/click.ogg', 20, TRUE)
|
||||
qdel(O)
|
||||
has_water_reclaimer = TRUE
|
||||
begin_reclamation()
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/storage/fancy/pickles_jar))
|
||||
if(O.contents.len)
|
||||
to_chat(user, span_notice("Looks like there's something left in the jar"))
|
||||
return
|
||||
new /obj/item/reagent_containers/cup/beaker/large(loc)
|
||||
to_chat(user, span_notice("You washed the jar, ridding it of the brine."))
|
||||
qdel(O)
|
||||
return
|
||||
|
||||
if(!istype(O))
|
||||
return
|
||||
if(O.item_flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand.
|
||||
return
|
||||
|
||||
if(!user.combat_mode)
|
||||
to_chat(user, span_notice("You start washing [O]..."))
|
||||
busy = TRUE
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return 1
|
||||
busy = FALSE
|
||||
O.wash(CLEAN_WASH)
|
||||
reagents.expose(O, TOUCH, 5 / max(reagents.total_volume, 5))
|
||||
user.visible_message(span_notice("[user] washes [O] using [src]."), \
|
||||
span_notice("You wash [O] using [src]."))
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/sink/atom_deconstruct(dissambled = TRUE)
|
||||
drop_materials()
|
||||
if(has_water_reclaimer)
|
||||
new /obj/item/stock_parts/water_recycler(drop_location())
|
||||
|
||||
/obj/structure/sink/process(seconds_per_tick)
|
||||
// Water reclamation complete?
|
||||
if(!has_water_reclaimer || reagents.total_volume >= reagents.maximum_volume)
|
||||
return PROCESS_KILL
|
||||
|
||||
reagents.add_reagent(dispensedreagent, reclaim_rate * seconds_per_tick)
|
||||
|
||||
/obj/structure/sink/proc/drop_materials()
|
||||
if(buildstacktype)
|
||||
new buildstacktype(loc,buildstackamount)
|
||||
else
|
||||
for(var/i in custom_materials)
|
||||
var/datum/material/M = i
|
||||
new M.sheet_type(loc, FLOOR(custom_materials[M] / SHEET_MATERIAL_AMOUNT, 1))
|
||||
|
||||
/obj/structure/sink/proc/begin_reclamation()
|
||||
START_PROCESSING(SSplumbing, src)
|
||||
|
||||
/obj/structure/sink/kitchen
|
||||
name = "kitchen sink"
|
||||
icon_state = "sink_alt"
|
||||
pixel_z = 4
|
||||
pixel_shift = 16
|
||||
|
||||
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink/kitchen, (-16))
|
||||
|
||||
/obj/structure/sink/greyscale
|
||||
icon_state = "sink_greyscale"
|
||||
material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
|
||||
buildstacktype = null
|
||||
|
||||
/obj/structure/sinkframe
|
||||
name = "sink frame"
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "sink_frame"
|
||||
desc = "A sink frame, that needs a water recycler to finish construction."
|
||||
anchored = FALSE
|
||||
material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS
|
||||
|
||||
/obj/structure/sinkframe/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/simple_rotation)
|
||||
|
||||
/obj/structure/sinkframe/attackby(obj/item/tool, mob/living/user, params)
|
||||
if(istype(tool, /obj/item/stock_parts/water_recycler))
|
||||
qdel(tool)
|
||||
var/obj/structure/sink/greyscale/new_sink = new(loc, REVERSE_DIR(dir), TRUE)
|
||||
new_sink.set_custom_materials(custom_materials)
|
||||
qdel(src)
|
||||
playsound(new_sink, 'sound/machines/click.ogg', 20, TRUE)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/sinkframe/wrench_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
var/obj/structure/sink/greyscale/new_sink = new(loc, REVERSE_DIR(dir), FALSE)
|
||||
new_sink.set_custom_materials(custom_materials)
|
||||
qdel(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/structure/sinkframe/wrench_act_secondary(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
tool.play_tool_sound(src)
|
||||
deconstruct()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/sinkframe/atom_deconstruct(dissambled = TRUE)
|
||||
drop_materials()
|
||||
|
||||
/obj/structure/sinkframe/proc/drop_materials()
|
||||
for(var/datum/material/material as anything in custom_materials)
|
||||
new material.sheet_type(loc, FLOOR(custom_materials[material] / SHEET_MATERIAL_AMOUNT, 1))
|
||||
return
|
||||
|
||||
//Water source, use the type water_source for unlimited water sources like classic sinks.
|
||||
/obj/structure/water_source
|
||||
name = "Water Source"
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "sink"
|
||||
desc = "A sink used for washing one's hands and face. This one seems to be infinite!"
|
||||
anchored = TRUE
|
||||
var/busy = FALSE //Something's being washed at the moment
|
||||
var/dispensedreagent = /datum/reagent/water // for whenever plumbing happens
|
||||
|
||||
/obj/structure/water_source/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
create_reagents(INFINITY, NO_REACT)
|
||||
reagents.add_reagent(dispensedreagent, INFINITY)
|
||||
|
||||
/obj/structure/water_source/attack_hand(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!iscarbon(user))
|
||||
return
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
var/selected_area = user.parse_zone_with_bodypart(user.zone_selected)
|
||||
var/washing_face = FALSE
|
||||
if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES))
|
||||
washing_face = TRUE
|
||||
user.visible_message(span_notice("[user] starts washing [user.p_their()] [washing_face ? "face" : "hands"]..."), \
|
||||
span_notice("You start washing your [washing_face ? "face" : "hands"]..."))
|
||||
busy = TRUE
|
||||
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return
|
||||
|
||||
busy = FALSE
|
||||
|
||||
if(washing_face)
|
||||
SEND_SIGNAL(user, COMSIG_COMPONENT_CLEAN_FACE_ACT, CLEAN_WASH)
|
||||
else if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
if(!human_user.wash_hands(CLEAN_WASH))
|
||||
to_chat(user, span_warning("Your hands are covered by something!"))
|
||||
return
|
||||
else
|
||||
user.wash(CLEAN_WASH)
|
||||
|
||||
user.visible_message(span_notice("[user] washes [user.p_their()] [washing_face ? "face" : "hands"] using [src]."), \
|
||||
span_notice("You wash your [washing_face ? "face" : "hands"] using [src]."))
|
||||
|
||||
/obj/structure/water_source/attackby(obj/item/O, mob/living/user, params)
|
||||
if(busy)
|
||||
to_chat(user, span_warning("Someone's already washing here!"))
|
||||
return
|
||||
|
||||
if(is_reagent_container(O))
|
||||
var/obj/item/reagent_containers/container = O
|
||||
if(container.is_refillable())
|
||||
if(!container.reagents.holder_full())
|
||||
container.reagents.add_reagent(dispensedreagent, min(container.volume - container.reagents.total_volume, container.amount_per_transfer_from_this))
|
||||
to_chat(user, span_notice("You fill [container] from [src]."))
|
||||
return TRUE
|
||||
to_chat(user, span_notice("\The [container] is full."))
|
||||
return FALSE
|
||||
|
||||
if(istype(O, /obj/item/melee/baton/security))
|
||||
var/obj/item/melee/baton/security/baton = O
|
||||
if(baton.cell?.charge && baton.active)
|
||||
flick("baton_active", src)
|
||||
user.Paralyze(baton.knockdown_time)
|
||||
user.set_stutter(baton.knockdown_time)
|
||||
baton.cell.use(baton.cell_hit_cost)
|
||||
user.visible_message(span_warning("[user] shocks [user.p_them()]self while attempting to wash the active [baton.name]!"), \
|
||||
span_userdanger("You unwisely attempt to wash [baton] while it's still on."))
|
||||
playsound(src, baton.on_stun_sound, 50, TRUE)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/mop))
|
||||
O.reagents.add_reagent(dispensedreagent, 5)
|
||||
to_chat(user, span_notice("You wet [O] in [src]."))
|
||||
playsound(loc, 'sound/effects/slosh.ogg', 25, TRUE)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/medical/gauze))
|
||||
var/obj/item/stack/medical/gauze/G = O
|
||||
new /obj/item/reagent_containers/cup/rag(loc)
|
||||
to_chat(user, span_notice("You tear off a strip of gauze and make a rag."))
|
||||
G.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/sheet/cloth))
|
||||
var/obj/item/stack/sheet/cloth/cloth = O
|
||||
new /obj/item/reagent_containers/cup/rag(loc)
|
||||
to_chat(user, span_notice("You tear off a strip of cloth and make a rag."))
|
||||
cloth.use(1)
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/stack/ore/glass))
|
||||
new /obj/item/stack/sheet/sandblock(loc)
|
||||
to_chat(user, span_notice("You wet the sand and form it into a block."))
|
||||
O.use(1)
|
||||
return
|
||||
|
||||
if(O.item_flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand.
|
||||
return
|
||||
|
||||
if(!user.combat_mode)
|
||||
to_chat(user, span_notice("You start washing [O]..."))
|
||||
busy = TRUE
|
||||
if(!do_after(user, 4 SECONDS, target = src))
|
||||
busy = FALSE
|
||||
return TRUE
|
||||
busy = FALSE
|
||||
O.wash(CLEAN_WASH)
|
||||
reagents.expose(O, TOUCH, 5 / max(reagents.total_volume, 5))
|
||||
user.visible_message(span_notice("[user] washes [O] using [src]."), \
|
||||
span_notice("You wash [O] using [src]."))
|
||||
return TRUE
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/water_source/puddle //splishy splashy ^_^
|
||||
name = "puddle"
|
||||
desc = "A puddle used for washing one's hands and face."
|
||||
icon_state = "puddle"
|
||||
resistance_flags = UNACIDABLE
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/structure/water_source/puddle/attack_hand(mob/user, list/modifiers)
|
||||
icon_state = "puddle-splash"
|
||||
. = ..()
|
||||
icon_state = "puddle"
|
||||
|
||||
/obj/structure/water_source/puddle/attackby(obj/item/O, mob/user, params)
|
||||
icon_state = "puddle-splash"
|
||||
. = ..()
|
||||
icon_state = "puddle"
|
||||
|
||||
//End legacy sink
|
||||
|
||||
|
||||
//Shower Curtains//
|
||||
//Defines used are pre-existing in layers.dm//
|
||||
|
||||
/obj/structure/curtain
|
||||
name = "curtain"
|
||||
desc = "Contains less than 1% mercury."
|
||||
icon = 'icons/obj/watercloset.dmi'
|
||||
icon_state = "bathroom-open"
|
||||
var/icon_type = "bathroom"//used in making the icon state
|
||||
color = "#ACD1E9" //Default color, didn't bother hardcoding other colors, mappers can and should easily change it.
|
||||
alpha = 200 //Mappers can also just set this to 255 if they want curtains that can't be seen through
|
||||
layer = SIGN_LAYER
|
||||
anchored = TRUE
|
||||
opacity = FALSE
|
||||
density = FALSE
|
||||
var/open = TRUE
|
||||
/// if it can be seen through when closed
|
||||
var/opaque_closed = FALSE
|
||||
|
||||
/obj/structure/curtain/Initialize(mapload)
|
||||
// see-through curtains should let emissives shine through
|
||||
if(!opaque_closed)
|
||||
blocks_emissive = EMISSIVE_BLOCK_NONE
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/proc/toggle()
|
||||
open = !open
|
||||
if(open)
|
||||
layer = SIGN_LAYER
|
||||
set_opacity(FALSE)
|
||||
else
|
||||
layer = WALL_OBJ_LAYER
|
||||
if(opaque_closed)
|
||||
set_opacity(TRUE)
|
||||
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/curtain/update_icon_state()
|
||||
icon_state = "[icon_type]-[open ? "open" : "closed"]"
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/attackby(obj/item/W, mob/user)
|
||||
if (istype(W, /obj/item/toy/crayon))
|
||||
color = input(user,"","Choose Color",color) as color
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/wrench_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
default_unfasten_wrench(user, tool, time = 5 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/curtain/wirecutter_act(mob/living/user, obj/item/I)
|
||||
..()
|
||||
if(anchored)
|
||||
return TRUE
|
||||
|
||||
user.visible_message(span_warning("[user] cuts apart [src]."),
|
||||
span_notice("You start to cut apart [src]."), span_hear("You hear cutting."))
|
||||
if(I.use_tool(src, user, 50, volume=100) && !anchored)
|
||||
to_chat(user, span_notice("You cut apart [src]."))
|
||||
deconstruct()
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/structure/curtain/attack_hand(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
playsound(loc, 'sound/effects/curtain.ogg', 50, TRUE)
|
||||
toggle()
|
||||
|
||||
/obj/structure/curtain/atom_deconstruct(disassembled = TRUE)
|
||||
new /obj/item/stack/sheet/cloth (loc, 2)
|
||||
new /obj/item/stack/sheet/plastic (loc, 2)
|
||||
new /obj/item/stack/rods (loc, 1)
|
||||
|
||||
/obj/structure/curtain/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(damage_amount)
|
||||
playsound(src.loc, 'sound/weapons/slash.ogg', 80, TRUE)
|
||||
else
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, TRUE)
|
||||
if(BURN)
|
||||
playsound(loc, 'sound/items/welder.ogg', 80, TRUE)
|
||||
|
||||
/obj/structure/curtain/bounty
|
||||
icon_type = "bounty"
|
||||
icon_state = "bounty-open"
|
||||
color = null
|
||||
alpha = 255
|
||||
opaque_closed = TRUE
|
||||
|
||||
/obj/structure/curtain/bounty/start_closed
|
||||
icon_state = "bounty-closed"
|
||||
|
||||
/obj/structure/curtain/bounty/start_closed/Initialize(mapload)
|
||||
. = ..()
|
||||
if(open)
|
||||
toggle()
|
||||
|
||||
/obj/structure/curtain/cloth
|
||||
color = null
|
||||
alpha = 255
|
||||
opaque_closed = TRUE
|
||||
|
||||
/obj/structure/curtain/cloth/atom_deconstruct(disassembled = TRUE)
|
||||
new /obj/item/stack/sheet/cloth (loc, 4)
|
||||
new /obj/item/stack/rods (loc, 1)
|
||||
|
||||
/obj/structure/curtain/cloth/fancy
|
||||
icon_type = "cur_fancy"
|
||||
icon_state = "cur_fancy-open"
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical
|
||||
var/id = null
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/Destroy()
|
||||
GLOB.curtains -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/Initialize(mapload)
|
||||
. = ..()
|
||||
GLOB.curtains += src
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
||||
id = "[port.shuttle_id]_[id]"
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/proc/open()
|
||||
icon_state = "[icon_type]-open"
|
||||
layer = SIGN_LAYER
|
||||
SET_PLANE_IMPLICIT(src, GAME_PLANE)
|
||||
set_density(FALSE)
|
||||
open = TRUE
|
||||
set_opacity(FALSE)
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/proc/close()
|
||||
icon_state = "[icon_type]-closed"
|
||||
layer = WALL_OBJ_LAYER
|
||||
set_density(TRUE)
|
||||
open = FALSE
|
||||
if(opaque_closed)
|
||||
set_opacity(TRUE)
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/attack_hand(mob/user, list/modifiers)
|
||||
return
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/start_closed
|
||||
icon_state = "cur_fancy-closed"
|
||||
|
||||
/obj/structure/curtain/cloth/fancy/mechanical/start_closed/Initialize(mapload)
|
||||
. = ..()
|
||||
close()
|
||||
@@ -665,7 +665,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw
|
||||
anchored = FALSE
|
||||
|
||||
/obj/structure/window/plasma/fulltile
|
||||
icon = 'icons/obj/smooth_structures/plasma_window.dmi' //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon = 'icons/obj/smooth_structures/plasma_window.dmi' //ICON OVERRIDDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
icon_state = "plasma_window-0"
|
||||
base_icon_state = "plasma_window"
|
||||
max_integrity = 400
|
||||
|
||||
Reference in New Issue
Block a user