Files
Bubberstation/code/game/objects/structures/bedsheet_bin.dm
LemonInTheDark 23bfdec8f4 Multiz Rework: Human Suffering Edition (Contains PLANE CUBE) (#69115)
About The Pull Request

I've reworked multiz. This was done because our current implementation of multiz flattens planes down into just the openspace plane. This breaks any effects we attach to plane masters (including lighting), but it also totally kills the SIDE_MAP map format, which we NEED for wallening (A major 3/4ths resprite of all wall and wall adjacent things, making them more then one tile high. Without sidemap we would be unable to display things both in from of and behind objects on map. Stupid.)

This required MASSIVE changes. Both to all uses of the plane var for reasons I'll discuss later, and to a ton of different systems that interact with rendering.

I'll do my best to keep this compact, but there's only so much I can do. Sorry brother.
Core idea

OK: first thing.
vis_contents as it works now squishes the planes of everything inside it down into the plane of the vis_loc.
This is bad. But how to do better?

It's trivially easy to make copies of our existing plane masters but offset, and relay them to the bottom of the plane above. Not a problem. The issue is how to get the actual atoms on the map to "land" on them properly.

We could use FLOAT_PLANE to offset planes based off how they're being seen, in theory this would allow us to create lens for how objects are viewed.
But that's not a stable thing to do, because properly "landing" a plane on a desired plane master would require taking into account every bit of how it's being seen, would inherently break this effect.

Ok so we need to manually edit planes based off "z layer" (IE: what layer of a z stack are you on).

That's the key conceit of this pr. Implementing the plane cube, and ensuring planes are always offset properly.
Everything else is just gravy.
About the Plane Cube

Each plane master (except ones that opt out) is copied down by some constant value equal to the max absolute change between the first and the last plane.
We do this based off the max z stack size detected by SSmapping. This is also where updates come from, and where all our updating logic will live.

As mentioned, plane masters can choose to opt out of being mirrored down. In this case, anything that interacts with them assuming that they'll be offset will instead just get back the valid plane value. This works for render targets too, since I had to work them into the system as well.

Plane masters can also be temporarily hidden from the client's screen. This is done as an attempt at optimization, and applies to anything used in niche cases, or planes only used if there's a z layer below you.
About Plane Master Groups

BYOND supports having different "maps" on screen at once (IE: groups of items/turfs/etc)
Plane masters cannot cover 2 maps at once, since their location is determined by their screen_loc.
So we need to maintain a mirror of each plane for every map we have open.

This was quite messy, so I've refactored it (and maps too) to be a bit more modular.

Rather then storing a list of plane masters, we store a list of plane master group datums.
Each datum is in charge of the plane masters for its particular map, both creating them, and managing them.

Like I mentioned, I also refactored map views. Adding a new mapview is now as simple as newing a /atom/movable/screen/map_view, calling generate_view with the appropriate map id, setting things you want to display in its vis_contents, and then calling display_to on it, passing in the mob to show ourselves to.

Much better then the hardcoded pattern we used to use. So much duplicated code man.

Oh and plane master controllers, that system we have that allows for applying filters to sets of plane masters? I've made it use lookups on plane master groups now, rather then hanging references to all impacted planes. This makes logic easier, and prevents the need to manage references and update the controllers.

image

In addition, I've added a debug ui for plane masters.
It allows you to view all of your own plane masters and short descriptions of what they do, alongside tools for editing them and their relays.

It ALSO supports editing someone elses plane masters, AND it supports (in a very fragile and incomplete manner) viewing literally through someone else's eyes, including their plane masters. This is very useful, because it means you can debug "hey my X is yorked" issues yourself, on live.

In order to accomplish this I have needed to add setters for an ungodly amount of visual impacting vars. Sight flags, eye, see_invis, see_in_dark, etc.

It also comes with an info dump about the ui, and plane masters/relays in general.

Sort of on that note. I've documented everything I know that's niche/useful about our visual effects and rendering system. My hope is this will serve to bring people up to speed on what can be done more quickly, alongside making my sin here less horrible.
See https://github.com/LemonInTheDark/tgstation/blob/multiz-hell/.github/guides/VISUALS.md.
"Landing" planes

Ok so I've explained the backend, but how do we actually land planes properly?
Most of the time this is really simple. When a plane var is set, we need to provide some spokesperson for the appearance's z level. We can use this to derive their z layer, and thus what offset to use.

This is just a lot of gruntwork, but it's occasionally more complex.
Sometimes we need to cache a list of z layer -> effect, and then use that.
Also a LOT of updating on z move. So much z move shit.

Oh. and in order to make byond darkness work properly, I needed to add SEE_BLACKNESS to all sight flags.
This draws darkness to plane 0, which means I'm able to relay it around and draw it on different z layers as is possible. fun darkness ripple effects incoming someday

I also need to update mob overlays on move.
I do this by realiizing their appearances, mutating their plane, and then readding the overlay in the correct order.

The cost of this is currently 3N. I'm convinced this could be improved, but I've not got to it yet.
It can also occasionally cause overlays to corrupt. This is fixed by laying a protective ward of overlays.Copy in the sand, but that spell makes the compiler confused, so I'll have to bully lummy about fixing it at some point.
Behavior changes

We've had to give up on the already broken gateway "see through" effect. Won't work without managing gateway plane masters or something stupid. Not worth it.
So instead we display the other side as a ui element. It's worse, but not that bad.

Because vis_contents no longer flattens planes (most of the time), some uses of it now have interesting behavior.
The main thing that comes to mind is alert popups that display mobs. They can impact the lighting plane.
I don't really care, but it should be fixable, I think, given elbow grease.

Ah and I've cleaned up layers and plane defines to make them a bit easier to read/reason about, at least I think.
Why It's Good For The Game
<visual candy>

Fixes #65800
Fixes #68461
Changelog

cl
refactor: Refactored... well a lot really. Map views, anything to do with planes, multiz, a shit ton of rendering stuff. Basically if you see anything off visually report it
admin: VV a mob, and hit View/Edit Planes in the dropdown to steal their view, and modify it as you like. You can do the same to yourself using the Edit/Debug Planes verb
/cl
2022-09-27 20:11:04 +13:00

650 lines
20 KiB
Plaintext

/*
CONTAINS:
BEDSHEETS
LINEN BINS
*/
#define BEDSHEET_ABSTRACT "abstract"
#define BEDSHEET_SINGLE "single"
#define BEDSHEET_DOUBLE "double"
/obj/item/bedsheet
name = "bedsheet"
desc = "A surprisingly soft linen bedsheet."
icon = 'icons/obj/bedsheets.dmi'
lefthand_file = 'icons/mob/inhands/items/bedsheet_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/bedsheet_righthand.dmi'
icon_state = "sheetwhite"
inhand_icon_state = "sheetwhite"
slot_flags = ITEM_SLOT_NECK
layer = BELOW_MOB_LAYER
throwforce = 0
throw_speed = 1
throw_range = 2
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
dying_key = DYE_REGISTRY_BEDSHEET
dog_fashion = /datum/dog_fashion/head/ghost
var/list/dream_messages = list("white")
var/stack_amount = 3
var/bedsheet_type = BEDSHEET_SINGLE
/obj/item/bedsheet/Initialize(mapload)
. = ..()
AddComponent(/datum/component/surgery_initiator)
AddElement(/datum/element/bed_tuckable, 0, 0, 0)
if(bedsheet_type == BEDSHEET_DOUBLE)
stack_amount *= 2
dying_key = DYE_REGISTRY_DOUBLE_BEDSHEET
/obj/item/bedsheet/attack_self(mob/living/user)
if(!user.CanReach(src)) //No telekenetic grabbing.
return
if(!user.dropItemToGround(src))
return
if(layer == initial(layer))
layer = ABOVE_MOB_LAYER
SET_PLANE_IMPLICIT(src, GAME_PLANE_UPPER)
to_chat(user, span_notice("You cover yourself with [src]."))
pixel_x = 0
pixel_y = 0
else
layer = initial(layer)
SET_PLANE_IMPLICIT(src, initial(plane))
to_chat(user, span_notice("You smooth [src] out beneath you."))
if(user.body_position == LYING_DOWN) //The player isn't laying down currently
dir = user.dir
else
if(user.dir & WEST) //The player is rotated to the right, lay the sheet left!
dir = WEST
else //The player is rotated to the left, lay the sheet right!
dir = EAST
add_fingerprint(user)
return
/obj/item/bedsheet/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_WIRECUTTER || I.get_sharpness())
if (!(flags_1 & HOLOGRAM_1))
var/obj/item/stack/sheet/cloth/shreds = new (get_turf(src), stack_amount)
if(!QDELETED(shreds)) //stacks merged
transfer_fingerprints_to(shreds)
shreds.add_fingerprint(user)
qdel(src)
to_chat(user, span_notice("You tear [src] up."))
else
return ..()
/obj/item/bedsheet/blue
icon_state = "sheetblue"
inhand_icon_state = "sheetblue"
dream_messages = list("blue")
/obj/item/bedsheet/green
icon_state = "sheetgreen"
inhand_icon_state = "sheetgreen"
dream_messages = list("green")
/obj/item/bedsheet/grey
icon_state = "sheetgrey"
inhand_icon_state = "sheetgrey"
dream_messages = list("grey")
/obj/item/bedsheet/orange
icon_state = "sheetorange"
inhand_icon_state = "sheetorange"
dream_messages = list("orange")
/obj/item/bedsheet/purple
icon_state = "sheetpurple"
inhand_icon_state = "sheetpurple"
dream_messages = list("purple")
/obj/item/bedsheet/patriot
name = "patriotic bedsheet"
desc = "You've never felt more free than when sleeping on this."
icon_state = "sheetUSA"
inhand_icon_state = "sheetUSA"
dream_messages = list("America", "freedom", "fireworks", "bald eagles")
/obj/item/bedsheet/rainbow
name = "rainbow bedsheet"
desc = "A multicolored blanket. It's actually several different sheets cut up and sewn together."
icon_state = "sheetrainbow"
inhand_icon_state = "sheetrainbow"
dream_messages = list("red", "orange", "yellow", "green", "blue", "purple", "a rainbow")
/obj/item/bedsheet/red
icon_state = "sheetred"
inhand_icon_state = "sheetred"
dream_messages = list("red")
/obj/item/bedsheet/yellow
icon_state = "sheetyellow"
inhand_icon_state = "sheetyellow"
dream_messages = list("yellow")
/obj/item/bedsheet/mime
name = "mime's blanket"
desc = "A very soothing striped blanket. All the noise just seems to fade out when you're under the covers in this."
icon_state = "sheetmime"
inhand_icon_state = "sheetmime"
dream_messages = list("silence", "gestures", "a pale face", "a gaping mouth", "the mime")
/obj/item/bedsheet/clown
name = "clown's blanket"
desc = "A rainbow blanket with a clown mask woven in. It smells faintly of bananas."
icon_state = "sheetclown"
inhand_icon_state = "sheetrainbow"
dream_messages = list("honk", "laughter", "a prank", "a joke", "a smiling face", "the clown")
/obj/item/bedsheet/captain
name = "captain's bedsheet"
desc = "It has a Nanotrasen symbol on it, and was woven with a revolutionary new kind of thread guaranteed to have 0.01% permeability for most non-chemical substances, popular among most modern captains."
icon_state = "sheetcaptain"
inhand_icon_state = "sheetcaptain"
dream_messages = list("authority", "a golden ID", "sunglasses", "a green disc", "an antique gun", "the captain")
/obj/item/bedsheet/rd
name = "research director's bedsheet"
desc = "It appears to have a beaker emblem, and is made out of fire-resistant material, although it probably won't protect you in the event of fires you're familiar with every day."
icon_state = "sheetrd"
inhand_icon_state = "sheetrd"
dream_messages = list("authority", "a silvery ID", "a bomb", "a mech", "a facehugger", "maniacal laughter", "the research director")
// for Free Golems.
/obj/item/bedsheet/rd/royal_cape
name = "Royal Cape of the Liberator"
desc = "Majestic."
dream_messages = list("mining", "stone", "a golem", "freedom", "doing whatever")
/obj/item/bedsheet/medical
name = "medical blanket"
desc = "It's a sterilized* blanket commonly used in the Medbay. *Sterilization is voided if a virologist is present onboard the station."
icon_state = "sheetmedical"
inhand_icon_state = "sheetmedical"
dream_messages = list("healing", "life", "surgery", "a doctor")
/obj/item/bedsheet/cmo
name = "chief medical officer's bedsheet"
desc = "It's a sterilized blanket that has a cross emblem. There's some cat fur on it, likely from Runtime."
icon_state = "sheetcmo"
inhand_icon_state = "sheetcmo"
dream_messages = list("authority", "a silvery ID", "healing", "life", "surgery", "a cat", "the chief medical officer")
/obj/item/bedsheet/hos
name = "head of security's bedsheet"
desc = "It is decorated with a shield emblem. While crime doesn't sleep, you do, but you are still THE LAW!"
icon_state = "sheethos"
inhand_icon_state = "sheethos"
dream_messages = list("authority", "a silvery ID", "handcuffs", "a baton", "a flashbang", "sunglasses", "the head of security")
/obj/item/bedsheet/hop
name = "head of personnel's bedsheet"
desc = "It is decorated with a key emblem. For those rare moments when you can rest and cuddle with Ian without someone screaming for you over the radio."
icon_state = "sheethop"
inhand_icon_state = "sheethop"
dream_messages = list("authority", "a silvery ID", "obligation", "a computer", "an ID", "a corgi", "the head of personnel")
/obj/item/bedsheet/ce
name = "chief engineer's bedsheet"
desc = "It is decorated with a wrench emblem. It's highly reflective and stain resistant, so you don't need to worry about ruining it with oil."
icon_state = "sheetce"
inhand_icon_state = "sheetce"
dream_messages = list("authority", "a silvery ID", "the engine", "power tools", "an APC", "a parrot", "the chief engineer")
/obj/item/bedsheet/qm
name = "quartermaster's bedsheet"
desc = "It is decorated with a crate emblem in silver lining. It's rather tough, and just the thing to lie on after a hard day of pushing paper."
icon_state = "sheetqm"
inhand_icon_state = "sheetqm"
dream_messages = list("authority", "a silvery ID", "a shuttle", "a crate", "a sloth", "the quartermaster")
/obj/item/bedsheet/chaplain
name = "chaplain's blanket"
desc = "A blanket woven with the hearts of gods themselves... Wait, that's just linen."
icon_state = "sheetchap"
inhand_icon_state = "sheetchap"
dream_messages = list("a grey ID", "the gods", "a fulfilled prayer", "a cult", "the chaplain")
/obj/item/bedsheet/brown
icon_state = "sheetbrown"
inhand_icon_state = "sheetbrown"
dream_messages = list("brown")
/obj/item/bedsheet/black
icon_state = "sheetblack"
inhand_icon_state = "sheetblack"
dream_messages = list("black")
/obj/item/bedsheet/centcom
name = "\improper CentCom bedsheet"
desc = "Woven with advanced nanothread for warmth as well as being very decorated, essential for all officials."
icon_state = "sheetcentcom"
inhand_icon_state = "sheetcentcom"
dream_messages = list("a unique ID", "authority", "artillery", "an ending")
/obj/item/bedsheet/syndie
name = "syndicate bedsheet"
desc = "It has a syndicate emblem and it has an aura of evil."
icon_state = "sheetsyndie"
inhand_icon_state = "sheetsyndie"
dream_messages = list("a green disc", "a red crystal", "a glowing blade", "a wire-covered ID")
/obj/item/bedsheet/cult
name = "cultist's bedsheet"
desc = "You might dream of Nar'Sie if you sleep with this. It seems rather tattered and glows of an eldritch presence."
icon_state = "sheetcult"
inhand_icon_state = "sheetcult"
dream_messages = list("a tome", "a floating red crystal", "a glowing sword", "a bloody symbol", "a massive humanoid figure")
/obj/item/bedsheet/wiz
name = "wizard's bedsheet"
desc = "A special fabric enchanted with magic so you can have an enchanted night. It even glows!"
icon_state = "sheetwiz"
inhand_icon_state = "sheetwiz"
dream_messages = list("a book", "an explosion", "lightning", "a staff", "a skeleton", "a robe", "magic")
/obj/item/bedsheet/nanotrasen
name = "\improper Nanotrasen bedsheet"
desc = "It has the Nanotrasen logo on it and has an aura of duty."
icon_state = "sheetNT"
inhand_icon_state = "sheetNT"
dream_messages = list("authority", "an ending")
/obj/item/bedsheet/ian
icon_state = "sheetian"
inhand_icon_state = "sheetian"
dream_messages = list("a dog", "a corgi", "woof", "bark", "arf")
/obj/item/bedsheet/cosmos
name = "cosmic space bedsheet"
desc = "Made from the dreams of those who wonder at the stars."
icon_state = "sheetcosmos"
inhand_icon_state = "sheetcosmos"
dream_messages = list("the infinite cosmos", "Hans Zimmer music", "a flight through space", "the galaxy", "being fabulous", "shooting stars")
light_power = 2
light_range = 1.4
/obj/item/bedsheet/random
icon_state = "random_bedsheet"
name = "random bedsheet"
desc = "If you're reading this description ingame, something has gone wrong! Honk!"
bedsheet_type = BEDSHEET_ABSTRACT
var/static/list/bedsheet_list
var/spawn_type = BEDSHEET_SINGLE
/obj/item/bedsheet/random/Initialize(mapload)
..()
if(!LAZYACCESS(bedsheet_list, spawn_type))
var/list/spawn_list = list()
var/list/possible_types = typesof(/obj/item/bedsheet)
for(var/obj/item/bedsheet/sheet as anything in possible_types)
if(initial(sheet.bedsheet_type) == spawn_type)
spawn_list += sheet
LAZYSET(bedsheet_list, spawn_type, spawn_list)
var/chosen_type = pick(bedsheet_list[spawn_type])
new chosen_type(loc)
return INITIALIZE_HINT_QDEL
/obj/item/bedsheet/random/double
icon_state = "random_bedsheet"
spawn_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/dorms
icon_state = "random_bedsheet"
name = "random dorms bedsheet"
desc = "If you're reading this description ingame, something has gone wrong! Honk!"
bedsheet_type = BEDSHEET_DOUBLE
slot_flags = null
/obj/item/bedsheet/dorms/Initialize(mapload)
..()
var/type = pick_weight(list("Colors" = 80, "Special" = 20))
switch(type)
if("Colors")
type = pick(list(/obj/item/bedsheet,
/obj/item/bedsheet/blue,
/obj/item/bedsheet/green,
/obj/item/bedsheet/grey,
/obj/item/bedsheet/orange,
/obj/item/bedsheet/purple,
/obj/item/bedsheet/red,
/obj/item/bedsheet/yellow,
/obj/item/bedsheet/brown,
/obj/item/bedsheet/black))
if("Special")
type = pick(list(/obj/item/bedsheet/patriot,
/obj/item/bedsheet/rainbow,
/obj/item/bedsheet/ian,
/obj/item/bedsheet/cosmos,
/obj/item/bedsheet/nanotrasen))
var/obj/item/bedsheet = new type(loc)
bedsheet.dir = dir
return INITIALIZE_HINT_QDEL
/obj/item/bedsheet/double
icon_state = "double_sheetwhite"
worn_icon_state = "sheetwhite"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/blue/double
icon_state = "double_sheetblue"
worn_icon_state = "sheetblue"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/green/double
icon_state = "double_sheetgreen"
worn_icon_state = "sheetgreen"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/grey/double
icon_state = "double_sheetgrey"
worn_icon_state = "sheetgrey"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/orange/double
icon_state = "double_sheetorange"
worn_icon_state = "sheetorange"
dying_key = DYE_REGISTRY_DOUBLE_BEDSHEET
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/purple/double
icon_state = "double_sheetpurple"
worn_icon_state = "sheetpurple"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/patriot/double
icon_state = "double_sheetUSA"
worn_icon_state = "sheetUSA"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/rainbow/double
icon_state = "double_sheetrainbow"
worn_icon_state = "sheetrainbow"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/red/double
icon_state = "double_sheetred"
worn_icon_state = "sheetred"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/yellow/double
icon_state = "double_sheetyellow"
worn_icon_state = "sheetyellow"
dying_key = DYE_REGISTRY_DOUBLE_BEDSHEET
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/mime/double
icon_state = "double_sheetmime"
worn_icon_state = "sheetmime"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/clown/double
icon_state = "double_sheetclown"
worn_icon_state = "sheetclown"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/captain/double
icon_state = "double_sheetcaptain"
worn_icon_state = "sheetcaptain"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/rd/double
icon_state = "double_sheetrd"
worn_icon_state = "sheetrd"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/medical/double
icon_state = "double_sheetmedical"
worn_icon_state = "sheetmedical"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/cmo/double
icon_state = "double_sheetcmo"
worn_icon_state = "sheetcmo"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/hos/double
icon_state = "double_sheethos"
worn_icon_state = "sheethos"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/hop/double
icon_state = "double_sheethop"
worn_icon_state = "sheethop"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/ce/double
icon_state = "double_sheetce"
worn_icon_state = "sheetce"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/qm/double
icon_state = "double_sheetqm"
worn_icon_state = "sheetqm"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/chaplain/double
icon_state = "double_sheetchap"
worn_icon_state = "sheetchap"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/brown/double
icon_state = "double_sheetbrown"
worn_icon_state = "sheetbrown"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/black/double
icon_state = "double_sheetblack"
worn_icon_state = "sheetblack"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/centcom/double
icon_state = "double_sheetcentcom"
worn_icon_state = "sheetcentcom"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/syndie/double
icon_state = "double_sheetsyndie"
worn_icon_state = "sheetsyndie"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/cult/double
icon_state = "double_sheetcult"
worn_icon_state = "sheetcult"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/wiz/double
icon_state = "double_sheetwiz"
worn_icon_state = "sheetwiz"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/nanotrasen/double
icon_state = "double_sheetNT"
worn_icon_state = "sheetNT"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/ian/double
icon_state = "double_sheetian"
worn_icon_state = "sheetian"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/cosmos/double
icon_state = "double_sheetcosmos"
worn_icon_state = "sheetcosmos"
bedsheet_type = BEDSHEET_DOUBLE
/obj/item/bedsheet/dorms_double
icon_state = "random_bedsheet"
bedsheet_type = BEDSHEET_ABSTRACT
/obj/item/bedsheet/dorms_double/Initialize(mapload)
..()
var/type = pick_weight(list("Colors" = 80, "Special" = 20))
switch(type)
if("Colors")
type = pick(list(
/obj/item/bedsheet/double,
/obj/item/bedsheet/blue/double,
/obj/item/bedsheet/green/double,
/obj/item/bedsheet/grey/double,
/obj/item/bedsheet/orange/double,
/obj/item/bedsheet/purple/double,
/obj/item/bedsheet/red/double,
/obj/item/bedsheet/yellow/double,
/obj/item/bedsheet/brown/double,
/obj/item/bedsheet/black/double,
))
if("Special")
type = pick(list(
/obj/item/bedsheet/patriot/double,
/obj/item/bedsheet/rainbow/double,
/obj/item/bedsheet/ian/double,
/obj/item/bedsheet/cosmos/double,
/obj/item/bedsheet/nanotrasen/double,
))
var/obj/item/bedsheet = new type(loc)
bedsheet.dir = dir
return INITIALIZE_HINT_QDEL
/obj/structure/bedsheetbin
name = "linen bin"
desc = "It looks rather cosy."
icon = 'icons/obj/structures.dmi'
icon_state = "linenbin-full"
anchored = TRUE
resistance_flags = FLAMMABLE
max_integrity = 70
var/amount = 10
var/list/sheets = list()
var/obj/item/hidden = null
/obj/structure/bedsheetbin/empty
amount = 0
icon_state = "linenbin-empty"
anchored = FALSE
/obj/structure/bedsheetbin/examine(mob/user)
. = ..()
if(amount < 1)
. += "There are no bed sheets in the bin."
else if(amount == 1)
. += "There is one bed sheet in the bin."
else
. += "There are [amount] bed sheets in the bin."
/obj/structure/bedsheetbin/update_icon_state()
switch(amount)
if(0)
icon_state = "linenbin-empty"
if(1 to 5)
icon_state = "linenbin-half"
else
icon_state = "linenbin-full"
return ..()
/obj/structure/bedsheetbin/fire_act(exposed_temperature, exposed_volume)
if(amount)
amount = 0
update_appearance()
..()
/obj/structure/bedsheetbin/screwdriver_act(mob/living/user, obj/item/tool)
if(flags_1 & NODECONSTRUCT_1)
return FALSE
if(amount)
to_chat(user, span_warning("The [src] must be empty first!"))
return TOOL_ACT_TOOLTYPE_SUCCESS
if(tool.use_tool(src, user, 0.5 SECONDS, volume=50))
to_chat(user, span_notice("You disassemble the [src]."))
new /obj/item/stack/rods(loc, 2)
qdel(src)
return TOOL_ACT_TOOLTYPE_SUCCESS
/obj/structure/bedsheetbin/wrench_act(mob/living/user, obj/item/tool)
. = ..()
default_unfasten_wrench(user, tool, time = 0.5 SECONDS)
return TOOL_ACT_TOOLTYPE_SUCCESS
/obj/structure/bedsheetbin/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/bedsheet))
if(!user.transferItemToLoc(I, src))
return
sheets.Add(I)
amount++
to_chat(user, span_notice("You put [I] in [src]."))
update_appearance()
else if(amount && !hidden && I.w_class < WEIGHT_CLASS_BULKY) //make sure there's sheets to hide it among, make sure nothing else is hidden in there.
if(!user.transferItemToLoc(I, src))
to_chat(user, span_warning("\The [I] is stuck to your hand, you cannot hide it among the sheets!"))
return
hidden = I
to_chat(user, span_notice("You hide [I] among the sheets."))
/obj/structure/bedsheetbin/attack_paw(mob/user, list/modifiers)
return attack_hand(user, modifiers)
/obj/structure/bedsheetbin/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
if(isliving(user))
var/mob/living/L = user
if(!(L.mobility_flags & MOBILITY_PICKUP))
return
if(amount >= 1)
amount--
var/obj/item/bedsheet/B
if(sheets.len > 0)
B = sheets[sheets.len]
sheets.Remove(B)
else
B = new /obj/item/bedsheet(loc)
B.forceMove(drop_location())
user.put_in_hands(B)
to_chat(user, span_notice("You take [B] out of [src]."))
update_appearance()
if(hidden)
hidden.forceMove(drop_location())
to_chat(user, span_notice("[hidden] falls out of [B]!"))
hidden = null
add_fingerprint(user)
/obj/structure/bedsheetbin/attack_tk(mob/user)
if(amount >= 1)
amount--
var/obj/item/bedsheet/B
if(sheets.len > 0)
B = sheets[sheets.len]
sheets.Remove(B)
else
B = new /obj/item/bedsheet(loc)
B.forceMove(drop_location())
to_chat(user, span_notice("You telekinetically remove [B] from [src]."))
update_appearance()
if(hidden)
hidden.forceMove(drop_location())
hidden = null
add_fingerprint(user)
return COMPONENT_CANCEL_ATTACK_CHAIN
#undef BEDSHEET_ABSTRACT
#undef BEDSHEET_SINGLE
#undef BEDSHEET_DOUBLE