/* Tents */ /datum/large_structure/tent stages = list("poles" = STAGE_DISASSEMBLED, "canvas" = STAGE_DISASSEMBLED, "guy lines" = STAGE_DISASSEMBLED, "pegs" = STAGE_DISASSEMBLED) component_structure = /obj/structure/component/tent_canvas source_item_type = /obj/item/tent /** * The state name of an overlay in `icons/obj/item/tent_decals.dmi` * Used for branded tents, such as the SCC base camp tent */ var/decal /datum/large_structure/tent/build_structures() . = ..() var/list/roofs = list() for(var/obj/structure/component/tent_canvas/C in grouped_structures) var/perspective_fix = FALSE // Used to make E/W facing even tents have similar perspective to odd ones if(dir & (NORTH | SOUTH)) if(C.x == x1 || C.x == x2) C.icon_state = "canvas_[get_location(C)]" var/mid = Mean(x1, x2) if(C.x < mid) C.dir = WEST else C.dir = EAST else var/width = y2 - y1 if(C.y == y1 || C.y == y2) C.icon_state = "canvas_[get_location(C)]" if(C.y == y2) //Upper wall C.layer = ABOVE_TILE_LAYER var/mid = Mean(y1, y2) if(C.y < mid) C.dir = SOUTH else if(ISODD(width) && C.y == Ceil(mid)) // `width` is actually 1 less than the width, so we need to check if this is odd perspective_fix = TRUE C.dir = NORTH var/obj/structure/component/tent_canvas/roof/roof = new /obj/structure/component/tent_canvas/roof(C.loc) roofs += roof roof.color = color roof.dir = C.dir if(decal && C.x == x1 && C.y == y1) roof.AddOverlays(overlay_image('icons/obj/item/tent_decals.dmi', decal, flags=RESET_COLOR)) roof.icon_state = "roof_[get_location(C)]" if(perspective_fix) roof.AddOverlays(overlay_image(roof.icon, "[roof.icon_state]_p")) grouped_structures += roofs /datum/large_structure/tent/structure_entered(turf/entry_point, atom/movable/entering) . = ..() if(!.) return var/mob/M = entering if(!M.renderers) return var/atom/movable/renderer/roofs/roof_plane = M.renderers["[ROOF_PLANE]"] if(roof_plane) roof_plane.alpha = 76 /datum/large_structure/tent/mob_moved(mob/mover, turf/exit_point) . = ..() if(!.) var/atom/movable/renderer/roofs/roof_plane = mover.renderers["[ROOF_PLANE]"] if(roof_plane) roof_plane.alpha = 255 /** * Determines the state to use for each section of the tent * Returns `edge` for structures on the edge of the tent * Returns `entrance_top` for structures acting as an entrance, at the north/east of the tent * Returns `entrance_bot` for structures acting as an entrance, at the south/west of the tent * Returns `edge_entrance_top` for structures on the edge of the tent, and acting as an entrance, at the north/east of the tent * Returns `edge_entrance_bot` for structures on the edge of the tent, and acting as an entrance, at the south/west of the tent * Returns `mid` for structures in the exact centre of the tent, for odd number widths * Returns `mid_entrance_top` for structures in the exact centre of the tent, for odd number widths, acting as an entrance, at the north/east of the tent * Returns `mid_entrance_bot` for structures in the exact centre of the tent, for odd number widths, acting as an entrance, at the south/west of the tent * Otherwise returns `norm` for other structures */ /datum/large_structure/tent/proc/get_location(var/obj/structure/component/tent_canvas/canvas) var/edge1 var/edge2 var/side_coord var/top_coord var/top_edge var/bot_edge if(dir & (NORTH | SOUTH)) edge1 = x1 edge2 = x2 side_coord = canvas.x top_edge = y2 bot_edge = y1 top_coord = canvas.y else edge1 = y1 edge2 = y2 side_coord = canvas.y top_edge = x2 bot_edge = x1 top_coord = canvas.x if(side_coord == edge1 || side_coord == edge2) if(top_coord == top_edge) return "edge_entrance_top" else if(top_coord == bot_edge) return "edge_entrance_bot" return "edge" else if(side_coord == Mean(edge1, edge2)) if(top_coord == top_edge) return "mid_entrance_top" else if(top_coord == bot_edge) return "mid_entrance_bot" return "mid" else if(top_coord == top_edge) return "entrance_top" else if(top_coord == bot_edge) return "entrance_bot" return "norm" /obj/item/tent name = "expedition tent" desc = "A rolled up tent, ready to be assembled to make a base camp, shelter, or just a cozy place to chat." desc_info = "Drag this to yourself to begin assembly. This will take some time, in 4 stages. Others can start working on the other stages by dragging it to themselves as well." icon = 'icons/obj/item/camping.dmi' icon_state = "tent" item_state = "tent" contained_sprite = TRUE w_class = ITEMSIZE_LARGE color = "#58a178" var/width = 2 var/length = 3 var/decal var/datum/large_structure/tent/my_tent /obj/item/tent/Initialize() . = ..() w_class = min(ceil(width * length / 1.5), ITEMSIZE_IMMENSE) // 2x2 = ITEMSIZE_NORMAL desc += "\nThis one is [width] x [length] in size." /obj/item/tent/Destroy() if(my_tent) my_tent.source_item = null if(!my_tent.grouped_structures) QDEL_NULL(my_tent) return ..() /obj/item/tent/MouseDrop(over_object, src_location, over_location) . = ..() if(use_check(usr) || !Adjacent(usr)) return var/turf/T = get_turf(src) if(istype(T)) deploy_tent(T, usr) /obj/item/tent/proc/deploy_tent(var/turf/target, var/mob/user) if(my_tent) if(my_tent.origin == get_turf(src)) //Not moved my_tent.assemble(1 SECOND, user) return else QDEL_NULL(my_tent) var/deploy_dir = get_compass_dir(user,target) if(target == get_turf(user)) deploy_dir = user.dir my_tent = new /datum/large_structure/tent(src) setup_my_tent(deploy_dir, target) my_tent.assemble(1 SECOND, user) /obj/item/tent/proc/setup_my_tent(var/deploy_dir, var/turf/target) my_tent.name = name my_tent.color = color my_tent.decal = decal my_tent.dir = deploy_dir my_tent.z1 = target.z my_tent.z2 = target.z my_tent.source_item_type = type my_tent.source_item = src my_tent.origin = get_turf(src) if(deploy_dir & NORTH) my_tent.x1 = target.x - floor((width-1)/2) my_tent.x2 = target.x + ceil((width-1)/2) my_tent.y1 = target.y my_tent.y2 = target.y + (length-1) else if(deploy_dir & SOUTH) my_tent.x1 = target.x - ceil((width-1)/2) my_tent.x2 = target.x + floor((width-1)/2) my_tent.y1 = target.y - (length-1) my_tent.y2 = target.y else if(deploy_dir & EAST) my_tent.x1 = target.x my_tent.x2 = target.x + (length-1) my_tent.y1 = target.y - ceil((width-1)/2) my_tent.y2 = target.y + floor((width-1)/2) else my_tent.x1 = target.x - (length-1) my_tent.x2 = target.x my_tent.y1 = target.y - floor((width-1)/2) my_tent.y2 = target.y + ceil((width-1)/2) /obj/item/tent/big name = "base camp tent" color = "#2e3763" width = 3 length = 4 /obj/item/tent/big/scc name = "scc base camp tent" decal = "scc" /obj/item/tent/mining name = "miners' tent" color = "#8b7242" width = 3 length = 3 /obj/structure/component/tent_canvas name = "tent canvas" desc = "The fabric and poles which make up the wall of a tent. Not air-tight, but able to keep out the weather, and very cozy." desc_info = "Drag this to yourself to begin disassembly. This will take some time, in 4 stages. Others can start working on the other stages by dragging it, or other sections, to themselves as well." icon = 'icons/obj/item/camping.dmi' icon_state = "canvas" item_state = "canvas" anchored = TRUE density = TRUE atom_flags = ATOM_FLAG_CHECKS_BORDER atmos_canpass = CANPASS_ALWAYS //Tents are not air tight layer = ABOVE_HUMAN_LAYER /obj/structure/component/tent_canvas/CanPass(atom/movable/mover, turf/target, height, air_group) . = ..() if(icon_state in list("canvas", "canvas_mid", "canvas_entrance_top", "canvas_entrace_bot")) return TRUE //Non-directional, always allow passage if(get_dir(loc, target) & dir) return !density return TRUE /obj/structure/component/tent_canvas/CheckExit(atom/movable/O, turf/target) . = ..() if(icon_state in list("canvas", "canvas_mid", "canvas_entrance_top", "canvas_entrace_bot")) return TRUE //Non-directional, always allow passage if(get_dir(O.loc, target) & dir) return !density return TRUE /obj/structure/component/tent_canvas/MouseDrop(over_object, src_location, over_location) ..() if(use_check(usr, USE_ALLOW_NON_ADJACENT) || (get_dist(usr, src) > 1)) // use_check() can't check for adjacency due to density issues, so we check range as well return part_of.disassemble(2 SECONDS, usr, src) /obj/structure/component/tent_canvas/Destroy() //When we're destroyed, make sure we return the roof plane to anyone inside for(var/mob/M in loc) var/atom/movable/renderer/roofs/roof_plane = M.renderers["[ROOF_PLANE]"] if(roof_plane) roof_plane.alpha = 255 return ..() /obj/structure/component/tent_canvas/roof plane = ROOF_PLANE /obj/structure/component/tent_canvas/roof/CanPass(atom/movable/mover, turf/target, height, air_group) return TRUE /obj/structure/component/tent_canvas/roof/CheckExit(atom/movable/O, turf/target) return TRUE //Pre-fabricated tents for mapping /obj/effect/tent name = "Pre-frabricated expedition tent" icon = 'icons/effects/map_effects.dmi' icon_state = "portal_side_a" var/builds = /obj/item/tent /obj/effect/tent/Initialize(mapload, ...) . = ..() var/obj/item/tent/tent_item = new builds(src) var/datum/large_structure/tent/tent = new /datum/large_structure/tent(src) tent_item.my_tent = tent tent_item.setup_my_tent(dir, get_turf(src)) tent.get_target_turfs(null, TRUE) tent.build_structures() for(var/stage in tent.stages) tent.stages[stage] = STAGE_ASSEMBLED qdel(tent_item) qdel(src) /* Sleeping bags */ /obj/item/sleeping_bag name = "sleeping bag" desc = "A rolled up sleeping bag, ready to be taken on a camping trip." desc_extended = "This item can be attached to a backpack." icon = 'icons/obj/item/camping.dmi' icon_state = "sleepingbag" item_state = "sleepingbag" contained_sprite = TRUE w_class = ITEMSIZE_LARGE /obj/item/sleeping_bag/Initialize(mapload, ...) . = ..() if(!color) color = pick(COLOR_NAVY_BLUE, COLOR_GREEN, COLOR_MAROON, COLOR_VIOLET, COLOR_OLIVE, COLOR_SEDONA) /obj/item/sleeping_bag/afterattack(obj/target, mob/user, proximity) . = ..() if(!proximity) return var/turf/T = target if(istype(T)) unroll(T, user) /obj/item/sleeping_bag/attack_self(mob/user) . = ..() var/turf/T = get_turf(user) if(istype(T)) unroll(T, user) /obj/item/sleeping_bag/MouseDrop(over_object, src_location, over_location) . = ..() if(use_check(usr) || !Adjacent(usr)) return var/turf/T = get_turf(src) if(istype(T)) unroll(T, usr) /** * Creates sleeping bag structure on the target turf, deleting this item in the process */ /obj/item/sleeping_bag/proc/unroll(var/turf/target, var/mob/user) user.visible_message(SPAN_NOTICE("\The [user] unrolls \the [src].")) var/obj/structure/bed/sleeping_bag/S = new /obj/structure/bed/sleeping_bag(target, MATERIAL_CLOTH) S.color = color qdel(src) /obj/item/sleeping_bag/mining color = COLOR_DARK_BROWN /obj/structure/bed/sleeping_bag name = "sleeping bag" desc = "A bag for sleeping in. Great for trying to pretend you're somewhere more comfortable than you really are." icon = 'icons/obj/item/camping.dmi' icon_state = "sleepingbag_floor" base_icon = "sleepingbag_floor" density = FALSE anchored = FALSE buckling_sound = 'sound/items/drop/cloth.ogg' held_item = /obj/item/sleeping_bag can_dismantle = FALSE can_pad = FALSE /obj/structure/bed/sleeping_bag/update_icon() return /obj/structure/bed/sleeping_bag/buckle(mob/living/M) . = ..() var/image/I = overlay_image(icon, "[base_icon]_top", color) M.AddOverlays(I) /obj/structure/bed/sleeping_bag/unbuckle() if(buckled) buckled.update_icon() . = ..() /obj/structure/bed/sleeping_bag/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) . = ..() if(use_check(usr) || !Adjacent(usr)) return if(!ishuman(usr) && (!isrobot(usr) || isDrone(usr))) //Humans and borgs can roll, but not drones return if(buckled) to_chat(usr, SPAN_WARNING("You can't roll up \the [src] while someone is sleeping inside.")) return var/obj/item/sleeping_bag/S = new held_item(get_turf(src)) S.color = color usr.visible_message(SPAN_NOTICE("\The [usr] rolls up \the [src].")) qdel(src) /* Folding Tables */ /obj/item/material/folding_table name = "folding table" desc = "A temporary surface, for when you need a table, but only for a little while." icon = 'icons/obj/item/camping.dmi' icon_state = "table_folded" item_state = "table_folded" contained_sprite = TRUE default_material = MATERIAL_ALUMINIUM /obj/item/material/folding_table/attack_self(mob/user) if(use_check(user) || !Adjacent(user)) return deploy(get_turf(user), user.dir, user) /obj/item/material/folding_table/afterattack(atom/target, mob/user, proximity_flag, click_parameters) if(use_check(user) || !user.Adjacent(target)) to_chat(usr, SPAN_WARNING("You fail to set up \the [src] in that location.")) return if(isturf(target)) deploy(target, user.dir, user) /obj/item/material/folding_table/proc/deploy(var/turf/T, var/direction, var/mob/user) new /obj/structure/table/rack/folding_table(T) user.visible_message(SPAN_NOTICE("\The [user] sets up \the [src].")) qdel(src) /obj/structure/table/rack/folding_table name = "folding table" desc = "A temporary surface, for when you need a table, but only for a little while." icon_state = "camping_table" table_mat = MATERIAL_ALUMINIUM /obj/structure/table/rack/folding_table/dismantle(obj/item/wrench/W, mob/user) return FALSE /obj/structure/table/rack/folding_table/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) . = ..() if(use_check(usr) || !Adjacent(usr)) return if(!ishuman(usr) && (!isrobot(usr) || isDrone(usr))) //Humans and borgs can collapse, but not drones return new /obj/item/material/folding_table(get_turf(src)) usr.visible_message(SPAN_NOTICE("\The [usr] collapses \the [src].")) qdel(src) /obj/item/material/stool/chair/folding/camping default_material = MATERIAL_ALUMINIUM