diff --git a/code/modules/admin/buildmode.dm b/code/modules/admin/buildmode.dm
index cc53ef0ba62..455bea43014 100644
--- a/code/modules/admin/buildmode.dm
+++ b/code/modules/admin/buildmode.dm
@@ -4,7 +4,10 @@
#define THROW_BUILDMODE 4
#define AREA_BUILDMODE 5
#define COPY_BUILDMODE 6
-#define NUM_BUILDMODES 6
+#define AREAEDIT_BUILDMODE 7
+#define FILL_BUILDMODE 8
+#define LINK_BUILDMODE 9
+#define NUM_BUILDMODES 9
/obj/screen/buildmode
icon = 'icons/misc/buildmode.dmi'
@@ -88,6 +91,36 @@
cl = null
qdel(I)
+/obj/effect/buildmode_line
+ var/image/I
+ var/client/cl
+
+/obj/effect/buildmode_line/New(var/client/c, var/atom/atom_a, var/atom/atom_b, var/linename)
+ name = linename
+ loc = get_turf(atom_a)
+ I = image('icons/misc/mark.dmi', src, "line", 19.0)
+ var/x_offset = ((atom_b.x * 32) + atom_b.pixel_x) - ((atom_a.x * 32) + atom_a.pixel_x)
+ var/y_offset = ((atom_b.y * 32) + atom_b.pixel_y) - ((atom_a.y * 32) + atom_a.pixel_y)
+
+ var/matrix/M = matrix()
+ M.Translate(0, 16)
+ M.Scale(1, sqrt((x_offset * x_offset) + (y_offset * y_offset)) / 32)
+ M.Turn(90 - Atan2(x_offset, y_offset)) // So... You pass coords in order x,y to this version of atan2. It should be called acsc2.
+ M.Translate(atom_a.pixel_x, atom_a.pixel_y)
+
+ transform = M
+ cl = c
+ cl.images += I
+
+/obj/effect/buildmode_line/Destroy()
+ if(I)
+ if(istype(cl))
+ cl.images -= I
+ cl = null
+ qdel(I)
+ I = null
+ return ..()
+
/datum/click_intercept
var/client/holder = null
var/list/obj/screen/buttons = list()
@@ -128,11 +161,23 @@
var/varholder = "name"
var/valueholder = "derp"
var/objholder = /obj/structure/closet
+ var/area/storedarea = null
+ var/image/areaimage
var/atom/movable/stored = null
+ var/list/link_lines = list()
+ var/obj/link_obj
+ var/valid_links = 0
+
+/datum/click_intercept/buildmode/New(client/c)
+ ..()
+ areaimage = image('icons/turf/areas.dmi',null,"yellow")
+ holder.images += areaimage
/datum/click_intercept/buildmode/Destroy()
stored = null
Reset()
+ areaimage.loc = null
+ qdel(areaimage)
..()
/datum/click_intercept/buildmode/create_buttons()
@@ -188,6 +233,22 @@
to_chat(user, "Left Mouse Button on obj/turf/mob = Spawn a Copy of selected target")
to_chat(user, "Right Mouse Button on obj/mob = Select target to copy")
to_chat(user, "***********************************************************")
+ if(AREAEDIT_BUILDMODE)
+ to_chat(user, "***********************************************************")
+ to_chat(user, "Left Mouse Button on obj/turf/mob = Paint area")
+ to_chat(user, "Right Mouse Button on obj/turf/mob = Select area to paint")
+ to_chat(user, "Right Mouse Button on buildmode button = Create new area")
+ to_chat(user, "***********************************************************")
+ if(FILL_BUILDMODE)
+ to_chat(user, "***********************************************************")
+ to_chat(user, "Left Mouse Button on turf/obj/mob = Select corner")
+ to_chat(user, "Right Mouse Button on buildmode button = Select object type")
+ to_chat(user, "***********************************************************")
+ if(LINK_BUILDMODE)
+ to_chat(user, "***********************************************************")
+ to_chat(user, "Left Mouse Button on obj = Select button to link")
+ to_chat(user, "Right Mouse Button on obj = Link/unlink to selected button")
+ to_chat(user, "***********************************************************")
/datum/click_intercept/buildmode/proc/change_settings(mob/user)
switch(mode)
@@ -199,7 +260,7 @@
objholder = text2path(target_path)
if(!ispath(objholder))
objholder = pick_closest_path(target_path)
- if(!objholder)
+ if(!objholder || ispath(objholder, /area))
objholder = /obj/structure/closet
alert("That path is not allowed.")
else
@@ -234,6 +295,32 @@
generator_path = type
cornerA = null
cornerB = null
+ if(AREAEDIT_BUILDMODE)
+ var/target_path = input(user,"Enter typepath:", "Typepath", "/area")
+ var/areatype = text2path(target_path)
+ if(ispath(areatype,/area))
+ var/areaname = input(user,"Enter area name:", "Area name", "Area")
+ if(!areaname || !length(areaname))
+ return
+ storedarea = new areatype
+ storedarea.power_equip = 0
+ storedarea.power_light = 0
+ storedarea.power_environ = 0
+ storedarea.always_unpowered = 0
+ storedarea.name = areaname
+ areaimage.loc = storedarea
+ if(FILL_BUILDMODE)
+ var/target_path = input(user,"Enter typepath:" ,"Typepath","/obj/structure/closet")
+ objholder = text2path(target_path)
+ if(!ispath(objholder))
+ objholder = pick_closest_path(target_path)
+ if(!objholder || ispath(objholder, /area))
+ objholder = /obj/structure/closet
+ return
+ else
+ if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0))
+ objholder = /obj/structure/closet
+ deselect_region()
/datum/click_intercept/buildmode/proc/change_dir()
switch(build_dir)
@@ -257,6 +344,13 @@
/datum/click_intercept/buildmode/proc/Reset()//Reset temporary variables
deselect_region()
+ if(mode == AREAEDIT_BUILDMODE)
+ areaimage.loc = storedarea
+ else
+ areaimage.loc = null
+ for(var/obj/effect/buildmode_line/L in link_lines)
+ qdel(L)
+ link_lines -= L
/datum/click_intercept/buildmode/proc/select_tile(var/turf/T)
return new /obj/effect/buildmode_reticule(T, holder)
@@ -396,3 +490,109 @@
if(ismovableatom(object)) // No copying turfs for now.
to_chat(user, "[object] set as template.")
stored = object
+ if(AREAEDIT_BUILDMODE)
+ if(left_click)
+ if(!storedarea)
+ return
+ var/turf/T = get_turf(object)
+ if(get_area(T) != storedarea)
+ storedarea.contents.Add(T)
+ else if(right_click)
+ var/turf/T = get_turf(object)
+ storedarea = get_area(T)
+ areaimage.loc = storedarea
+ if(FILL_BUILDMODE)
+ if(!cornerA)
+ cornerA = select_tile(get_turf(object))
+ return
+ if(cornerA && !cornerB)
+ cornerB = select_tile(get_turf(object))
+ if(left_click) //rectangular
+ if(cornerA && cornerB)
+ if(!objholder)
+ to_chat(user, "Select object type first.")
+ else
+ for(var/turf/T in block(get_turf(cornerA),get_turf(cornerB)))
+ if(ispath(objholder,/turf))
+ T.ChangeTurf(objholder)
+ else
+ var/obj/A = new objholder(T)
+ A.dir = build_dir
+ deselect_region()
+ return
+
+ //Something wrong - Reset
+ deselect_region()
+ if(LINK_BUILDMODE)
+ if(left_click && istype(object, /obj/machinery))
+ link_obj = object
+ if(right_click && istype(object, /obj/machinery))
+ if(istype(link_obj, /obj/machinery/door_control) && istype(object, /obj/machinery/door/airlock))
+ var/obj/machinery/door_control/M = link_obj
+ var/obj/machinery/door/airlock/P = object
+ if(!M.id || M.id == "")
+ M.id = input(holder, "Please select an ID for the button", "Buildmode", "")
+ if(!M.id || M.id == "")
+ goto(line_jump)
+ if(P.id_tag == M.id && (P in range(M.range, M)) && P.id_tag && P.id_tag != "")
+ P.id_tag = null
+ to_chat(holder, "[P] unlinked.")
+ goto(line_jump)
+ if(!M.normaldoorcontrol)
+ if(link_lines.len && alert(holder, "Warning: This will disable links to connected pod doors. Continue?", "Buildmode", "Yes", "No") == "No")
+ goto(line_jump)
+ M.normaldoorcontrol = 1
+ if(P.id_tag && alert(holder, "Warning: This will unlink something else from the door. Continue?", "Buildmode", "Yes", "No") == "No")
+ goto(line_jump)
+ P.id_tag = M.id
+ if(istype(link_obj, /obj/machinery/door_control) && istype(object, /obj/machinery/door/poddoor))
+ var/obj/machinery/door_control/M = link_obj
+ var/obj/machinery/door/poddoor/P = object
+ if(!M.id || M.id == "")
+ M.id = input(holder, "Please select an ID for the button", "Buildmode", "")
+ if(!M.id || M.id == "")
+ goto(line_jump)
+ if(P.id_tag == M.id && P.id_tag && P.id_tag != "")
+ P.id_tag = null
+ to_chat(holder, "[P] unlinked.")
+ goto(line_jump)
+ if(M.normaldoorcontrol)
+ if(link_lines.len && alert(holder, "Warning: This will disable links to connected airlocks. Continue?", "Buildmode", "Yes", "No") == "No")
+ goto(line_jump)
+ M.normaldoorcontrol = 0
+ if(!M.id || M.id == "")
+ M.id = input(holder, "Please select an ID for the button", "Buildmode", "")
+ if(!M.id || M.id == "")
+ goto(line_jump)
+ if(P.id_tag && P.id_tag != 1 && alert(holder, "Warning: This will unlink something else from the door. Continue?", "Buildmode", "Yes", "No") == "No")
+ goto(line_jump)
+ P.id_tag = M.id
+
+ line_jump // For the goto
+ valid_links = 0
+ for(var/obj/effect/buildmode_line/L in link_lines)
+ qdel(L)
+ link_lines -= L
+
+ if(istype(link_obj, /obj/machinery/door_control))
+ var/obj/machinery/door_control/M = link_obj
+ for(var/obj/machinery/door/airlock/P in range(M.range,M))
+ if(P.id_tag == M.id)
+ var/obj/effect/buildmode_line/L = new(holder, M, P, "[M.name] to [P.name]")
+ L.color = M.normaldoorcontrol ? "#339933" : "#993333"
+ if(M.normaldoorcontrol)
+ valid_links = 1
+ link_lines += L
+ var/obj/effect/buildmode_line/L2 = new(holder, P, M, "[M.name] to [P.name]") // Yes, reversed one so that you can see it from both sides.
+ L2.color = L.color
+ link_lines += L2
+ for(var/obj/machinery/door/poddoor/P in world)
+ if(P.id_tag == M.id)
+ var/obj/effect/buildmode_line/L = new(holder, M, P, "[M.name] to [P.name]")
+ L.color = M.normaldoorcontrol ? "#993333" : "#339933"
+ if(M.normaldoorcontrol)
+ valid_links = 0
+ link_lines += L
+ var/obj/effect/buildmode_line/L2 = new(holder, P, M, "[M.name] to [P.name]") // Yes, reversed one so that you can see it from both sides.
+ L2.color = L.color
+ link_lines += L2
diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi
index ca9d1fd05cc..1d206b45e75 100644
Binary files a/icons/misc/buildmode.dmi and b/icons/misc/buildmode.dmi differ
diff --git a/icons/misc/mark.dmi b/icons/misc/mark.dmi
index 51d111f56ec..f0c6049707f 100644
Binary files a/icons/misc/mark.dmi and b/icons/misc/mark.dmi differ