diff --git a/code/game/atoms.dm b/code/game/atoms.dm index d8dd3bb44c8..b067e6f0812 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1153,3 +1153,10 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons) if(degrees) appearance_flags |= PIXEL_SCALE transform = M + +///Setter for the `density` variable to append behavior related to its changing. +/atom/proc/set_density(new_value) + if(density == new_value) + return + . = density + density = new_value diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index c736026bca8..48a60768b28 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -1,6 +1,17 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \ - new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 10, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 10, one_per_turf = 1, on_floor = 1), \ + null, + new /datum/stack_recipe("railing", /obj/structure/railing, 3, time = 10, one_per_turf = 1, on_floor = 1), \ + new /datum/stack_recipe("railing corner", /obj/structure/railing/corner, 3, time = 10, one_per_turf = 1, on_floor = 1), \ + null, + new /datum/stack_recipe_list("chainlink fence", list( \ + new/datum/stack_recipe("chainlink fence", /obj/structure/fence, 5, time = 10, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("chainlink fence post", /obj/structure/fence/post, 5, time = 10, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("chainlink fence corner", /obj/structure/fence/corner, 5, time = 10, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("chainlink fence door", /obj/structure/fence/door, 10, time = 10, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("chainlink fence end", /obj/structure/fence/end, 3, time = 10, one_per_turf = 1, on_floor = 1), \ + )), \ )) /obj/item/stack/rods diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm new file mode 100644 index 00000000000..361cef688d6 --- /dev/null +++ b/code/game/objects/structures/fence.dm @@ -0,0 +1,168 @@ +//Chain link fences +//Sprites ported from /VG/ + + +#define CUT_TIME 100 +#define CLIMB_TIME 150 + +#define NO_HOLE 0 //section is intact +#define MEDIUM_HOLE 1 //medium hole in the section - can climb through +#define LARGE_HOLE 2 //large hole in the section - can walk through +#define MAX_HOLE_SIZE LARGE_HOLE +#define HOLE_REPAIR (hole_size * 2) //How many rods to fix these sections + +/obj/structure/fence + name = "fence" + desc = "A chain link fence. Not as effective as a wall, but generally it keeps people out." + density = TRUE + anchored = TRUE + + icon = 'icons/obj/fence.dmi' + icon_state = "straight" + + var/cuttable = TRUE + var/hole_size= NO_HOLE + var/invulnerable = FALSE + +/obj/structure/fence/Initialize() + . = ..() + + update_cut_status() + +/obj/structure/fence/examine(mob/user) + . = ..() + + switch(hole_size) + if(MEDIUM_HOLE) + . += "There is a large hole in \the [src]." + if(LARGE_HOLE) + . += "\The [src] has been completely cut through." + +/obj/structure/fence/end + icon_state = "end" + cuttable = FALSE + +/obj/structure/fence/corner + icon_state = "corner" + cuttable = FALSE + +/obj/structure/fence/post + icon_state = "post" + cuttable = FALSE + +/obj/structure/fence/cut/medium + icon_state = "straight_cut2" + hole_size = MEDIUM_HOLE + +/obj/structure/fence/cut/large + icon_state = "straight_cut3" + hole_size = LARGE_HOLE + + +/obj/structure/fence/wirecutter_act(mob/living/user, obj/item/W) + if(!cuttable) + to_chat(user, "This section of the fence can't be cut!") + return + if(invulnerable) + to_chat(user, "This fence is too strong to cut through!") + return + var/current_stage = hole_size + if(current_stage >= MAX_HOLE_SIZE) + to_chat(user, "This fence has too much cut out of it already!") + return + + user.visible_message("\The [user] starts cutting through \the [src] with \the [W].",\ + "You start cutting through \the [src] with \the [W].") + if(W.use_tool(src, user, CUT_TIME * W.toolspeed, volume = W.tool_volume)) + if(current_stage == hole_size) + switch(++hole_size) + if(MEDIUM_HOLE) + visible_message("\The [user] cuts into \the [src] some more.") + to_chat(user, "You could probably fit yourself through that hole now. Although climbing through would be much faster if you made it even bigger.") + climbable = TRUE + if(LARGE_HOLE) + visible_message("\The [user] completely cuts through \the [src].") + to_chat(user, "The hole in \the [src] is now big enough to walk through.") + climbable = FALSE + update_cut_status() + return + + +/obj/structure/fence/attackby(obj/item/C, mob/user) + . = ..() + if(istype(C, /obj/item/stack/rods)) + if(hole_size == NO_HOLE) + return + var/obj/item/stack/rods/R = C + if(R.get_amount() < HOLE_REPAIR) + to_chat(user, "You need [HOLE_REPAIR] rods to fix this fence!") + return TRUE + else + to_chat(user, "You begin repairing the fence...") + if(do_after(user, 30 * C.toolspeed, target = src)) + if(R.get_amount() >= HOLE_REPAIR && !(hole_size == NO_HOLE)) + hole_size = NO_HOLE + playsound(src, C.usesound, 80, 1) + R.use(2) + to_chat(user, "You repair the fence.") + update_cut_status() + return TRUE + +/obj/structure/fence/proc/update_cut_status() + if(!cuttable) + return + var/new_density = TRUE + switch(hole_size) + if(NO_HOLE) + icon_state = initial(icon_state) + if(MEDIUM_HOLE) + icon_state = "straight_cut2" + if(LARGE_HOLE) + icon_state = "straight_cut3" + new_density = FALSE + set_density(new_density) + +//FENCE DOORS + +/obj/structure/fence/door + name = "fence door" + desc = "Not very useful without a real lock." + icon_state = "door_closed" + cuttable = FALSE + var/open = FALSE + +/obj/structure/fence/door/Initialize() + . = ..() + update_door_status() + +/obj/structure/fence/door/opened + icon_state = "door_opened" + open = TRUE + density = TRUE + +/obj/structure/fence/door/attack_hand(mob/user, list/modifiers) + if(can_open(user)) + toggle(user) + + return TRUE + +/obj/structure/fence/door/proc/toggle(mob/user) + open = !open + visible_message("\The [user] [open ? "opens" : "closes"] \the [src].") + update_door_status() + playsound(src, 'sound/machines/door_open.ogg', 100, TRUE) + +/obj/structure/fence/door/proc/update_door_status() + set_density(!density) + icon_state = density ? "door_closed" : "door_opened" + +/obj/structure/fence/door/proc/can_open(mob/user) + return TRUE + +#undef CUT_TIME +#undef CLIMB_TIME + +#undef NO_HOLE +#undef MEDIUM_HOLE +#undef LARGE_HOLE +#undef MAX_HOLE_SIZE diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm new file mode 100644 index 00000000000..ecfa334b337 --- /dev/null +++ b/code/game/objects/structures/railings.dm @@ -0,0 +1,124 @@ +/obj/structure/railing + name = "railing" + desc = "Basic railing meant to protect idiots like you from falling." + icon = 'icons/obj/fence.dmi' + icon_state = "railing" + density = TRUE + anchored = TRUE + climbable = TRUE + var/currently_climbed = FALSE + +/obj/structure/railing/corner //aesthetic corner sharp edges hurt oof ouch + icon_state = "railing_corner" + density = FALSE + climbable = FALSE + +/obj/structure/railing/Initialize() + . = ..() + +/obj/structure/railing/attackby(obj/item/I, mob/living/user, params) + ..() + add_fingerprint(user) + +/obj/structure/railing/welder_act(mob/living/user, obj/item/I) + if(user.intent == INTENT_HELP) + if(obj_integrity < max_integrity) + if(!I.tool_start_check(user, amount = 0)) + return + to_chat(user, "You begin repairing [src]...") + if(I.use_tool(src, user, 40, volume = 50)) + obj_integrity = max_integrity + to_chat(user, "You repair [src].") + return + + to_chat(user, "[src] is already in good condition!") + return + +/obj/structure/railing/wirecutter_act(mob/living/user, obj/item/I) + . = ..() + if(!anchored) + to_chat(user, "You cut apart the railing.") + I.play_tool_sound(src, 100) + deconstruct() + return TRUE + +/obj/structure/railing/deconstruct(disassembled) + if(!(flags & NODECONSTRUCT)) + var/obj/item/stack/rods/rod = new /obj/item/stack/rods(drop_location(), 3) + transfer_fingerprints_to(rod) + return ..() + +///Implements behaviour that makes it possible to unanchor the railing. +/obj/structure/railing/wrench_act(mob/living/user, obj/item/I) + . = ..() + if(flags & NODECONSTRUCT) + return + to_chat(user, "You begin to [anchored ? "unfasten the railing from":"fasten the railing to"] the floor...") + if(I.use_tool(src, user, volume = 75, extra_checks = CALLBACK(src, .proc/check_anchored, anchored))) + if(!anchored) + anchored = TRUE + else + anchored = FALSE + to_chat(user, "You [anchored ? "fasten the railing to":"unfasten the railing from"] the floor.") + return TRUE + +/obj/structure/railing/CanPass(atom/movable/mover, turf/target) + ..() + var/mob/living/M = mover + if(M.flying || M.floating || mover.throwing) + return TRUE + if(get_dir(loc, target) == dir) + return !density + return TRUE + +/obj/structure/railing/corner/CanPass() + ..() + return TRUE + +/obj/structure/railing/CheckExit(atom/movable/O, target) + var/mob/living/M = O + if(M.flying | M.floating) + return TRUE + if(O.throwing) + return TRUE + if(O.move_force >= MOVE_FORCE_EXTREMELY_STRONG) + return TRUE + if(currently_climbed) + if(get_turf(M) == get_turf(src)) + var/turf/T = target + if(T.density) + return TRUE + for(var/atom/A in T) + if(A.density) + return FALSE + currently_climbed = FALSE + return TRUE + if(get_dir(O.loc, target) == dir) + return FALSE + return TRUE + +/obj/structure/railing/do_climb(mob/living/user) + . = ..() + if(!climbable) + return + if(get_turf(user) == get_turf(src)) + currently_climbed = TRUE + +/obj/structure/railing/proc/can_be_rotated(mob/user, rotation_type) + if(anchored) + to_chat(user, "[src] cannot be rotated while it is fastened to the floor!") + return FALSE + + var/target_dir = turn(dir, -90) + + if(!valid_window_location(loc, target_dir)) //Expanded to include rails, as well! + to_chat(user, "[src] cannot be rotated in that direction!") + return FALSE + return TRUE + +/obj/structure/railing/proc/check_anchored(checked_anchored) + if(anchored == checked_anchored) + return TRUE + +/obj/structure/railing/proc/after_rotation(mob/user,rotation_type) + add_fingerprint(user) diff --git a/icons/obj/fence.dmi b/icons/obj/fence.dmi new file mode 100644 index 00000000000..9debf926053 Binary files /dev/null and b/icons/obj/fence.dmi differ diff --git a/paradise.dme b/paradise.dme index cfe41674e94..7c5da49fd52 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1059,6 +1059,7 @@ #include "code\game\objects\structures\engicart.dm" #include "code\game\objects\structures\extinguisher.dm" #include "code\game\objects\structures\false_walls.dm" +#include "code\game\objects\structures\fence.dm" #include "code\game\objects\structures\flora.dm" #include "code\game\objects\structures\fluff.dm" #include "code\game\objects\structures\foodcart.dm" @@ -1079,6 +1080,7 @@ #include "code\game\objects\structures\morgue.dm" #include "code\game\objects\structures\noticeboard.dm" #include "code\game\objects\structures\plasticflaps.dm" +#include "code\game\objects\structures\railings.dm" #include "code\game\objects\structures\reflector.dm" #include "code\game\objects\structures\safe.dm" #include "code\game\objects\structures\signs.dm"