Files
Aurora.3/code/game/objects/items/camping.dm
Sparky eff6ca9a7b Expedition Fluff Expansion - Tents & Sleeping Bags (#19362)
Adds tents, in two variants (A larger and smaller one). These utilise a
new large structure framework allowing a single item to spawn multiple
structures (The parts of the tent) in the correct places. The tents
count as inside, so can be used to shelter from weather. Tents have
roofs which become semi-transparent when entered. There are also
mappable effects which generate a tent at round start for mapping.

Adds sleeping bags, which can be attached to the outside of bags for
easy carrying. Ideally this would be an accessories interaction, but
backpacks aren't clothing and converting them to be such is outside of
the scope of this PR.

Adds foldable tables, for setting up on expeditions.
2024-06-19 19:51:25 +00:00

387 lines
11 KiB
Plaintext

/*
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)
if(dir & (NORTH | SOUTH))
if(C.x == x1 || C.x == x2)
C.icon_state = "canvas_dir"
var/mid = Mean(x1, x2)
if(C.x < mid)
C.dir = WEST
else
C.dir = EAST
else
if(C.y == y1 || C.y == y2)
C.icon_state = "canvas_dir"
var/mid = Mean(y1, y2)
if(C.y < mid)
C.dir = SOUTH
else
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_roof_type(C)]"
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 roof state over each canvas structure
* Returns `edge` for structures on the edge of the tent, so they don't cover the walls
* Returns `mid` for structures in the centre of the tent, for odd number widths
* Otherwise returns `norm` for other structures
*/
/datum/large_structure/tent/proc/get_roof_type(var/obj/structure/component/tent_canvas/canvas)
var/edge1
var/edge2
var/axis
if(dir & (NORTH | SOUTH))
edge1 = x1
edge2 = x2
axis = canvas.x
else
edge1 = y1
edge2 = y2
axis = canvas.y
if(axis == edge1 || axis == edge2)
return "edge"
else if(axis == Mean(edge1, edge2))
return "mid"
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"
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 == "canvas")
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 == "canvas")
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) || !Adjacent(usr))
return
part_of.disassemble(2 SECONDS, usr, src)
/obj/structure/component/tent_canvas/roof
plane = ROOF_PLANE
//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()
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) || !Adjacent(user))
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