diff --git a/aurorastation.dme b/aurorastation.dme
index 1a80c686e7b..4621ac0b28b 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -1468,6 +1468,18 @@
#include "code\modules\admin\stickyban.dm"
#include "code\modules\admin\ticket.dm"
#include "code\modules\admin\topic.dm"
+#include "code\modules\admin\buildmode\advanced.dm"
+#include "code\modules\admin\buildmode\basic.dm"
+#include "code\modules\admin\buildmode\buildmode.dm"
+#include "code\modules\admin\buildmode\buttons.dm"
+#include "code\modules\admin\buildmode\click_handler.dm"
+#include "code\modules\admin\buildmode\edit.dm"
+#include "code\modules\admin\buildmode\ladders.dm"
+#include "code\modules\admin\buildmode\light_maker.dm"
+#include "code\modules\admin\buildmode\move_into.dm"
+#include "code\modules\admin\buildmode\relocate_to.dm"
+#include "code\modules\admin\buildmode\room_builder.dm"
+#include "code\modules\admin\buildmode\throw_at.dm"
#include "code\modules\admin\callproc\callproc.dm"
#include "code\modules\admin\DB ban\ban_mirroring.dm"
#include "code\modules\admin\DB ban\functions.dm"
@@ -1515,7 +1527,6 @@
#include "code\modules\admin\verbs\atmosdebug.dm"
#include "code\modules\admin\verbs\bluespacetech.dm"
#include "code\modules\admin\verbs\BrokenInhands.dm"
-#include "code\modules\admin\verbs\buildmode.dm"
#include "code\modules\admin\verbs\cinematic.dm"
#include "code\modules\admin\verbs\clear_toxins.dm"
#include "code\modules\admin\verbs\custom_event.dm"
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 39d8d1bcc2b..e523618ddcb 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -10,10 +10,6 @@
Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner.
*/
/mob/living/silicon/ai/DblClickOn(var/atom/A, params)
- if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
- build_click(src, client.buildmode, params, A)
- return
-
if(control_disabled || stat) return
if(ismob(A))
@@ -27,10 +23,6 @@
return
next_click = world.time + 1
- if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
- build_click(src, client.buildmode, params, A)
- return
-
if(stat)
return
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 33bb17cb4e3..a4849f10210 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -17,12 +17,12 @@
*/
/atom/Click(location,control,params)
- if(src)
- usr.ClickOn(src, params)
+ var/datum/click_handler/click_handler = usr.GetClickHandler()
+ click_handler.OnClick(src, params)
/atom/DblClick(var/location, var/control, var/params)
- if(src)
- usr.DblClickOn(src, params)
+ var/datum/click_handler/click_handler = usr.GetClickHandler()
+ click_handler.OnDblClick(src, params)
/atom/proc/allow_click_through(var/atom/A, var/params, var/mob/user)
return FALSE
@@ -36,10 +36,6 @@
/mob/proc/OnMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params)
if(istype(loc, /atom))
var/atom/A = loc
- if(client && client.buildmode)
- build_click(src, client.buildmode, params, A)
- return
-
if(A.RelayMouseDrag(src_object, over_object, src_location, over_location, src_control, over_control, params, src))
return
@@ -52,7 +48,7 @@
/**
* Standard mob ClickOn()
- * Handles exceptions: Buildmode, middle click, modified clicks, mech actions
+ * Handles exceptions: middle click, modified clicks, mech actions
*
* After that, mostly just check your state, check whether you're holding an item,
* check whether you're adjacent to the target, then pass off the click to whoever
@@ -82,10 +78,6 @@
return
return B.ClickOn(A, params)
- if(client && client.buildmode)
- build_click(src, client.buildmode, params, A)
- return
-
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
@@ -422,3 +414,100 @@ var/global/list/click_catchers
set hidden = 1
set name = ".mouse"
LogMouseMacro(".mouse", params)
+
+/*
+ Custom Click Handlinig
+*/
+
+/mob
+ var/datum/stack/click_handlers
+
+/mob/Destroy()
+ if(click_handlers)
+ click_handlers.QdelClear()
+ QDEL_NULL(click_handlers)
+ . = ..()
+
+var/const/CLICK_HANDLER_NONE = 0
+var/const/CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT = 1
+var/const/CLICK_HANDLER_ALL = (~0)
+
+/datum/click_handler
+ var/mob/user
+ var/handler_flags = CLICK_HANDLER_NONE
+
+/datum/click_handler/New(mob/user)
+ ..()
+ src.user = user
+ if(handler_flags & CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT)
+ RegisterSignal(user, COMSIG_MOB_LOGOUT, /datum/click_handler/proc/OnMobLogout, TRUE)
+
+/datum/click_handler/Destroy()
+ if(handler_flags & CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT)
+ UnregisterSignal(user, COMSIG_MOB_LOGOUT)
+ user = null
+ . = ..()
+
+/datum/click_handler/proc/Enter()
+ return
+
+/datum/click_handler/proc/Exit()
+ return
+
+
+/datum/click_handler/proc/OnMobLogout()
+ user.RemoveClickHandler(src)
+
+/datum/click_handler/proc/OnClick(var/atom/A, var/params)
+ return
+
+/datum/click_handler/proc/OnDblClick(var/atom/A, var/params)
+ return
+
+/datum/click_handler/default/OnClick(var/atom/A, var/params)
+ user.ClickOn(A, params)
+
+/datum/click_handler/default/OnDblClick(var/atom/A, var/params)
+ user.DblClickOn(A, params)
+
+/mob/proc/GetClickHandler(var/datum/click_handler/popped_handler)
+ if(!click_handlers)
+ click_handlers = new()
+ if(click_handlers.is_empty())
+ PushClickHandler(/datum/click_handler/default)
+ return click_handlers.Top()
+
+/mob/proc/RemoveClickHandler(var/datum/click_handler/click_handler)
+ if(!click_handlers)
+ return
+
+ var/was_top = click_handlers.Top() == click_handler
+
+ if(was_top)
+ click_handler.Exit()
+ click_handlers.Remove(click_handler)
+ qdel(click_handler)
+
+ if(!was_top)
+ return
+ click_handler = click_handlers.Top()
+ if(click_handler)
+ click_handler.Enter()
+
+/mob/proc/PopClickHandler()
+ if(!click_handlers)
+ return
+ RemoveClickHandler(click_handlers.Top())
+
+/mob/proc/PushClickHandler(var/datum/click_handler/new_click_handler_type)
+ if((initial(new_click_handler_type.handler_flags) & CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT) && !client)
+ return FALSE
+ if(!click_handlers)
+ click_handlers = new()
+ var/datum/click_handler/click_handler = click_handlers.Top()
+ if(click_handler)
+ click_handler.Exit()
+
+ click_handler = new new_click_handler_type(src)
+ click_handler.Enter()
+ click_handlers.Push(click_handler)
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index 5028af39eee..40ecc88f1cf 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -11,10 +11,6 @@
return
next_click = world.time + 1
- if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
- build_click(src, client.buildmode, params, A)
- return
-
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])
CtrlShiftClickOn(A)
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index 0cac821fad8..8abdab43ccc 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -11,9 +11,6 @@
to_chat(src, "You will no longer examine things you click on.")
/mob/abstract/observer/DblClickOn(var/atom/A, var/params)
- if(client.buildmode)
- build_click(src, client.buildmode, params, A)
- return
if(can_reenter_corpse && mind && mind.current)
if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
@@ -29,9 +26,6 @@
forceMove(get_turf(A))
/mob/abstract/observer/ClickOn(var/atom/A, var/params)
- if(client.buildmode)
- build_click(src, client.buildmode, params, A)
- return
if(!canClick()) return
setClickCooldown(4)
// You are responsible for checking config.ghost_interaction when you override this function
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 43b2bf2b46b..c3f1312d73f 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -746,8 +746,14 @@ var/list/admin_verbs_cciaa = list(
/client/proc/togglebuildmodeself()
set name = "Toggle Build Mode Self"
set category = "Special Verbs"
- if(src.mob)
- togglebuildmode(src.mob)
+
+ if(!check_rights(R_ADMIN))
+ return
+ var/datum/click_handler/handler = mob.GetClickHandler()
+ if(handler.type == /datum/click_handler/build_mode)
+ usr.PopClickHandler()
+ else
+ usr.PushClickHandler(/datum/click_handler/build_mode)
feedback_add_details("admin_verb","TBMS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/object_talk(var/msg as text) // -- TLE
diff --git a/code/modules/admin/buildmode/advanced.dm b/code/modules/admin/buildmode/advanced.dm
new file mode 100644
index 00000000000..2f7b2b47f33
--- /dev/null
+++ b/code/modules/admin/buildmode/advanced.dm
@@ -0,0 +1,46 @@
+/datum/build_mode/advanced
+ name = "Advanced"
+ icon_state = "buildmode2"
+ var/build_type
+
+/datum/build_mode/advanced/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Left Click = Create objects"))
+ to_chat(user, SPAN_NOTICE("Right Click = Delete objects"))
+ to_chat(user, SPAN_NOTICE("Left Click + Ctrl = Capture object type"))
+ to_chat(user, SPAN_NOTICE("Middle Click = Capture object type"))
+ to_chat(user, SPAN_NOTICE("Right Click on Build Mode Button = Select object type"))
+ to_chat(user, "")
+ to_chat(user, SPAN_NOTICE("Use the directional button in the upper left corner to"))
+ to_chat(user, SPAN_NOTICE("change the direction of built objects."))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/advanced/Configurate()
+ SetBuildType(select_subpath(build_type || /obj/structure/closet))
+
+/datum/build_mode/advanced/OnClick(var/atom/A, var/list/parameters)
+ if(parameters["left"] && !parameters["ctrl"])
+ if(ispath(build_type,/turf))
+ var/turf/T = get_turf(A)
+ T.ChangeTurf(build_type)
+ else if(ispath(build_type))
+ var/atom/new_atom = new build_type (get_turf(A))
+ new_atom.set_dir(host.dir)
+ Log("Created - [log_info_line(new_atom)]")
+ else
+ to_chat(user, SPAN_NOTICE("Select a type to construct."))
+ else if(parameters["right"])
+ Log("Deleted - [log_info_line(A)]")
+ qdel(A)
+ else if((parameters["left"] && parameters["ctrl"]) || parameters["middle"])
+ SetBuildType(A.type)
+
+/datum/build_mode/advanced/proc/SetBuildType(var/atom_type)
+ if(!atom_type || atom_type == build_type)
+ return
+
+ if(ispath(atom_type, /atom))
+ build_type = atom_type
+ to_chat(user, SPAN_NOTICE("Will now construct instances of the type [atom_type]."))
+ else
+ to_chat(user, SPAN_WARNING("Cannot construct instances of type [atom_type]."))
diff --git a/code/modules/admin/buildmode/basic.dm b/code/modules/admin/buildmode/basic.dm
new file mode 100644
index 00000000000..ec257aefa1b
--- /dev/null
+++ b/code/modules/admin/buildmode/basic.dm
@@ -0,0 +1,70 @@
+/datum/build_mode/basic
+ the_default = TRUE
+ name = "Basic"
+ icon_state = "buildmode1"
+
+/datum/build_mode/basic/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Left Click = Construct / Upgrade"))
+ to_chat(user, SPAN_NOTICE("Right Click = Deconstruct / Delete / Downgrade"))
+ to_chat(user, SPAN_NOTICE("Left Click + Ctrl = R-Window"))
+ to_chat(user, SPAN_NOTICE("Left Click + Alt = Airlock"))
+ to_chat(user, "")
+ to_chat(user, SPAN_NOTICE("Use the directional button in the upper left corner to"))
+ to_chat(user, SPAN_NOTICE("change the direction of built objects."))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/basic/OnClick(var/atom/object, var/list/pa)
+ if(istype(object,/turf) && pa["left"] && !pa["alt"] && !pa["ctrl"] )
+ if(istype(object,/turf/space))
+ var/turf/T = object
+ Log("Upgraded - [log_info_line(object)]")
+ T.ChangeTurf(/turf/simulated/floor)
+ return
+ else if(istype(object,/turf/simulated/floor))
+ var/turf/T = object
+ Log("Upgraded - [log_info_line(object)]")
+ T.ChangeTurf(/turf/simulated/wall)
+ return
+ else if(istype(object,/turf/simulated/wall))
+ var/turf/T = object
+ Log("Upgraded - [log_info_line(object)]")
+ T.ChangeTurf(/turf/simulated/wall/r_wall)
+ return
+ else if(pa["right"])
+ if(istype(object,/turf/simulated/wall))
+ var/turf/T = object
+ Log("Downgraded - [log_info_line(object)]")
+ T.ChangeTurf(/turf/simulated/floor)
+ return
+ else if(istype(object,/turf/simulated/floor))
+ var/turf/T = object
+ Log("Downgraded - [log_info_line(object)]")
+ T.ChangeTurf(/turf/space)
+ return
+ else if(istype(object,/turf/simulated/wall/r_wall))
+ var/turf/T = object
+ Log("Downgraded - [log_info_line(object)]")
+ T.ChangeTurf(/turf/simulated/wall)
+ return
+ else if(istype(object,/obj))
+ Log("Deleted - [log_info_line(object)]")
+ qdel(object)
+ return
+ else if(istype(object,/turf) && pa["alt"] && pa["left"])
+ var/airlock = new/obj/machinery/door/airlock(get_turf(object))
+ Log("Created - [log_info_line(airlock)]")
+ else if(istype(object,/turf) && pa["ctrl"] && pa["left"])
+ var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
+ Log("Created - [log_info_line(object)]")
+ switch(host.dir)
+ if(NORTH)
+ WIN.set_dir(NORTH)
+ if(SOUTH)
+ WIN.set_dir(SOUTH)
+ if(EAST)
+ WIN.set_dir(EAST)
+ if(WEST)
+ WIN.set_dir(WEST)
+ if(NORTHWEST)
+ WIN.set_dir(NORTHWEST)
diff --git a/code/modules/admin/buildmode/buildmode.dm b/code/modules/admin/buildmode/buildmode.dm
new file mode 100644
index 00000000000..fca84332254
--- /dev/null
+++ b/code/modules/admin/buildmode/buildmode.dm
@@ -0,0 +1,51 @@
+/datum/build_mode
+ var/the_default = FALSE
+ var/name
+ var/icon_state
+ var/datum/click_handler/build_mode/host
+ var/mob/user
+
+/datum/build_mode/New(var/host)
+ ..()
+ src.host = host
+ user = src.host.user
+
+/datum/build_mode/Destroy()
+ host = null
+ . = ..()
+
+/datum/build_mode/proc/OnClick(var/atom/A, var/list/parameters)
+ return
+
+/datum/build_mode/proc/Configurate()
+ return
+
+/datum/build_mode/proc/Help()
+ return
+
+/datum/build_mode/proc/Log(message)
+ log_admin("BUILD MODE - [name] - [key_name(usr)] - [message]")
+
+/datum/build_mode/proc/Warn(message)
+ to_chat(user, "BUILD MODE - [name] - [message])")
+
+/datum/build_mode/proc/select_subpath(given_path)
+ var/desired_path = input("Enter full or partial typepath.","Typepath","[given_path]") as text|null
+ if(!desired_path)
+ return
+
+ var/list/types = typesof(/atom)
+ var/list/matches = list()
+
+ for(var/path in types)
+ if(findtext("[path]", desired_path))
+ matches += path
+
+ if(!matches.len)
+ alert("No results found. Sorry.")
+ return
+
+ if(matches.len==1)
+ return matches[1]
+ else
+ return (input("Select an atom type", "Spawn Atom", matches[1]) as null|anything in matches)
diff --git a/code/modules/admin/buildmode/buttons.dm b/code/modules/admin/buildmode/buttons.dm
new file mode 100644
index 00000000000..9748602e8b1
--- /dev/null
+++ b/code/modules/admin/buildmode/buttons.dm
@@ -0,0 +1,78 @@
+/obj/effect/bmode
+ name = "Build Mode"
+ density = 1
+ anchored = 1
+ layer = HUD_BASE_LAYER
+ mouse_opacity = MOUSE_OPACITY_OPAQUE
+ icon = 'icons/misc/buildmode.dmi'
+ var/datum/click_handler/build_mode/host
+
+/obj/effect/bmode/New(var/host)
+ ..()
+ src.host = host
+
+/obj/effect/bmode/Destroy()
+ host = null
+ . = ..()
+
+/obj/effect/bmode/proc/OnClick(var/list/params)
+ return
+
+/obj/effect/bmode/dir
+ name = "Modify Dir"
+ icon_state = "build"
+ screen_loc = "NORTH,WEST"
+
+/obj/effect/bmode/dir/New()
+ ..()
+ set_dir(host.dir)
+
+/obj/effect/bmode/dir/OnClick(var/list/parameters)
+ switch(dir)
+ if(SOUTH)
+ set_dir(WEST)
+ if(WEST)
+ set_dir(NORTH)
+ if(NORTH)
+ set_dir(EAST)
+ if(EAST)
+ set_dir(NORTHWEST)
+ else
+ set_dir(SOUTH)
+ host.dir = dir
+
+/obj/effect/bmode/help
+ name = "Help"
+ icon_state = "buildhelp"
+ screen_loc = "NORTH,WEST+1"
+
+/obj/effect/bmode/help/OnClick()
+ host.current_build_mode.Help()
+
+/obj/effect/bmode/mode
+ name = "Select Mode"
+ screen_loc = "NORTH,WEST+2"
+
+/obj/effect/bmode/mode/New()
+ ..()
+ icon_state = host.current_build_mode.icon_state
+
+/obj/effect/bmode/mode/OnClick(var/list/parameters)
+ if(parameters["left"])
+ var/datum/build_mode/build_mode = input("Select build mode", "Select build mode", host.current_build_mode) as null|anything in host.build_modes
+ if(build_mode && host && (build_mode in host.build_modes))
+ host.current_build_mode = build_mode
+ icon_state = build_mode.icon_state
+ to_chat(usr, SPAN_NOTICE("Build mode '[host.current_build_mode]' selected."))
+ else if(parameters["right"])
+ host.current_build_mode.Configurate()
+
+/obj/effect/bmode/quit
+ name = "Quit"
+ icon_state = "buildquit"
+ screen_loc = "NORTH,WEST+3"
+
+/obj/effect/bmode/quit/OnClick()
+ var/datum/click_handler/handler = usr.GetClickHandler()
+ if(handler.type == /datum/click_handler/build_mode)
+ usr.PopClickHandler()
diff --git a/code/modules/admin/buildmode/click_handler.dm b/code/modules/admin/buildmode/click_handler.dm
new file mode 100644
index 00000000000..dfab1ac97f3
--- /dev/null
+++ b/code/modules/admin/buildmode/click_handler.dm
@@ -0,0 +1,52 @@
+/datum/click_handler/build_mode
+ handler_flags = CLICK_HANDLER_REMOVE_ON_MOB_LOGOUT
+ var/dir
+
+ var/list/build_modes
+ var/list/build_buttons
+
+ var/datum/build_mode/current_build_mode
+
+/datum/click_handler/build_mode/New(var/mob/user)
+ ..()
+
+ build_modes = list()
+ for(var/mode_type in subtypesof(/datum/build_mode))
+ var/datum/build_mode/build_mode = new mode_type(src)
+ build_modes += build_mode
+ if(build_mode.the_default)
+ current_build_mode = build_mode
+
+ build_buttons = list()
+ for(var/button_type in subtypesof(/obj/effect/bmode))
+ var/obj/effect/bmode/build_button = new button_type(src)
+ build_buttons += build_button
+
+/datum/click_handler/build_mode/Destroy()
+ QDEL_NULL(current_build_mode)
+
+ QDEL_LIST(build_modes)
+ QDEL_LIST(build_buttons)
+
+ . = ..()
+
+/datum/click_handler/build_mode/Enter()
+ user.client.show_popup_menus = FALSE
+ for(var/build_button in build_buttons)
+ user.client.screen += build_button
+
+/datum/click_handler/build_mode/Exit()
+ user.client.show_popup_menus = TRUE
+ for(var/build_button in build_buttons)
+ user.client.screen -= build_button
+
+/datum/click_handler/build_mode/OnDblClick(var/atom/A, var/params)
+ OnClick(A, params) // We treat double-clicks as normal clicks
+
+/datum/click_handler/build_mode/OnClick(var/atom/A, var/params)
+ params = params2list(params)
+ if(A in build_buttons)
+ var/obj/effect/bmode/build_button = A
+ build_button.OnClick(params)
+ else
+ current_build_mode.OnClick(A, params)
diff --git a/code/modules/admin/buildmode/edit.dm b/code/modules/admin/buildmode/edit.dm
new file mode 100644
index 00000000000..edaf59bd2ab
--- /dev/null
+++ b/code/modules/admin/buildmode/edit.dm
@@ -0,0 +1,81 @@
+/datum/build_mode/edit
+ name = "Edit"
+ icon_state = "buildmode3"
+ var/var_to_edit = "name"
+ var/value_to_set = "derp"
+
+/datum/build_mode/edit/Destroy()
+ ClearValue()
+ . = ..()
+
+/datum/build_mode/edit/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Right Click on Build Mode Button = Select var & value"))
+ to_chat(user, SPAN_NOTICE("Left Click = Sets the var's value"))
+ to_chat(user, SPAN_NOTICE("Right Click = Reset the var's value"))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/edit/Configurate()
+ var/var_name = input("Enter variable name:", "Name", var_to_edit) as text|null
+ if(!var_name)
+ return
+
+ var/thetype = input("Select variable type:", "Type") as null|anything in list("text","number","mob-reference","obj-reference","turf-reference")
+ if(!thetype) return
+
+ var/new_value
+ switch(thetype)
+ if("text")
+ new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as text|null
+ if("number")
+ new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as num|null
+ if("mob-reference")
+ new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|mob in GLOB.mob_list
+ if("obj-reference")
+ new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|obj in world
+ if("turf-reference")
+ new_value = input(usr,"Enter variable value:" ,"Value", value_to_set) as null|turf in world
+
+ if(var_name && new_value)
+ var_to_edit = var_name
+ SetValue(new_value)
+
+/datum/build_mode/edit/OnClick(var/atom/A, var/list/parameters)
+ if(var_to_edit in VVlocked)
+ if(!check_rights(R_DEBUG)) return
+ if(var_to_edit in VVckey_edit)
+ if(!check_rights(R_SPAWN|R_DEBUG)) return
+ if(var_to_edit in VVicon_edit_lock)
+ if(!check_rights(R_FUN|R_DEBUG)) return
+ if(!(var_to_edit in A.vars))
+ to_chat(user, SPAN_WARNING("\The [A] does not have a var '[var_to_edit]'"))
+ return
+
+ var/old_value = A.vars[var_to_edit]
+ var/new_value
+ if(parameters["left"])
+ new_value = value_to_set
+ if(parameters["right"])
+ new_value = initial(A.vars[var_to_edit])
+
+ if(old_value == new_value)
+ return
+ A.vars[var_to_edit] = new_value
+ to_chat(user, SPAN_NOTICE("Changed the value of [var_to_edit] from '[old_value]' to '[new_value]'."))
+ Log("[log_info_line(A)] - [var_to_edit] - [old_value] -> [new_value]")
+
+/datum/build_mode/edit/proc/SetValue(var/new_value)
+ if(value_to_set == new_value)
+ return
+ ClearValue()
+ value_to_set = new_value
+ GLOB.destroyed_event.register(value_to_set, src, /datum/build_mode/edit/proc/ClearValue)
+
+/datum/build_mode/edit/proc/ClearValue(var/feedback)
+ if(!istype(value_to_set, /datum))
+ return
+
+ GLOB.destroyed_event.unregister(value_to_set, src, /datum/build_mode/edit/proc/ClearValue)
+ value_to_set = initial(value_to_set)
+ if(feedback)
+ Warn("The selected reference value was deleted. Default value restored.")
diff --git a/code/modules/admin/buildmode/ladders.dm b/code/modules/admin/buildmode/ladders.dm
new file mode 100644
index 00000000000..5bd3e11aa46
--- /dev/null
+++ b/code/modules/admin/buildmode/ladders.dm
@@ -0,0 +1,29 @@
+/datum/build_mode/ladders
+ name = "Ladders"
+ icon_state = "buildmode6"
+ var/turf/ladder_upper
+ var/turf/ladder_lower
+
+/datum/build_mode/ladders/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Left Click on Turf = Set as upper ladder loc"))
+ to_chat(user, SPAN_NOTICE("Right Click on Turf = Set as lower ladder loc"))
+ to_chat(user, SPAN_NOTICE("As soon as both points have been selected, the ladder is created."))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/ladders/OnClick(var/atom/A, var/list/parameters)
+ if(parameters["left"])
+ ladder_upper = get_turf(A)
+ to_chat(user, SPAN_NOTICE("Defined [ladder_upper] ([ladder_upper.type]) as the upper ladder location."))
+ if(parameters["right"])
+ ladder_lower = get_turf(A)
+ to_chat(user, SPAN_NOTICE("Defined [ladder_lower] ([ladder_lower.type]) as the lower ladder location."))
+ if(ladder_upper && ladder_lower)
+ to_chat(user, SPAN_NOTICE("Ladder locations set, building ladders."))
+ Log("Created a ladder between '[log_info_line(ladder_upper)]' and '[log_info_line(ladder_lower)]'.")
+ var/obj/structure/ladder/upper = new /obj/structure/ladder(ladder_upper)
+ var/obj/structure/ladder/lower = new /obj/structure/ladder/up(ladder_lower)
+ upper.target_down = lower
+ lower.target_up = upper
+ ladder_upper = null
+ ladder_lower = null
diff --git a/code/modules/admin/buildmode/light_maker.dm b/code/modules/admin/buildmode/light_maker.dm
new file mode 100644
index 00000000000..063a0f0b7d3
--- /dev/null
+++ b/code/modules/admin/buildmode/light_maker.dm
@@ -0,0 +1,38 @@
+/datum/build_mode/light_maker
+ name = "Light Maker"
+ icon_state = "buildmode8"
+
+ var/light_range = 3
+ var/light_power = 3
+ var/light_color = COLOR_WHITE
+
+/datum/build_mode/light_maker/Help()
+ to_chat(usr, SPAN_NOTICE("***********************************************************"))
+ to_chat(usr, SPAN_NOTICE("Left Click = Make it glow"))
+ to_chat(usr, SPAN_NOTICE("Right Click = Reset glow"))
+ to_chat(usr, SPAN_NOTICE("Right Click on Build Mode Button = Change glow properties"))
+ to_chat(usr, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/light_maker/Configurate()
+ var/choice = alert("Change the new light range, power, or color?", "Light Maker", "Range", "Power", "Color", "Cancel")
+ switch(choice)
+ if("Range")
+ var/input = input("New light range.", name, light_range) as null|num
+ if(input)
+ light_range = input
+ if("Power")
+ var/input = input("New light power.", name, light_power) as null|num
+ if(input)
+ light_power = input
+ if("Color")
+ var/input = input("New light color.", name, light_color) as null|color
+ if(input)
+ light_color = input
+
+/datum/build_mode/light_maker/OnClick(var/atom/A, var/list/parameters)
+ if(parameters["left"])
+ if(A)
+ A.set_light(light_range, light_power, light_color)
+ if(parameters["right"])
+ if(A)
+ A.set_light(0, 0, COLOR_WHITE)
diff --git a/code/modules/admin/buildmode/move_into.dm b/code/modules/admin/buildmode/move_into.dm
new file mode 100644
index 00000000000..8ad6e00a8c6
--- /dev/null
+++ b/code/modules/admin/buildmode/move_into.dm
@@ -0,0 +1,46 @@
+/datum/build_mode/move_into
+ name = "Move Into"
+ icon_state = "buildmode7"
+
+ var/atom/destination
+
+/datum/build_mode/move_into/Destroy()
+ ClearDestination()
+ . = ..()
+
+/datum/build_mode/move_into/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Left Click = Select destination"))
+ to_chat(user, SPAN_NOTICE("Right Click on Movable Atom = Move target into destination"))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/move_into/OnClick(var/atom/movable/A, var/list/parameters)
+ if(parameters["left"])
+ SetDestination(A)
+ if(parameters["right"])
+ if(!destination)
+ to_chat(user, SPAN_WARNING("No target destination."))
+ else if(!ismovable(A))
+ to_chat(user, SPAN_WARNING("\The [A] must be of type /atom/movable."))
+ else
+ to_chat(user, SPAN_NOTICE("Moved \the [A] into \the [destination]."))
+ Log("Moved '[log_info_line(A)]' into '[log_info_line(destination)]'.")
+ A.forceMove(destination)
+
+/datum/build_mode/move_into/proc/SetDestination(var/atom/A)
+ if(A == destination)
+ return
+ ClearDestination()
+
+ destination = A
+ GLOB.destroyed_event.register(destination, src, /datum/build_mode/move_into/proc/ClearDestination)
+ to_chat(user, SPAN_NOTICE("Will now move targets into \the [destination]."))
+
+/datum/build_mode/move_into/proc/ClearDestination(var/feedback)
+ if(!destination)
+ return
+
+ GLOB.destroyed_event.unregister(destination, src, /datum/build_mode/move_into/proc/ClearDestination)
+ destination = null
+ if(feedback)
+ Warn("The selected destination was deleted.")
diff --git a/code/modules/admin/buildmode/relocate_to.dm b/code/modules/admin/buildmode/relocate_to.dm
new file mode 100644
index 00000000000..86e827e1e15
--- /dev/null
+++ b/code/modules/admin/buildmode/relocate_to.dm
@@ -0,0 +1,47 @@
+/datum/build_mode/relocate_to
+ name = "Relocate To"
+ icon_state = "buildmode9"
+ var/atom/movable/to_relocate
+
+/datum/build_mode/relocate_to/Destroy()
+ ClearRelocator()
+ . = ..()
+
+/datum/build_mode/relocate_to/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Left Click on Movable Atom = Select object to be relocated"))
+ to_chat(user, SPAN_NOTICE("Right Click on Turf = Destination to be relocated to"))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/relocate_to/OnClick(var/atom/A, var/list/parameters)
+ if(parameters["left"])
+ if(istype(A, /atom/movable))
+ SetRelocator(A)
+ else if(parameters["right"])
+ if(to_relocate)
+ var/destination_turf = get_turf(A)
+ if(destination_turf)
+ to_relocate.forceMove(destination_turf)
+ Log("Relocated '[log_info_line(to_relocate)]' to '[log_info_line(destination_turf)]'")
+ else
+ to_chat(user, SPAN_WARNING("Unable to locate destination turf."))
+ else
+ to_chat(user, SPAN_WARNING("You have nothing selected to relocate."))
+
+/datum/build_mode/relocate_to/proc/SetRelocator(var/new_relocator)
+ if(to_relocate == new_relocator)
+ return
+ ClearRelocator()
+
+ to_relocate = new_relocator
+ RegisterSignal(to_relocate, COMSIG_QDELETING, PROC_REF(ClearRelocator))
+ to_chat(user, SPAN_NOTICE("Will now be relocating \the [to_relocate]."))
+
+/datum/build_mode/relocate_to/proc/ClearRelocator(var/feedback)
+ if(!to_relocate)
+ return
+
+ UnregisterSignal(to_relocate, COMSIG_QDELETING)
+ to_relocate = null
+ if(feedback)
+ Warn("The selected relocation object was deleted.")
diff --git a/code/modules/admin/buildmode/room_builder.dm b/code/modules/admin/buildmode/room_builder.dm
new file mode 100644
index 00000000000..c4e3a5f3ade
--- /dev/null
+++ b/code/modules/admin/buildmode/room_builder.dm
@@ -0,0 +1,91 @@
+/datum/build_mode/room_builder
+ name = "Room Builder"
+ icon_state = "buildmode5"
+
+ var/turf/coordinate_A
+ var/turf/coordinate_B
+
+ var/floor_type = /turf/simulated/floor/plating
+ var/wall_type = /turf/simulated/wall
+
+/datum/build_mode/room_builder/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Left Click on Turf = Select as point A"))
+ to_chat(user, SPAN_NOTICE("Right Click on Turf = Select as point B"))
+ to_chat(user, SPAN_NOTICE("As soon as both points have been selected, the room is created."))
+ to_chat(user, "")
+ to_chat(user, SPAN_NOTICE("Right Click on Build Mode Button = Change floor/wall type"))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/room_builder/Configurate()
+ var/choice = alert("Would you like to set the floor or wall type?", name, "Floor", "Wall", "Cancel")
+ switch(choice)
+ if("Floor")
+ floor_type = select_subpath(floor_type) || floor_type
+ to_chat(user, SPAN_NOTICE("Floor type set to [floor_type]."))
+ if("Wall")
+ wall_type = select_subpath(wall_type) || wall_type
+ to_chat(user, SPAN_NOTICE("Wall type set to [wall_type]."))
+
+/datum/build_mode/room_builder/OnClick(var/atom/A, var/list/parameters)
+ if(parameters["left"])
+ coordinate_A = get_turf(A)
+ to_chat(user, SPAN_NOTICE("Defined [coordinate_A] ([coordinate_A.type]) as point A."))
+ if(parameters["right"])
+ coordinate_B = get_turf(A)
+ to_chat(user, SPAN_NOTICE("Defined [coordinate_B] ([coordinate_B.type]) as point B."))
+
+ if(coordinate_A && coordinate_B)
+ to_chat(user, SPAN_NOTICE("Room coordinates set. Building room."))
+ Log("Created a room with wall type [wall_type] and floor type [floor_type] from [log_info_line(coordinate_A)] to [log_info_line(coordinate_B)]")
+ make_rectangle(coordinate_A, coordinate_B, wall_type, floor_type)
+ coordinate_A = null
+ coordinate_B = null
+
+/datum/build_mode/room_builder/proc/make_rectangle(var/turf/A, var/turf/B, var/turf/wall_type, var/turf/floor_type)
+ if(!A || !B) // No coords
+ return
+ if(A.z != B.z) // Not same z-level
+ return
+
+ var/height = A.y - B.y
+ var/width = A.x - B.x
+ var/z_level = A.z
+
+ var/turf/lower_left_corner = null
+ // First, try to find the lowest part
+ var/desired_y = 0
+ if(A.y <= B.y)
+ desired_y = A.y
+ else
+ desired_y = B.y
+
+ //Now for the left-most part.
+ var/desired_x = 0
+ if(A.x <= B.x)
+ desired_x = A.x
+ else
+ desired_x = B.x
+
+ lower_left_corner = locate(desired_x, desired_y, z_level)
+
+ // Now we can begin building the actual room. This defines the boundries for the room.
+ var/low_bound_x = lower_left_corner.x
+ var/low_bound_y = lower_left_corner.y
+
+ var/high_bound_x = lower_left_corner.x + abs(width)
+ var/high_bound_y = lower_left_corner.y + abs(height)
+
+ for(var/i = low_bound_x, i <= high_bound_x, i++)
+ for(var/j = low_bound_y, j <= high_bound_y, j++)
+ var/turf/T = locate(i, j, z_level)
+ if(i == low_bound_x || i == high_bound_x || j == low_bound_y || j == high_bound_y)
+ if(ispath(wall_type, /turf))
+ T.ChangeTurf(wall_type)
+ else
+ new wall_type(T)
+ else
+ if(ispath(floor_type, /turf))
+ T.ChangeTurf(floor_type)
+ else
+ new floor_type(T)
diff --git a/code/modules/admin/buildmode/throw_at.dm b/code/modules/admin/buildmode/throw_at.dm
new file mode 100644
index 00000000000..0e03c4b4bf1
--- /dev/null
+++ b/code/modules/admin/buildmode/throw_at.dm
@@ -0,0 +1,46 @@
+/datum/build_mode/throw_at
+ name = "Throw At"
+ icon_state = "buildmode4"
+ var/atom/movable/to_throw
+
+/datum/build_mode/throw_at/Destroy()
+ ClearThrowable()
+ . = ..()
+
+/datum/build_mode/throw_at/Help()
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+ to_chat(user, SPAN_NOTICE("Left Click on Movable Atom = Select object to be thrown"))
+ to_chat(user, SPAN_NOTICE("Right Click on Atom = Throw at the target"))
+ to_chat(user, SPAN_NOTICE("***********************************************************"))
+
+/datum/build_mode/throw_at/OnClick(var/atom/A, var/list/parameters)
+ if(parameters["left"])
+ if(istype(A, /atom/movable))
+ SetThrowable(A)
+ else if(parameters["right"])
+ if(to_throw)
+ if(!isturf(to_throw.loc))
+ to_chat(user, SPAN_WARNING("\The [to_throw] is currently not on a turf and cannot be thrown."))
+ else
+ to_throw.throw_at(A, 10, 1)
+ Log("Threw '[log_info_line(to_throw)]' at '[log_info_line(A)]'")
+ else
+ to_chat(user, SPAN_WARNING("You have nothing selected to throw."))
+
+/datum/build_mode/throw_at/proc/SetThrowable(var/new_throwable)
+ if(to_throw == new_throwable)
+ return
+ ClearThrowable()
+
+ to_throw = new_throwable
+ RegisterSignal(to_throw, COMSIG_QDELETING, PROC_REF(ClearThrowable))
+ to_chat(user, SPAN_NOTICE("Will now be throwing \the [to_throw]."))
+
+/datum/build_mode/throw_at/proc/ClearThrowable(var/feedback)
+ if(!to_throw)
+ return
+
+ UnregisterSignal(to_throw, COMSIG_QDELETING)
+ to_throw = null
+ if(feedback)
+ Warn("The selected throwing object was deleted.")
diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm
deleted file mode 100644
index 29bcfc84a22..00000000000
--- a/code/modules/admin/verbs/buildmode.dm
+++ /dev/null
@@ -1,355 +0,0 @@
-/proc/togglebuildmode(mob/M as mob in GLOB.player_list)
- set name = "Toggle Build Mode"
- set category = "Special Verbs"
- if(M.client)
- if(M.client.buildmode)
- log_admin("[key_name(usr)] has left build mode.",admin_key=key_name(usr))
- M.client.buildmode = 0
- M.client.show_popup_menus = 1
- remove_verb(M, /verb/load_template_verb)
- for(var/obj/effect/bmode/buildholder/H)
- if(H.cl == M.client)
- qdel(H)
- else
- log_admin("[key_name(usr)] has entered build mode.",admin_key=key_name(usr))
- M.client.buildmode = 1
- M.client.show_popup_menus = 0
- add_verb(M, /verb/load_template_verb)
- var/obj/effect/bmode/buildholder/H = new/obj/effect/bmode/buildholder()
- var/obj/effect/bmode/builddir/A = new/obj/effect/bmode/builddir(H)
- A.master = H
- var/obj/effect/bmode/buildhelp/B = new/obj/effect/bmode/buildhelp(H)
- B.master = H
- var/obj/effect/bmode/buildmode/C = new/obj/effect/bmode/buildmode(H)
- C.master = H
- var/obj/effect/bmode/buildquit/D = new/obj/effect/bmode/buildquit(H)
- D.master = H
- var/obj/effect/bmode/template/E = new/obj/effect/bmode/template(H)
- E.master = H
-
- H.builddir = A
- H.buildhelp = B
- H.buildmode = C
- H.buildquit = D
- H.load_template = E
- M.client.screen += A
- M.client.screen += B
- M.client.screen += C
- M.client.screen += D
- M.client.screen += E
- H.cl = M.client
-
-/obj/effect/bmode//Cleaning up the tree a bit
- density = 1
- anchored = 1
- layer = HUD_BASE_LAYER
- dir = NORTH
- icon = 'icons/misc/buildmode.dmi'
- mouse_opacity = MOUSE_OPACITY_OPAQUE
- var/obj/effect/bmode/buildholder/master
-
-/obj/effect/bmode/Destroy()
- if(master && master.cl)
- master.cl.screen -= src
- master = null
- return ..()
-
-/obj/effect/bmode/builddir
- icon_state = "build"
- screen_loc = "NORTH,WEST"
-
-/obj/effect/bmode/builddir/Click()
- switch(dir)
- if(NORTH)
- set_dir(EAST)
- if(EAST)
- set_dir(SOUTH)
- if(SOUTH)
- set_dir(WEST)
- if(WEST)
- set_dir(NORTHWEST)
- if(NORTHWEST)
- set_dir(NORTH)
- return 1
-
-/obj/effect/bmode/buildhelp
- icon = 'icons/misc/buildmode.dmi'
- icon_state = "buildhelp"
- screen_loc = "NORTH,WEST+1"
-
-/obj/effect/bmode/buildhelp/Click()
- switch(master.cl.buildmode)
- if(1)
- to_chat(usr, "***********************************************************")
- to_chat(usr, "Left Mouse Button = Construct / Upgrade")
- to_chat(usr, "Right Mouse Button = Deconstruct / Delete / Downgrade")
- to_chat(usr, "Left Mouse Button + ctrl = R-Window")
- to_chat(usr, "Left Mouse Button + alt = Airlock")
- to_chat(usr, " ")
- to_chat(usr, "Use the button in the upper left corner to")
- to_chat(usr, "change the direction of built objects.")
- to_chat(usr, "***********************************************************")
- if(2)
- to_chat(usr, "***********************************************************")
- to_chat(usr, "Right Mouse Button on buildmode button = Set object type")
- to_chat(usr, "Middle Mouse Button on buildmode button= On/Off object type saying")
- to_chat(usr, "Middle Mouse Button on turf/obj = Capture object type")
- to_chat(usr, "Left Mouse Button on turf/obj = Place objects")
- to_chat(usr, "Right Mouse Button = Delete objects")
- to_chat(usr, " ")
- to_chat(usr, "Use the button in the upper left corner to")
- to_chat(usr, "change the direction of built objects.")
- to_chat(usr, "***********************************************************")
- if(3)
- to_chat(usr, "***********************************************************")
- to_chat(usr, "Right Mouse Button on buildmode button = Select var(type) & value")
- to_chat(usr, "Left Mouse Button on turf/obj/mob = Set var(type) & value")
- to_chat(usr, "Right Mouse Button on turf/obj/mob = Reset var's value")
- to_chat(usr, "***********************************************************")
- if(4)
- to_chat(usr, "***********************************************************")
- to_chat(usr, "Left Mouse Button on turf/obj/mob = Select")
- to_chat(usr, "Right Mouse Button on turf/obj/mob = Throw")
- to_chat(usr, "***********************************************************")
- return 1
-
-/obj/effect/bmode/buildquit
- icon_state = "buildquit"
- screen_loc = "NORTH,WEST+4"
-
-/obj/effect/bmode/buildquit/Click()
- togglebuildmode(master.cl.mob)
- return 1
-
-/obj/effect/bmode/buildholder
- density = 0
- anchored = 1
- var/client/cl = null
- var/obj/effect/bmode/builddir/builddir = null
- var/obj/effect/bmode/buildhelp/buildhelp = null
- var/obj/effect/bmode/buildmode/buildmode = null
- var/obj/effect/bmode/buildquit/buildquit = null
- var/obj/effect/bmode/template/load_template = null
- var/atom/movable/throw_atom = null
-
-/obj/effect/bmode/buildholder/Destroy()
- qdel(builddir)
- builddir = null
- qdel(buildhelp)
- buildhelp = null
- qdel(buildmode)
- buildmode = null
- qdel(buildquit)
- buildquit = null
- throw_atom = null
- cl = null
- return ..()
-
-/obj/effect/bmode/template
- icon_state = "load_template"
- screen_loc = "NORTH,WEST+2"
-
-/obj/effect/bmode/template/Click()
- load_template(usr)
- return 1
-
-/obj/effect/bmode/buildmode
- icon_state = "buildmode1"
- screen_loc = "NORTH,WEST+3"
- var/varholder = "name"
- var/valueholder = "derp"
- var/objholder = /obj/structure/closet
- var/objsay = 1
-
-/obj/effect/bmode/buildmode/Click(location, control, params)
- var/list/pa = params2list(params)
-
- if(pa.Find("middle"))
- switch(master.cl.buildmode)
- if(2)
- objsay=!objsay
-
-
- if(pa.Find("left"))
- switch(master.cl.buildmode)
- if(1)
- master.cl.buildmode = 2
- src.icon_state = "buildmode2"
- if(2)
- master.cl.buildmode = 3
- src.icon_state = "buildmode3"
- if(3)
- master.cl.buildmode = 4
- src.icon_state = "buildmode4"
- if(4)
- master.cl.buildmode = 1
- src.icon_state = "buildmode1"
-
- else if(pa.Find("right"))
- switch(master.cl.buildmode)
- if(1)
- return 1
- if(2)
- objholder = text2path(input(usr,"Enter typepath:" ,"Typepath","/obj/structure/closet"))
- if(!ispath(objholder))
- objholder = /obj/structure/closet
- alert("That path is not allowed.")
- else
- if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0))
- objholder = /obj/structure/closet
- if(3)
- var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine")
-
- master.buildmode.varholder = input(usr,"Enter variable name:" ,"Name", "name")
- if(master.buildmode.varholder in locked && !check_rights(R_DEBUG,0))
- return 1
- var/thetype = input(usr,"Select variable type:" ,"Type") in list("text","number","mob-reference","obj-reference","turf-reference")
- if(!thetype) return 1
- switch(thetype)
- if("text")
- master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value", "value") as text
- if("number")
- master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value", 123) as num
- if("mob-reference")
- master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as mob in GLOB.mob_list
- if("obj-reference")
- master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as obj in world
- if("turf-reference")
- master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as turf in world
- return 1
-
-/proc/build_click(var/mob/user, buildmode, params, var/obj/object)
- var/obj/effect/bmode/buildholder/holder = null
- for(var/obj/effect/bmode/buildholder/H)
- if(H.cl == user.client)
- holder = H
- break
- if(!holder) return
- var/list/pa = params2list(params)
-
- switch(buildmode)
- if(1)
- if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") )
- if(istype(object,/turf/space))
- var/turf/T = object
- T.ChangeTurf(/turf/simulated/floor)
- return
- else if(istype(object,/turf/simulated/floor))
- var/turf/T = object
- T.ChangeTurf(/turf/simulated/wall)
- return
- else if(istype(object,/turf/simulated/wall))
- var/turf/T = object
- T.ChangeTurf(/turf/simulated/wall/r_wall)
- return
- else if(pa.Find("right"))
- if(istype(object,/turf/simulated/wall))
- var/turf/T = object
- T.ChangeTurf(/turf/simulated/floor)
- return
- else if(istype(object,/turf/simulated/floor))
- var/turf/T = object
- T.ChangeTurf(/turf/space)
- return
- else if(istype(object,/turf/simulated/wall/r_wall))
- var/turf/T = object
- T.ChangeTurf(/turf/simulated/wall)
- return
- else if(istype(object,/obj))
- qdel(object)
- return
- else if(istype(object,/turf) && pa.Find("alt") && pa.Find("left"))
- new/obj/machinery/door/airlock(get_turf(object))
- else if(istype(object,/turf) && pa.Find("ctrl") && pa.Find("left"))
- switch(holder.builddir.dir)
- if(NORTH)
- var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
- WIN.set_dir(NORTH)
- if(SOUTH)
- var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
- WIN.set_dir(SOUTH)
- if(EAST)
- var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
- WIN.set_dir(EAST)
- if(WEST)
- var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
- WIN.set_dir(WEST)
- if(NORTHWEST)
- var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object))
- WIN.set_dir(NORTHWEST)
- if(2)
- if(pa.Find("left"))
- if(ispath(holder.buildmode.objholder,/turf))
- var/turf/T = get_turf(object)
- T.ChangeTurf(holder.buildmode.objholder)
- else
- var/obj/A = new holder.buildmode.objholder (get_turf(object))
- A.set_dir(holder.builddir.dir)
- else if(pa.Find("right"))
- if(isobj(object)) qdel(object)
- if(pa.Find("middle"))
- holder.buildmode.objholder = text2path("[object.type]")
- if(holder.buildmode.objsay) to_chat(usr, "[object.type]")
-
-
- if(3)
- if(pa.Find("left")) //I cant believe this shit actually compiles.
- if(object.vars.Find(holder.buildmode.varholder))
- log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]",admin_key=key_name(usr))
- object.vars[holder.buildmode.varholder] = holder.buildmode.valueholder
- else
- to_chat(usr, "[initial(object.name)] does not have a var called '[holder.buildmode.varholder]'")
- if(pa.Find("right"))
- if(object.vars.Find(holder.buildmode.varholder))
- log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]",admin_key=key_name(usr))
- object.vars[holder.buildmode.varholder] = initial(object.vars[holder.buildmode.varholder])
- else
- to_chat(usr, "[initial(object.name)] does not have a var called '[holder.buildmode.varholder]'")
-
- if(4)
- if(pa.Find("left"))
- if(istype(object, /atom/movable))
- holder.throw_atom = object
- if(pa.Find("right"))
- if(holder.throw_atom)
- holder.throw_atom.throw_at(object, 10, 1)
- log_admin("[key_name(usr)] threw [holder.throw_atom] at [object]",admin_key=key_name(usr))
-
-/verb/load_template_verb()
- set name = "Load Template"
- set category = "Special Verbs"
- if(!usr)
- return
- load_template(usr)
-
-/proc/load_template(var/mob/user)
- if(!user)
- return
-
- if(!check_rights(R_SPAWN))
- return
-
- var/list/templates
- try
- templates = json_decode(return_file_text("config/templates_list.json"))
- catch(var/exception/ej)
- LOG_DEBUG("Warning: Could not load the templates config as templates_list.json is missing - [ej]")
- return
-
- if(!templates || !templates["templates_list"] || templates["templates_folder"] == "")
- return
-
- var/turf/T = get_turf(user)
- var/name = input(user, "Which template would you like to load?", "Load Template", null) as null|anything in templates["templates_list"]
-
- if (!name || !T)
- return
-
- var/datum/map_template/maploader = new (templates["templates_folder"] + name, name)
- if (!maploader)
- LOG_DEBUG("Error, unable to load maploader in proc load_template!")
- return
-
- var/centered = input(user, "Do you want template to load as center or Edge?", "Load Template", null) as null|anything in list("Center", "Edge")
- maploader.load(T, centered == "Center" ? TRUE : FALSE)
- log_and_message_admins("[key_name_admin(user)] has loaded template [name].", user, T)
diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm
index 4ef682386e4..62b554097e4 100644
--- a/code/modules/admin/view_variables/topic.dm
+++ b/code/modules/admin/view_variables/topic.dm
@@ -123,17 +123,6 @@
src.cmd_admin_dust(M)
- else if(href_list["build_mode"])
- if(!check_rights(R_BUILDMODE|R_DEV)) return
-
- var/mob/M = locate(href_list["build_mode"])
- if(!istype(M))
- to_chat(usr, "This can only be used on instances of type /mob")
- return
-
- togglebuildmode(M)
- href_list["datumrefresh"] = href_list["build_mode"]
-
else if(href_list["drop_everything"])
if(!check_rights(R_DEBUG|R_ADMIN)) return
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index 43ca7e43fde..2721e4fde7b 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -8,7 +8,6 @@
// Admin
var/datum/admins/holder = null
var/datum/admins/deadmin_holder = null
- var/buildmode = 0
// Spam Protection
var/last_message = "" // Contains the last message sent by this client - used to protect against copy-paste spamming.
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 59025cfe6e3..805b329e170 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -819,11 +819,6 @@ var/list/localhost_addresses = list(
autofire_aiming_at[1] = over_object
autofire_aiming_at[2] = params
var/mob/living/M = mob
- if(istype(get_turf(over_object), /atom))
- var/atom/A = get_turf(over_object)
- if(src && src.buildmode)
- build_click(M, src.buildmode, params, A)
- return
if(istype(M) && !M.incapacitated())
var/obj/item/I = M.get_active_hand()
diff --git a/code/unit_tests/create_and_destroy.dm b/code/unit_tests/create_and_destroy.dm
index ed5a17ea6c3..a27655652d1 100644
--- a/code/unit_tests/create_and_destroy.dm
+++ b/code/unit_tests/create_and_destroy.dm
@@ -159,6 +159,7 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE)
ignore += typesof(/mob/living/heavy_vehicle)
ignore += typesof(/obj/singularity/narsie)
ignore += typesof(/obj/screen/ability)
+ ignore += typesof(/obj/effect/bmode)
// Requires something in icon update or runtimes
ignore += typesof(/obj/item/gun/energy/gun/nuclear)
diff --git a/html/changelogs/RustingWithYou - click.yml b/html/changelogs/RustingWithYou - click.yml
new file mode 100644
index 00000000000..b58f9871730
--- /dev/null
+++ b/html/changelogs/RustingWithYou - click.yml
@@ -0,0 +1,41 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+# balance
+# admin
+# backend
+# security
+# refactor
+#################################
+
+# Your name.
+author: RustingWithYou
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Ports Baystation click handlers and build mode."
diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi
index 269b266e858..2550a1a486c 100644
Binary files a/icons/misc/buildmode.dmi and b/icons/misc/buildmode.dmi differ