From d650dbe87ae6d720b5cef3c0011d1b805fd37ad9 Mon Sep 17 00:00:00 2001 From: Aronai Sieyes Date: Fri, 1 May 2020 13:00:13 -0400 Subject: [PATCH] Port Bay's Catwalks Allows for various new funtimes. --- code/game/objects/structures.dm | 88 +++++++++- code/game/objects/structures/catwalk.dm | 220 ++++++++++++++++-------- code/modules/tables/tables.dm | 56 ------ icons/turf/catwalks.dmi | Bin 6149 -> 6544 bytes 4 files changed, 226 insertions(+), 138 deletions(-) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 3e571009d27..f89aa2edc91 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -8,11 +8,21 @@ var/parts var/list/climbers = list() var/block_turf_edges = FALSE // If true, turf edge icons will not be made on the turf this occupies. + + var/list/connections = list("0", "0", "0", "0") + var/list/other_connections = list("0", "0", "0", "0") + var/list/blend_objects = newlist() // Objects which to blend with + var/list/noblend_objects = newlist() //Objects to avoid blending with (such as children of listed blend objects. + +/obj/structure/Initialize() + . = ..() + if(climbable) + verbs += /obj/structure/proc/climb_on /obj/structure/Destroy() if(parts) new parts(loc) - . = ..() + return ..() /obj/structure/attack_hand(mob/user) if(breakable) @@ -46,13 +56,7 @@ if(3.0) return -/obj/structure/New() - ..() - if(climbable) - verbs += /obj/structure/proc/climb_on - /obj/structure/proc/climb_on() - set name = "Climb structure" set desc = "Climbs onto a structure." set category = "Object" @@ -61,7 +65,6 @@ do_climb(usr) /obj/structure/MouseDrop_T(mob/target, mob/user) - var/mob/living/H = user if(istype(H) && can_climb(H) && target == user) do_climb(target) @@ -185,3 +188,72 @@ user.do_attack_animation(src) spawn(1) qdel(src) return 1 + +/obj/structure/proc/can_visually_connect() + return anchored + +/obj/structure/proc/can_visually_connect_to(var/obj/structure/S) + return istype(S, src) + +/obj/structure/proc/update_connections(propagate = 0) + var/list/dirs = list() + var/list/other_dirs = list() + + for(var/obj/structure/S in orange(src, 1)) + if(can_visually_connect_to(S)) + if(S.can_visually_connect()) + if(propagate) + //S.update_connections() //Not here + S.update_icon() + dirs += get_dir(src, S) + + if(!can_visually_connect()) + connections = list("0", "0", "0", "0") + other_connections = list("0", "0", "0", "0") + return FALSE + + for(var/direction in cardinal) + var/turf/T = get_step(src, direction) + var/success = 0 + for(var/b_type in blend_objects) + if(istype(T, b_type)) + success = 1 + if(propagate) + var/turf/simulated/wall/W = T + if(istype(W)) + W.update_connections(1) + if(success) + break + if(success) + break + if(!success) + for(var/obj/O in T) + for(var/b_type in blend_objects) + if(istype(O, b_type)) + success = 1 + for(var/obj/structure/S in T) + if(istype(S, src)) + success = 0 + for(var/nb_type in noblend_objects) + if(istype(O, nb_type)) + success = 0 + + if(success) + break + if(success) + break + + if(success) + dirs += get_dir(src, T) + other_dirs += get_dir(src, T) + + refresh_neighbors() + + connections = dirs_to_corner_states(dirs) + other_connections = dirs_to_corner_states(other_dirs) + return TRUE + +/obj/structure/proc/refresh_neighbors() + for(var/thing in RANGE_TURFS(1, src)) + var/turf/T = thing + T.update_icon() diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index 26e040c7e9e..325cfff923b 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -1,102 +1,111 @@ -// Based on catwalk.dm from https://github.com/Endless-Horizon/CEV-Eris /obj/structure/catwalk name = "catwalk" desc = "Cats really don't like these things." - plane = DECAL_PLANE - layer = ABOVE_UTILITY icon = 'icons/turf/catwalks.dmi' icon_state = "catwalk" + plane = DECAL_PLANE + layer = ABOVE_UTILITY density = 0 + anchored = 1.0 + var/hatch_open = FALSE + var/plating_color = null + var/obj/item/stack/tile/plated_tile = null + var/static/plating_colors = list( + /obj/item/stack/tile/floor = "#858a8f", + /obj/item/stack/tile/floor/dark = "#4f4f4f", + /obj/item/stack/tile/floor/white = "#e8e8e8") var/health = 100 var/maxhealth = 100 - anchored = 1.0 /obj/structure/catwalk/Initialize() . = ..() - for(var/obj/structure/catwalk/O in range(1)) - O.update_icon() for(var/obj/structure/catwalk/C in get_turf(src)) if(C != src) - warning("Duplicate [type] in [loc] ([x], [y], [z])") - return INITIALIZE_HINT_QDEL + qdel(C) + update_connections(1) update_icon() + /obj/structure/catwalk/Destroy() - var/turf/location = loc - . = ..() - location.alpha = initial(location.alpha) - for(var/obj/structure/catwalk/L in orange(location, 1)) - L.update_icon() + redraw_nearby_catwalks() + return ..() + +/obj/structure/catwalk/proc/redraw_nearby_catwalks() + for(var/direction in alldirs) + var/obj/structure/catwalk/L = locate() in get_step(src, direction) + if(L) + L.update_connections() + L.update_icon() //so siding get updated properly + /obj/structure/catwalk/update_icon() - var/connectdir = 0 - for(var/direction in cardinal) - if(locate(/obj/structure/catwalk, get_step(src, direction))) - connectdir |= direction - - //Check the diagonal connections for corners, where you have, for example, connections both north and east. In this case it checks for a north-east connection to determine whether to add a corner marker or not. - var/diagonalconnect = 0 //1 = NE; 2 = SE; 4 = NW; 8 = SW - //NORTHEAST - if(connectdir & NORTH && connectdir & EAST) - if(locate(/obj/structure/catwalk, get_step(src, NORTHEAST))) - diagonalconnect |= 1 - //SOUTHEAST - if(connectdir & SOUTH && connectdir & EAST) - if(locate(/obj/structure/catwalk, get_step(src, SOUTHEAST))) - diagonalconnect |= 2 - //NORTHWEST - if(connectdir & NORTH && connectdir & WEST) - if(locate(/obj/structure/catwalk, get_step(src, NORTHWEST))) - diagonalconnect |= 4 - //SOUTHWEST - if(connectdir & SOUTH && connectdir & WEST) - if(locate(/obj/structure/catwalk, get_step(src, SOUTHWEST))) - diagonalconnect |= 8 - - icon_state = "catwalk[connectdir]-[diagonalconnect]" - + update_connections() + cut_overlays() + icon_state = "" + var/image/I + if(!hatch_open) + for(var/i = 1 to 4) + I = image(icon, "catwalk[connections[i]]", dir = 1<<(i-1)) + add_overlay(I) + if(plating_color) + I = image(icon, "plated") + I.color = plating_color + add_overlay(I) /obj/structure/catwalk/ex_act(severity) switch(severity) - if(1.0) + if(1) + new /obj/item/stack/rods(src.loc) qdel(src) - if(2.0) + if(2) + new /obj/item/stack/rods(src.loc) qdel(src) - if(3.0) - qdel(src) - return + +/obj/structure/catwalk/attack_robot(var/mob/user) + if(Adjacent(user)) + attack_hand(user) + +/obj/structure/catwalk/proc/deconstruct(mob/user) + playsound(src, 'sound/items/Welder.ogg', 100, 1) + to_chat(user, "Slicing \the [src] joints ...") + new /obj/item/stack/rods(src.loc) + new /obj/item/stack/rods(src.loc) + //Lattice would delete itself, but let's save ourselves a new obj + if(istype(src.loc, /turf/space) || istype(src.loc, /turf/simulated/open)) + new /obj/structure/lattice/(src.loc) + if(plated_tile) + new plated_tile(src.loc) + qdel(src) /obj/structure/catwalk/attackby(obj/item/C as obj, mob/user as mob) - if(istype(C, /obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = C - if(WT.isOn()) - if(WT.remove_fuel(0, user)) - to_chat(user, "Slicing lattice joints ...") - new /obj/item/stack/rods(src.loc) - new /obj/item/stack/rods(src.loc) - new /obj/structure/lattice(src.loc) - qdel(src) - if(C.is_screwdriver()) - if(health < maxhealth) - to_chat(user, "You begin repairing \the [src.name] with \the [C.name].") - if(do_after(user, 20, src)) - health = maxhealth - else - take_damage(C.force) - user.setClickCooldown(user.get_attack_speed(C)) - return ..() + if(C.is_crowbar() && plated_tile) + hatch_open = !hatch_open + if(hatch_open) + playsound(src, 'sound/items/Crowbar.ogg', 100, 2) + to_chat(user, "You pry open \the [src]'s maintenance hatch.") + else + playsound(src, 'sound/items/Deconstruct.ogg', 100, 2) + to_chat(user, "You shut \the [src]'s maintenance hatch.") + update_icon() + return + if(istype(C, /obj/item/stack/tile/floor) && !plated_tile) + var/obj/item/stack/tile/floor/ST = C + to_chat(user, "Placing tile...") + if (!do_after(user, 10)) + return + if(!ST.use(1)) + return + to_chat(user, "You plate \the [src]") + name = "plated catwalk" + plated_tile = C.type + src.add_fingerprint(user) + for(var/tiletype in plating_colors) + if(istype(ST, tiletype)) + plating_color = plating_colors[tiletype] + update_icon() -/obj/structure/catwalk/Crossed() - . = ..() - if(isliving(usr) && !usr.is_incorporeal()) - playsound(src, pick('sound/effects/footstep/catwalk1.ogg', 'sound/effects/footstep/catwalk2.ogg', 'sound/effects/footstep/catwalk3.ogg', 'sound/effects/footstep/catwalk4.ogg', 'sound/effects/footstep/catwalk5.ogg'), 25, 1) - -/obj/structure/catwalk/CheckExit(atom/movable/O, turf/target) - if(O.checkpass(PASSGRILLE)) - return 1 - if(target && target.z < src.z) - return 0 - return 1 +/obj/structure/catwalk/refresh_neighbors() + return /obj/structure/catwalk/take_damage(amount) health -= amount @@ -104,4 +113,67 @@ visible_message("\The [src] breaks down!") playsound(loc, 'sound/effects/grillehit.ogg', 50, 1) new /obj/item/stack/rods(get_turf(src)) - Destroy() \ No newline at end of file + Destroy() + +/obj/structure/catwalk/Crossed() + . = ..() + if(isliving(usr) && !usr.is_incorporeal()) + playsound(src, pick('sound/effects/footstep/catwalk1.ogg', 'sound/effects/footstep/catwalk2.ogg', 'sound/effects/footstep/catwalk3.ogg', 'sound/effects/footstep/catwalk4.ogg', 'sound/effects/footstep/catwalk5.ogg'), 25, 1) + +/obj/effect/catwalk_plated + name = "plated catwalk spawner" + icon = 'icons/turf/catwalks.dmi' + icon_state = "catwalk_plated" + density = 1 + anchored = 1.0 + var/activated = FALSE + plane = DECAL_PLANE + layer = ABOVE_UTILITY + var/tile = /obj/item/stack/tile/floor + var/platecolor = "#858a8f" + +/obj/effect/catwalk_plated/Initialize(mapload) + . = ..() + if(SSticker?.current_state < GAME_STATE_PLAYING) + activate() + +/obj/effect/catwalk_plated/CanPass() + return 0 + +/obj/effect/catwalk_plated/attack_hand() + attack_generic() + +/obj/effect/catwalk_plated/attack_ghost() + attack_generic() + +/obj/effect/catwalk_plated/attack_generic() + activate() + +/obj/effect/catwalk_plated/proc/activate() + if(activated) return + + if(locate(/obj/structure/catwalk) in loc) + warning("Frame Spawner: A catwalk already exists at [loc.x]-[loc.y]-[loc.z]") + else + var/obj/structure/catwalk/C = new /obj/structure/catwalk(loc) + C.plated_tile = tile + C.plating_color = platecolor + C.name = "plated catwalk" + C.update_icon() + activated = 1 + /* We don't have wallframes - yet + for(var/turf/T in orange(src, 1)) + for(var/obj/effect/wallframe_spawn/other in T) + if(!other.activated) other.activate() + */ + qdel(src) + +/obj/effect/catwalk_plated/dark + icon_state = "catwalk_plateddark" + tile = /obj/item/stack/tile/floor/dark + platecolor = "#4f4f4f" + +/obj/effect/catwalk_plated/white + icon_state = "catwalk_platedwhite" + tile = /obj/item/stack/tile/floor/white + platecolor = "#e8e8e8" diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm index 31b112e9bdf..f853e224fcb 100644 --- a/code/modules/tables/tables.dm +++ b/code/modules/tables/tables.dm @@ -28,8 +28,6 @@ var/list/table_icon_cache = list() var/carpeted = 0 var/carpeted_type = /obj/item/stack/tile/carpet - var/list/connections = list("nw0", "ne0", "sw0", "se0") - var/item_place = 1 //allows items to be placed on the table, but not on benches. /obj/structure/table/proc/update_material() @@ -402,60 +400,6 @@ var/list/table_icon_cache = list() if(carpeted) overlays += "carpet_flip[type]" -// set propagate if you're updating a table that should update tables around it too, for example if it's a new table or something important has changed (like material). -/obj/structure/table/proc/update_connections(propagate=0) - if(!material) - connections = list("0", "0", "0", "0") - - if(propagate) - for(var/obj/structure/table/T in oview(src, 1)) - T.update_connections() - return - - var/list/blocked_dirs = list() - for(var/obj/structure/window/W in get_turf(src)) - if(W.is_fulltile()) - connections = list("0", "0", "0", "0") - return - blocked_dirs |= W.dir - - for(var/D in list(NORTH, SOUTH, EAST, WEST) - blocked_dirs) - var/turf/T = get_step(src, D) - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir == reverse_dir[D]) - blocked_dirs |= D - break - else - if(W.dir != D) // it's off to the side - blocked_dirs |= W.dir|D // blocks the diagonal - - for(var/D in list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) - blocked_dirs) - var/turf/T = get_step(src, D) - - for(var/obj/structure/window/W in T) - if(W.is_fulltile() || W.dir & reverse_dir[D]) - blocked_dirs |= D - break - - // Blocked cardinals block the adjacent diagonals too. Prevents weirdness with tables. - for(var/x in list(NORTH, SOUTH)) - for(var/y in list(EAST, WEST)) - if((x in blocked_dirs) || (y in blocked_dirs)) - blocked_dirs |= x|y - - var/list/connection_dirs = list() - - for(var/obj/structure/table/T in orange(src, 1)) - var/T_dir = get_dir(src, T) - if(T_dir in blocked_dirs) continue - if(material && T.material && material.name == T.material.name && flipped == T.flipped) - connection_dirs |= T_dir - if(propagate) - spawn(0) - T.update_connections() - T.update_icon() - - connections = dirs_to_corner_states(connection_dirs) #define CORNER_NONE 0 #define CORNER_COUNTERCLOCKWISE 1 diff --git a/icons/turf/catwalks.dmi b/icons/turf/catwalks.dmi index 9e3d3d977caec0270cadf955a39622a0cfa5f85c..20c5e1f4d98bd97835547f4654c73d21e191791d 100644 GIT binary patch literal 6544 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 literal 6149 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 Mqi2sW4td=AFCB8(;{X5v