From 5fde45d366871ad58f332a08d505684a5024c782 Mon Sep 17 00:00:00 2001 From: S34NW <12197162+S34NW@users.noreply.github.com> Date: Fri, 10 Sep 2021 15:55:22 +0100 Subject: [PATCH] fences and railings --- code/game/atoms.dm | 7 + code/game/objects/items/stacks/rods.dm | 15 +- code/game/objects/structures/fence.dm | 168 +++++++++++++++++++++++ code/game/objects/structures/railings.dm | 124 +++++++++++++++++ icons/obj/fence.dmi | Bin 0 -> 7530 bytes paradise.dme | 2 + 6 files changed, 314 insertions(+), 2 deletions(-) create mode 100644 code/game/objects/structures/fence.dm create mode 100644 code/game/objects/structures/railings.dm create mode 100644 icons/obj/fence.dmi 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 0000000000000000000000000000000000000000..9debf92605378933d2128061630da337ebffb23f GIT binary patch literal 7530 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≫|vI z?GeZ4xBc_{i+s}INuA5}B}Sa6KV(MJ05AHW2v4N%!-ryUc2n+lnZgCTUwAe99_K3i;0Rws2+x9WjUVw>xcxrSJ04I;l~3Z-3^z}0cW_jr4zL} zA09IR{M2`bu0ea|;&^$;Hi38EJ0L7^cWLKrtKsoBly}f}c5lBs?q0lcLm)&XYbhFOwyYehfFbhfaoJ?p!!l&25?Xo! zr>1W9e&T#3t0s{t0le4QnkYZFYluL|A0grvtfGz;&XATBKpnO=QRkBV^ph|B%jzVG zei)a0yvbWX3n&l+1$;Dr@*x~k_BJqG8bNXB4ttn#Z`7}PH0k|hYfr|p1y}*0;q9&+ zq(8SivWKI0aL}>3x|+>uet33`qSP8BU`-L?=i~FDyA2UrJI^+Mx8i2 z;W3*{1c@4_^@ALX=hpXL(M^%F@$vQ5#;T}PO2s0HNEBIuAPAo{o1c1IEKt7hdISgwda!d>}<$@FnbmLa637=!Ts`1=@hkN zb{$W*!jKF-=-Cn=H8oX2NtjAc8SN2D7w*)WCC@sd*y@t%7mR%N)}@X-hD<}TwS8gJ zzrR{2Ii{J^voG({{uS8<1Tidvgh0cdUnbi%d~IVF^tQx`$$AfK3C?vPj2gyf`*;Dc zK!7_y^YtKtai~jzNq5W@QyS35HnCRGI(xvY&x8IfWqxIi^=va6*Or{@5w|NASoP85 z5S7E>!FW!b;C>}1nBe}9OjexW!KXYRSn~K?u)on7debvR@tU3FwhS{UBm3x=xS`Q# z88V`pF=vBxhD80>QEnakcsSddM9P4|jJNpfRO{q7Z$$YWb9Sf5L_ZEf?Qmm{TGZKj z(miKq=O5K4cT%abqgd!w%;Ngo5LF?3Z3lRBP4DtC_T$h32y+yh0TzKA(yZN^ptIOW z{a>y5!s08V4HaO~n1*$vjY^C;s=K7m527N7&$(E3rKQqyO+6=%Zqg$0l`rktU;fyl zeu7pDDk==+%3&Q3&aC^t=sB{`E6;FNEK1fQV5chF>`OyKN>u#|%-)G=kP3 zZCw^yJBBM#X^1`NO>c`^SX_i-4%oX%go15oG7oWt1AvtX;^?KtZ%(tu