diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 6cd11bcfc534..5fd925b54cf7 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -460,3 +460,6 @@ GLOBAL_LIST_INIT(pda_styles, list(MONO, VT, ORBITRON, SHARE)) #define CAMERA_SEE_GHOSTS_ORBIT 2 #define CLIENT_FROM_VAR(I) (ismob(I) ? I:client : (istype(I, /client) ? I : (istype(I, /datum/mind) ? I:current?:client : null))) + +#define AREASELECT_CORNERA "corner A" +#define AREASELECT_CORNERB "corner B" diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 59598b9d7f70..0c0146871216 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -10,9 +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(check_click_intercept(params,A)) - return - if(control_disabled || incapacitated()) return diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 63e1a14aa66f..6cacc90fcb5f 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -1,7 +1,4 @@ /mob/dead/observer/DblClickOn(var/atom/A, var/params) - if(check_click_intercept(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) diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm deleted file mode 100644 index 1c8002943d44..000000000000 --- a/code/modules/admin/verbs/buildmode.dm +++ /dev/null @@ -1,394 +0,0 @@ -#define BASIC_BUILDMODE 1 -#define ADV_BUILDMODE 2 -#define VAR_BUILDMODE 3 -#define THROW_BUILDMODE 4 -#define AREA_BUILDMODE 5 -#define COPY_BUILDMODE 6 -#define NUM_BUILDMODES 6 - -//Buildmode Shuttle -//Builmode Move - -/obj/screen/buildmode - icon = 'icons/misc/buildmode.dmi' - var/datum/buildmode/bd - -/obj/screen/buildmode/New(bd) - ..() - src.bd = bd - -/obj/screen/buildmode/Destroy() - bd.buttons -= src - bd = null - return ..() - -/obj/screen/buildmode/mode - icon_state = "buildmode1" - name = "Toggle Mode" - screen_loc = "NORTH,WEST" - -/obj/screen/buildmode/mode/Click(location, control, params) - var/list/pa = params2list(params) - - if(pa.Find("left")) - bd.toggle_modes() - else if(pa.Find("right")) - bd.change_settings(usr) - update_icon() - return 1 - -/obj/screen/buildmode/mode/update_icon() - icon_state = "buildmode[bd.mode]" - return - -/obj/screen/buildmode/help - icon_state = "buildhelp" - screen_loc = "NORTH,WEST+1" - name = "Buildmode Help" - -/obj/screen/buildmode/help/Click() - bd.show_help(usr) - return 1 - -/obj/screen/buildmode/bdir - icon_state = "build" - screen_loc = "NORTH,WEST+2" - name = "Change Dir" - - -/obj/screen/buildmode/bdir/update_icon() - setDir(bd.build_dir) - return - -/obj/screen/buildmode/quit - icon_state = "buildquit" - screen_loc = "NORTH,WEST+3" - name = "Quit Buildmode" - -/obj/screen/buildmode/quit/Click() - bd.quit() - return 1 - -/obj/screen/buildmode/bdir/Click() - bd.change_dir() - update_icon() - return 1 - -/datum/buildmode - var/mode = BASIC_BUILDMODE - var/client/holder = null - var/list/obj/screen/buttons = list() - var/build_dir = SOUTH - var/atom/movable/throw_atom = null - var/turf/cornerA = null - var/turf/cornerB = null - var/generator_path = null - var/varholder = "name" - var/valueholder = "derp" - var/objholder = /obj/structure/closet - var/atom/movable/stored = null - var/list/preview = list() - -/datum/buildmode/New(client/c) - create_buttons() - holder = c - holder.click_intercept = src - holder.show_popup_menus = 0 - holder.screen += buttons - -/datum/buildmode/proc/quit() - holder.screen -= buttons - holder.click_intercept = null - holder.show_popup_menus = 1 - usr.client.images -= preview - preview.Cut() - qdel(src) - return - -/datum/buildmode/Destroy() - stored = null - QDEL_LIST(buttons) - throw_atom = null - holder = null - preview.Cut() - cornerA = null - cornerB = null - return ..() - -/datum/buildmode/proc/create_buttons() - buttons += new /obj/screen/buildmode/mode(src) - buttons += new /obj/screen/buildmode/help(src) - buttons += new /obj/screen/buildmode/bdir(src) - buttons += new /obj/screen/buildmode/quit(src) - -/datum/buildmode/proc/toggle_modes() - mode = (mode % NUM_BUILDMODES) +1 - Reset() - return - -/datum/buildmode/proc/show_help(mob/user) - var/list/dat = list() - switch(mode) - if(BASIC_BUILDMODE) - dat += "***********************************************************" - dat += "Left Mouse Button = Construct / Upgrade" - dat += "Right Mouse Button = Deconstruct / Delete / Downgrade" - dat += "Left Mouse Button + ctrl = R-Window" - dat += "Left Mouse Button + alt = Airlock" - dat += "" - dat += "Use the button in the upper left corner to" - dat += "change the direction of built objects." - dat += "***********************************************************" - if(ADV_BUILDMODE) - dat += "***********************************************************" - dat += "Right Mouse Button on buildmode button = Set object type" - dat += "Left Mouse Button + alt on turf/obj = Copy object type" - dat += "Left Mouse Button on turf/obj = Place objects" - dat += "Right Mouse Button = Delete objects" - dat += "" - dat += "Use the button in the upper left corner to" - dat += "change the direction of built objects." - dat += "***********************************************************" - if(VAR_BUILDMODE) - dat += "***********************************************************" - dat += "Right Mouse Button on buildmode button = Select var(type) & value" - dat += "Left Mouse Button on turf/obj/mob = Set var(type) & value" - dat += "Right Mouse Button on turf/obj/mob = Reset var's value" - dat += "***********************************************************" - if(THROW_BUILDMODE) - dat += "***********************************************************" - dat += "Left Mouse Button on turf/obj/mob = Select" - dat += "Right Mouse Button on turf/obj/mob = Throw" - dat += "***********************************************************" - if(AREA_BUILDMODE) - dat += "***********************************************************" - dat += "Left Mouse Button on turf/obj/mob = Select corner" - dat += "Right Mouse Button on turf/obj/mob = Reset corner selection" - dat += "Right Mouse Button on buildmode button = Select generator" - dat += "***********************************************************" - if(COPY_BUILDMODE) - dat += "***********************************************************" - dat += "Left Mouse Button on obj/turf/mob = Spawn a Copy of selected target" - dat += "Right Mouse Button on obj/mob = Select target to copy" - dat += "***********************************************************" - to_chat(user, "[dat.Join("\n")]") - -/datum/buildmode/proc/change_settings(mob/user) - switch(mode) - if(BASIC_BUILDMODE) - return 1 - if(ADV_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) - 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(VAR_BUILDMODE) - var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "viruses", "cuffed", "ka", "last_eaten", "urine") - - varholder = input(user,"Enter variable name:" ,"Name", "name") - if(varholder in locked && !check_rights(R_DEBUG,0)) - return 1 - var/thetype = input(user,"Select variable type:" ,"Type") in list("text","number","mob-reference","obj-reference","turf-reference") - if(!thetype) - return 1 - switch(thetype) - if("text") - valueholder = input(user,"Enter variable value:" ,"Value", "value") as text - if("number") - valueholder = input(user,"Enter variable value:" ,"Value", 123) as num - if("mob-reference") - valueholder = input(user,"Enter variable value:" ,"Value") as mob in GLOB.mob_list - if("obj-reference") - valueholder = input(user,"Enter variable value:" ,"Value") as obj in world - if("turf-reference") - valueholder = input(user,"Enter variable value:" ,"Value") as turf in world - if(AREA_BUILDMODE) - var/list/gen_paths = subtypesof(/datum/mapGenerator) - var/list/options = list() - for(var/path in gen_paths) - var/datum/mapGenerator/MP = path - options[initial(MP.buildmode_name)] = path - var/type = input(user,"Select Generator Type","Type") as null|anything in options - if(!type) - return - - generator_path = options[type] - cornerA = null - cornerB = null - -/datum/buildmode/proc/change_dir() - switch(build_dir) - if(NORTH) - build_dir = EAST - if(EAST) - build_dir = SOUTH - if(SOUTH) - build_dir = WEST - if(WEST) - build_dir = NORTHWEST - if(NORTHWEST) - build_dir = NORTH - return 1 - -/datum/buildmode/proc/Reset()//Reset temporary variables - cornerA = null - cornerB = null - -/proc/togglebuildmode(mob/M in GLOB.player_list) - set name = "Toggle Build Mode" - set category = "Special Verbs" - if(M.client) - if(istype(M.client.click_intercept, /datum/buildmode)) - var/datum/buildmode/B = M.client.click_intercept - B.quit() - log_admin("[key_name(usr)] has left build mode.") - else - new/datum/buildmode(M.client) - message_admins("[key_name(usr)] has entered build mode.") - log_admin("[key_name(usr)] has entered build mode.") - - -/datum/buildmode/proc/InterceptClickOn(user,params,atom/object) //Click Intercept - var/list/pa = params2list(params) - var/right_click = pa.Find("right") - var/left_click = pa.Find("left") - var/alt_click = pa.Find("alt") - var/ctrl_click = pa.Find("ctrl") - - //Clicking on UI elements shouldn't try to build things in nullspace. - if(istype(object,/obj/screen)) - return FALSE - - . = TRUE - switch(mode) - if(BASIC_BUILDMODE) - if(isturf(object) && left_click && !alt_click && !ctrl_click) - var/turf/T = object - if(isspaceturf(object)) - T.PlaceOnTop(/turf/open/floor/plating) - else if(isplatingturf(object)) - T.PlaceOnTop(/turf/open/floor/plasteel) - else if(isfloorturf(object)) - T.PlaceOnTop(/turf/closed/wall) - else if(iswallturf(object)) - T.PlaceOnTop(/turf/closed/wall/r_wall) - log_admin("Build Mode: [key_name(user)] built [T] at [AREACOORD(T)]") - return - else if(right_click) - log_admin("Build Mode: [key_name(user)] deleted [object] at [AREACOORD(object)]") - if(isturf(object)) - var/turf/T = object - T.ScrapeAway() - else if(isobj(object)) - qdel(object) - return - else if(isturf(object) && alt_click && left_click) - log_admin("Build Mode: [key_name(user)] built an airlock at [AREACOORD(object)]") - new/obj/machinery/door/airlock(get_turf(object)) - else if(isturf(object) && ctrl_click && left_click) - var/obj/structure/window/reinforced/window - if(build_dir == NORTHWEST) - window = new /obj/structure/window/reinforced/fulltile(get_turf(object)) - else - window = new /obj/structure/window/reinforced(get_turf(object)) - window.setDir(build_dir) - log_admin("Build Mode: [key_name(user)] built a window at [AREACOORD(object)]") - if(ADV_BUILDMODE) - if(left_click && alt_click) - objholder = object.type - to_chat(user, "[initial(object.name)] ([object.type]) selected.") - else if(left_click) - if(ispath(objholder, /turf)) - var/turf/T = get_turf(object) - log_admin("Build Mode: [key_name(user)] modified [T] in [AREACOORD(object)] to [objholder]") - T.PlaceOnTop(objholder) - else - var/obj/A = new objholder (get_turf(object)) - A.setDir(build_dir) - log_admin("Build Mode: [key_name(user)] modified [A]'s [COORD(A)] dir to [build_dir]") - else if(right_click) - if(isobj(object)) - log_admin("Build Mode: [key_name(user)] deleted [object] at [AREACOORD(object)]") - qdel(object) - - if(VAR_BUILDMODE) - if(left_click) //I cant believe this shit actually compiles. - if(object.vars.Find(varholder)) - if(object.vv_edit_var(varholder, valueholder)) - log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [valueholder]") - else - to_chat(user, "Varedit rejected") - else - to_chat(user, "[initial(object.name)] does not have a var called '[varholder]'") - if(right_click) - if(object.vars.Find(varholder)) - if(object.vv_edit_var(varholder, initial(object.vars[varholder]))) - log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [valueholder]") - else - to_chat(user, "Varedit rejected") - else - to_chat(user, "[initial(object.name)] does not have a var called '[varholder]'") - - if(THROW_BUILDMODE) - if(left_click) - if(isturf(object)) - return - throw_atom = object - if(right_click) - if(throw_atom) - throw_atom.throw_at(object, 10, 1,user) - log_admin("Build Mode: [key_name(user)] threw [throw_atom] at [object] in [AREACOORD(object)]") - if(AREA_BUILDMODE) - if(left_click) //rectangular - if(!cornerA) - cornerA = get_turf(object) - preview += image('icons/turf/overlays.dmi',cornerA,"greenOverlay") - usr.client.images -= preview - usr.client.images += preview - return - if(cornerA && !cornerB) - cornerB = get_turf(object) - preview += image('icons/turf/overlays.dmi',cornerB,"blueOverlay") - usr.client.images -= preview - usr.client.images += preview - to_chat(user, "Region selected, if you're happy with your selection left click again, otherwise right click.") - return - if(cornerA && cornerB) - if(!generator_path) - to_chat(user, "Select generator type first.") - return - var/datum/mapGenerator/G = new generator_path - if(istype(G, /datum/mapGenerator/repair/reload_station_map)) - if(GLOB.reloading_map) - to_chat(user, "You are already reloading an area! Please wait for it to fully finish loading before trying to load another!") - return - G.defineRegion(cornerA, cornerB, 1) - for(var/t in G.map) - preview += image('icons/turf/overlays.dmi', t ,"redOverlay") - usr.client.images -= preview - usr.client.images += preview - var/confirm = alert("Are you sure you want run the map generator?", "Run generator", "Yes", "No") - if(confirm == "Yes") - G.generate() - cornerA = null - cornerB = null - usr.client.images -= preview - preview.Cut() - return - //Something wrong - Reset - cornerA = null - cornerB = null - if(COPY_BUILDMODE) - if(left_click) - var/turf/T = get_turf(object) - if(stored) - DuplicateObject(stored,perfectcopy=1,newloc=T) - else if(right_click) - if(ismovableatom(object)) // No copying turfs for now. - stored = object diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index 32a9714a2d82..4e00ace15c17 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -517,6 +517,25 @@ GLOBAL_PROTECT(VVpixelmovement) log_admin("[key_name(src)] modified [original_name]'s [objectvar]: [original_var]=[new_var]") message_admins("[key_name_admin(src)] modified [original_name]'s varlist [objectvar]: [original_var]=[new_var]") +/proc/vv_varname_lockcheck(param_var_name) + if(param_var_name in GLOB.VVlocked) + if(!check_rights(R_DEBUG)) + return FALSE + if(param_var_name in GLOB.VVckey_edit) + if(!check_rights(R_SPAWN|R_DEBUG)) + return FALSE + if(param_var_name in GLOB.VVicon_edit_lock) + if(!check_rights(R_FUN|R_DEBUG)) + return FALSE + if(param_var_name in GLOB.VVpixelmovement) + if(!check_rights(R_DEBUG)) + return FALSE + var/prompt = alert(usr, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT") + if (prompt != "Continue") + return FALSE + return TRUE + + /client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0) if(!check_rights(R_VAREDIT)) return @@ -546,26 +565,12 @@ GLOBAL_PROTECT(VVpixelmovement) return var_value = O.vars[variable] - - if(variable in GLOB.VVlocked) - if(!check_rights(R_DEBUG)) - return - if(variable in GLOB.VVckey_edit) - if(!check_rights(R_SPAWN|R_DEBUG)) - return - if(variable in GLOB.VVicon_edit_lock) - if(!check_rights(R_FUN|R_DEBUG)) - return + if(!vv_varname_lockcheck(variable)) + return if(istype(O, /datum/armor)) var/prompt = alert(src, "Editing this var changes this value on potentially thousands of items that share the same combination of armor values. If you want to edit the armor of just one item, use the \"Modify armor values\" dropdown item", "DANGER", "ABORT ", "Continue", " ABORT") if (prompt != "Continue") return - if(variable in GLOB.VVpixelmovement) - if(!check_rights(R_DEBUG)) - return - var/prompt = alert(src, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT") - if (prompt != "Continue") - return var/default = vv_get_class(variable, var_value) diff --git a/code/modules/buildmode/README.md b/code/modules/buildmode/README.md new file mode 100644 index 000000000000..1bdb6e07584c --- /dev/null +++ b/code/modules/buildmode/README.md @@ -0,0 +1,215 @@ +# Buildmode + +## Code layout + +### Buildmode + +Manager for buildmode modes. Contains logic to manage switching between each mode, and presenting a suitable user interface. + +### Effects + +Special graphics used by buildmode modes for user interface purposes. + +### Buildmode Mode + +Implementer of buildmode behaviors. + +Existing varieties: + ++ Basic + + **Description**: + + Allows creation of simple structures consisting of floors, walls, windows, and airlocks. + + **Controls**: + + + *Left click a turf*: + + "Upgrades" the turf based on the following rules below: + + + Space -> Tiled floor + + Simulated floor -> Regular wall + + Wall -> Reinforced wall + + + *Right click a turf*: + + "Downgrades" the turf based on the following rules below: + + + Reinforced wall -> Regular wall + + Wall -> Tiled floor + + Simulated floor -> Space + + + *Right click an object*: + + Deletes the clicked object. + + + *Alt+Left click a location*: + + Places an airlock at the clicked location. + + + *Ctrl+Left click a location*: + + Places a window at the clicked location. + ++ Advanced + + **Description**: + + Creates an instance of a configurable atom path where you click. + + **Controls**: + + + *Right click on the mode selector*: + + Choose a path to spawn. + + + *Left click a location* (requires chosen path): + + Place an instance of the chosen path at the location. + + + *Right click an object*: + + Delete the object. + ++ Fill + + **Description**: + + Creates an instance of an atom path on every tile in a chosen region. + + With a special control input, instead deletes everything within the region. + + **Controls**: + + + *Right click on the mode selector*: + + Choose a path to spawn. + + + *Left click on a region* (requires chosen path): + + Fill the region with the chosen path. + + + *Alt+Left click on a region*: + + Deletes everything within the region. + + + *Right click during region selection*: + + Cancel region selection. + ++ Copy + + **Description**: + + Take an existing object in the world, and place duplicates with identical attributes where you click. + + May not always work nicely - "deep" variables such as lists or datums may malfunction. + + **Controls**: + + + *Right click an existing object*: + + Select the clicked object as a template. + + + *Left click a location* (Requires a selected object as template): + + Place a duplicate of the template at the clicked location. + ++ Area Edit + + **Description**: + + Modifies and creates areas. + + The active area will be highlighted in yellow. + + **Controls**: + + + *Right click the mode selector*: + + Create a new area, and make it active. + + + *Right click an existing area*: + + Make the clicked area active. + + + *Left click a turf*: + + When an area is active, adds the turf to the active area. + ++ Var Edit + + **Description**: + + Allows for setting and resetting variables of objects with a click. + + If the object does not have the var, will do nothing and print a warning message. + + **Controls**: + + + *Right click the mode selector*: + + Choose which variable to set, and what to set it to. + + + *Left click an atom*: + + Change the clicked atom's variables as configured. + + + *Right click an atom*: + + Reset the targeted variable to its original value in the code. + ++ Map Generator + + **Description**: + + Fills rectangular regions with algorithmically generated content. Right click during region selection to cancel. + + See the `procedural_mapping` module for the generators themselves. + + **Controls**: + + + *Right-click on the mode selector*: + + Select a map generator from all the generators present in the codebase. + + + *Left click two corners of an area*: + + Use the generator to populate the region. + + + *Right click during region selection*: + + Cancel region selection. + ++ Throwing + + **Description**: + + Select an object with left click, and right click to throw it towards where you clicked. + + **Controls**: + + + *Left click on a movable atom*: + + Select the atom for throwing. + + + *Right click on a location*: + + Throw the selected atom towards that location. + ++ Boom + + **Description**: + + Make explosions where you click. + + **Controls**: + + + *Right click the mode selector*: + + Configure the explosion size. + + + *Left click a location*: + + Cause an explosion where you clicked. \ No newline at end of file diff --git a/code/modules/buildmode/bm_mode.dm b/code/modules/buildmode/bm_mode.dm new file mode 100644 index 000000000000..0c7d640fc0a2 --- /dev/null +++ b/code/modules/buildmode/bm_mode.dm @@ -0,0 +1,91 @@ +/datum/buildmode_mode + var/key = "oops" + + var/datum/buildmode/BM + + // would corner selection work better as a component? + var/use_corner_selection = FALSE + var/list/preview + var/turf/cornerA + var/turf/cornerB + +/datum/buildmode_mode/New(datum/buildmode/BM) + src.BM = BM + preview = list() + return ..() + +/datum/buildmode_mode/Destroy() + cornerA = null + cornerB = null + QDEL_LIST(preview) + preview = null + return ..() + +/datum/buildmode_mode/proc/enter_mode(datum/buildmode/BM) + return + +/datum/buildmode_mode/proc/exit_mode(datum/buildmode/BM) + return + +/datum/buildmode_mode/proc/get_button_iconstate() + return "buildmode_[key]" + +/datum/buildmode_mode/proc/show_help(client/c) + CRASH("No help defined, yell at a coder") + +/datum/buildmode_mode/proc/change_settings(client/c) + to_chat(c, "There is no configuration available for this mode") + return + +/datum/buildmode_mode/proc/Reset() + deselect_region() + +/datum/buildmode_mode/proc/select_tile(turf/T, corner_to_select) + var/overlaystate + BM.holder.images -= preview + switch(corner_to_select) + if(AREASELECT_CORNERA) + overlaystate = "greenOverlay" + if(AREASELECT_CORNERB) + overlaystate = "blueOverlay" + + var/image/I = image('icons/turf/overlays.dmi', T, overlaystate) + I.plane = ABOVE_LIGHTING_PLANE + preview += I + BM.holder.images += preview + return T + +/datum/buildmode_mode/proc/highlight_region(region) + BM.holder.images -= preview + for(var/t in region) + var/image/I = image('icons/turf/overlays.dmi', t, "redOverlay") + I.plane = ABOVE_LIGHTING_PLANE + preview += I + BM.holder.images += preview + +/datum/buildmode_mode/proc/deselect_region() + BM.holder.images -= preview + preview.Cut() + cornerA = null + cornerB = null + +/datum/buildmode_mode/proc/handle_click(client/c, params, object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + if(use_corner_selection) + if(left_click) + if(!cornerA) + cornerA = select_tile(get_turf(object), AREASELECT_CORNERA) + return + if(cornerA && !cornerB) + cornerB = select_tile(get_turf(object), AREASELECT_CORNERB) + to_chat(c, "Region selected, if you're happy with your selection left click again, otherwise right click.") + return + handle_selected_area(c, params) + deselect_region() + else + to_chat(c, "Region selection canceled!") + deselect_region() + return + +/datum/buildmode_mode/proc/handle_selected_area(client/c, params) \ No newline at end of file diff --git a/code/modules/buildmode/buildmode.dm b/code/modules/buildmode/buildmode.dm new file mode 100644 index 000000000000..b232bd212c64 --- /dev/null +++ b/code/modules/buildmode/buildmode.dm @@ -0,0 +1,161 @@ +#define BM_SWITCHSTATE_NONE 0 +#define BM_SWITCHSTATE_MODE 1 +#define BM_SWITCHSTATE_DIR 2 + +/datum/buildmode + var/build_dir = SOUTH + var/datum/buildmode_mode/mode + var/client/holder + + // login callback + var/li_cb + + // SECTION UI + var/list/buttons + + // Switching management + var/switch_state = BM_SWITCHSTATE_NONE + var/switch_width = 5 + // modeswitch UI + var/obj/screen/buildmode/mode/modebutton + var/list/modeswitch_buttons = list() + // dirswitch UI + var/obj/screen/buildmode/bdir/dirbutton + var/list/dirswitch_buttons = list() + +/datum/buildmode/New(client/c) + mode = new /datum/buildmode_mode/basic(src) + holder = c + buttons = list() + li_cb = CALLBACK(src, .proc/post_login) + holder.player_details.post_login_callbacks += li_cb + holder.show_popup_menus = FALSE + create_buttons() + holder.screen += buttons + holder.click_intercept = src + mode.enter_mode(src) + +/datum/buildmode/proc/quit() + mode.exit_mode(src) + holder.screen -= buttons + holder.click_intercept = null + holder.show_popup_menus = TRUE + qdel(src) + +/datum/buildmode/Destroy() + close_switchstates() + holder.player_details.post_login_callbacks -= li_cb + holder = null + QDEL_NULL(mode) + QDEL_LIST(modeswitch_buttons) + QDEL_LIST(dirswitch_buttons) + return ..() + +/datum/buildmode/proc/post_login() + // since these will get wiped upon login + holder.screen += buttons + // re-open the according switch mode + switch(switch_state) + if(BM_SWITCHSTATE_MODE) + open_modeswitch() + if(BM_SWITCHSTATE_DIR) + open_dirswitch() + +/datum/buildmode/proc/create_buttons() + // keep a reference so we can update it upon mode switch + modebutton = new /obj/screen/buildmode/mode(src) + buttons += modebutton + buttons += new /obj/screen/buildmode/help(src) + // keep a reference so we can update it upon dir switch + dirbutton = new /obj/screen/buildmode/bdir(src) + buttons += dirbutton + buttons += new /obj/screen/buildmode/quit(src) + // build the lists of switching buttons + build_options_grid(subtypesof(/datum/buildmode_mode), modeswitch_buttons, /obj/screen/buildmode/modeswitch) + build_options_grid(list(SOUTH,EAST,WEST,NORTH,NORTHWEST), dirswitch_buttons, /obj/screen/buildmode/dirswitch) + +// this creates a nice offset grid for choosing between buildmode options, +// because going "click click click ah hell" sucks. +/datum/buildmode/proc/build_options_grid(list/elements, list/buttonslist, buttontype) + var/pos_idx = 0 + for(var/thing in elements) + var/x = pos_idx % switch_width + var/y = FLOOR(pos_idx / switch_width, 1) + var/obj/screen/buildmode/B = new buttontype(src, thing) + // extra .5 for a nice offset look + B.screen_loc = "NORTH-[(1 + 0.5 + y*1.5)],WEST+[0.5 + x*1.5]" + buttonslist += B + pos_idx++ + +/datum/buildmode/proc/close_switchstates() + switch(switch_state) + if(BM_SWITCHSTATE_MODE) + close_modeswitch() + if(BM_SWITCHSTATE_DIR) + close_dirswitch() + +/datum/buildmode/proc/toggle_modeswitch() + if(switch_state == BM_SWITCHSTATE_MODE) + close_modeswitch() + else + close_switchstates() + open_modeswitch() + +/datum/buildmode/proc/open_modeswitch() + switch_state = BM_SWITCHSTATE_MODE + holder.screen += modeswitch_buttons + +/datum/buildmode/proc/close_modeswitch() + switch_state = BM_SWITCHSTATE_NONE + holder.screen -= modeswitch_buttons + +/datum/buildmode/proc/toggle_dirswitch() + if(switch_state == BM_SWITCHSTATE_DIR) + close_dirswitch() + else + close_switchstates() + open_dirswitch() + +/datum/buildmode/proc/open_dirswitch() + switch_state = BM_SWITCHSTATE_DIR + holder.screen += dirswitch_buttons + +/datum/buildmode/proc/close_dirswitch() + switch_state = BM_SWITCHSTATE_NONE + holder.screen -= dirswitch_buttons + +/datum/buildmode/proc/change_mode(newmode) + mode.exit_mode(src) + QDEL_NULL(mode) + close_switchstates() + mode = new newmode(src) + mode.enter_mode(src) + modebutton.update_icon() + +/datum/buildmode/proc/change_dir(newdir) + build_dir = newdir + close_dirswitch() + dirbutton.update_icon() + return 1 + +/datum/buildmode/proc/InterceptClickOn(mob/user, params, atom/object) + mode.handle_click(user.client, params, object) + return TRUE // no doing underlying actions + +/proc/togglebuildmode(mob/M as mob in GLOB.player_list) + set name = "Toggle Build Mode" + set category = "Event" + + if(M.client) + if(istype(M.client.click_intercept,/datum/buildmode)) + var/datum/buildmode/B = M.client.click_intercept + B.quit() + log_admin("[key_name(usr)] has left build mode.") + else + new /datum/buildmode(M.client) + message_admins("[key_name_admin(usr)] has entered build mode.") + log_admin("[key_name(usr)] has entered build mode.") + +#undef BM_SWITCHSTATE_NONE +#undef BM_SWITCHSTATE_MODE +#undef BM_SWITCHSTATE_DIR \ No newline at end of file diff --git a/code/modules/buildmode/buttons.dm b/code/modules/buildmode/buttons.dm new file mode 100644 index 000000000000..e72dbde06438 --- /dev/null +++ b/code/modules/buildmode/buttons.dm @@ -0,0 +1,90 @@ +/obj/screen/buildmode + icon = 'icons/misc/buildmode.dmi' + var/datum/buildmode/bd + // If we don't do this, we get occluded by item action buttons + layer = ABOVE_HUD_LAYER + +/obj/screen/buildmode/New(bld) + bd = bld + return ..() + +/obj/screen/buildmode/Destroy() + bd = null + return ..() + +/obj/screen/buildmode/mode + name = "Toggle Mode" + icon_state = "buildmode_basic" + screen_loc = "NORTH,WEST" + +/obj/screen/buildmode/mode/Click(location, control, params) + var/list/pa = params2list(params) + + if(pa.Find("left")) + bd.toggle_modeswitch() + else if(pa.Find("right")) + bd.mode.change_settings(usr.client) + update_icon() + return 1 + +/obj/screen/buildmode/mode/update_icon() + icon_state = bd.mode.get_button_iconstate() + +/obj/screen/buildmode/help + icon_state = "buildhelp" + screen_loc = "NORTH,WEST+1" + name = "Buildmode Help" + +/obj/screen/buildmode/help/Click(location, control, params) + bd.mode.show_help(usr.client) + return 1 + +/obj/screen/buildmode/bdir + icon_state = "build" + screen_loc = "NORTH,WEST+2" + name = "Change Dir" + +/obj/screen/buildmode/bdir/update_icon() + dir = bd.build_dir + return + +/obj/screen/buildmode/bdir/Click() + bd.toggle_dirswitch() + update_icon() + return 1 + +// used to switch between modes +/obj/screen/buildmode/modeswitch + var/datum/buildmode_mode/modetype + +/obj/screen/buildmode/modeswitch/New(bld, mt) + modetype = mt + icon_state = "buildmode_[initial(modetype.key)]" + name = initial(modetype.key) + return ..(bld) + +/obj/screen/buildmode/modeswitch/Click() + bd.change_mode(modetype) + return 1 + +// used to switch between dirs +/obj/screen/buildmode/dirswitch + icon_state = "build" + +/obj/screen/buildmode/dirswitch/New(bld, dir) + src.dir = dir + name = dir2text(dir) + return ..(bld) + +/obj/screen/buildmode/dirswitch/Click() + bd.change_dir(dir) + return 1 + +/obj/screen/buildmode/quit + icon_state = "buildquit" + screen_loc = "NORTH,WEST+3" + name = "Quit Buildmode" + +/obj/screen/buildmode/quit/Click() + bd.quit() + return 1 \ No newline at end of file diff --git a/code/modules/buildmode/effects/line.dm b/code/modules/buildmode/effects/line.dm new file mode 100644 index 000000000000..60191de93497 --- /dev/null +++ b/code/modules/buildmode/effects/line.dm @@ -0,0 +1,28 @@ +/obj/effect/buildmode_line + var/image/I + var/client/cl + +/obj/effect/buildmode_line/New(client/C, atom/atom_a, atom/atom_b, 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/mat = matrix() + mat.Translate(0, 16) + mat.Scale(1, sqrt((x_offset * x_offset) + (y_offset * y_offset)) / 32) + mat.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. + mat.Translate(atom_a.pixel_x, atom_a.pixel_y) + + transform = mat + cl = C + cl.images += I + +/obj/effect/buildmode_line/Destroy() + if(I) + if(istype(cl)) + cl.images -= I + cl = null + QDEL_NULL(I) + return ..() \ No newline at end of file diff --git a/code/modules/buildmode/submodes/advanced.dm b/code/modules/buildmode/submodes/advanced.dm new file mode 100644 index 000000000000..22eb998cdf80 --- /dev/null +++ b/code/modules/buildmode/submodes/advanced.dm @@ -0,0 +1,50 @@ +/datum/buildmode_mode/advanced + key = "advanced" + var/objholder = null + +// FIXME: add logic which adds a button displaying the icon +// of the currently selected path + +/datum/buildmode_mode/advanced/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Right Mouse Button on buildmode button = Set object type") + to_chat(c, "Left Mouse Button on turf/obj = Place objects") + to_chat(c, "Right Mouse Button = Delete objects") + to_chat(c, "") + to_chat(c, "Use the button in the upper left corner to") + to_chat(c, "change the direction of built objects.") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/advanced/change_settings(client/c) + var/target_path = input(c, "Enter typepath:", "Typepath", "/obj/structure/closet") + objholder = text2path(target_path) + if(!ispath(objholder)) + objholder = pick_closest_path(target_path) + if(!objholder) + alert("No path was selected") + return + else if(ispath(objholder, /area)) + objholder = null + alert("That path is not allowed.") + return + +/datum/buildmode_mode/advanced/handle_click(client/c, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + if(left_click) + if(ispath(objholder,/turf)) + var/turf/T = get_turf(object) + log_admin("Build Mode: [key_name(c)] modified [T] in [AREACOORD(object)] to [objholder]") + T.ChangeTurf(objholder) + else if(!isnull(objholder)) + var/obj/A = new objholder (get_turf(object)) + A.setDir(BM.build_dir) + log_admin("Build Mode: [key_name(c)] modified [A]'s [COORD(A)] dir to [BM.build_dir]") + else + to_chat(c, "Select object type first.") + else if(right_click) + if(isobj(object)) + log_admin("Build Mode: [key_name(c)] deleted [object] at [AREACOORD(object)]") + qdel(object) + \ No newline at end of file diff --git a/code/modules/buildmode/submodes/area_edit.dm b/code/modules/buildmode/submodes/area_edit.dm new file mode 100644 index 000000000000..19f536e07371 --- /dev/null +++ b/code/modules/buildmode/submodes/area_edit.dm @@ -0,0 +1,61 @@ +/datum/buildmode_mode/area_edit + key = "areaedit" + var/area/storedarea + var/image/areaimage + +/datum/buildmode_mode/area_edit/New() + areaimage = image('icons/turf/areas.dmi', null, "yellow") + ..() + +/datum/buildmode_mode/area_edit/enter_mode(datum/buildmode/BM) + BM.holder.images += areaimage + +/datum/buildmode_mode/area_edit/exit_mode(datum/buildmode/BM) + areaimage.loc = null // de-color the area + BM.holder.images -= areaimage + return ..() + +/datum/buildmode_mode/area_edit/Destroy() + QDEL_NULL(areaimage) + storedarea = null + return ..() + +/datum/buildmode_mode/area_edit/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Left Mouse Button on obj/turf/mob = Paint area") + to_chat(c, "Right Mouse Button on obj/turf/mob = Select area to paint") + to_chat(c, "Right Mouse Button on buildmode button = Create new area") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/area_edit/change_settings(client/c) + var/target_path = input(c, "Enter typepath:", "Typepath", "/area") + var/areatype = text2path(target_path) + if(ispath(areatype,/area)) + var/areaname = input(c, "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 // color our area + +/datum/buildmode_mode/area_edit/handle_click(client/c, params, object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + + if(left_click) + if(!storedarea) + to_chat(c, "Configure or select the area you want to paint first!") + return + var/turf/T = get_turf(object) + if(get_area(T) != storedarea) + log_admin("Build Mode: [key_name(c)] added [AREACOORD(T)] to [storedarea]") + storedarea.contents.Add(T) + else if(right_click) + var/turf/T = get_turf(object) + storedarea = get_area(T) + areaimage.loc = storedarea // color our area diff --git a/code/modules/buildmode/submodes/basic.dm b/code/modules/buildmode/submodes/basic.dm new file mode 100644 index 000000000000..4f7b176691de --- /dev/null +++ b/code/modules/buildmode/submodes/basic.dm @@ -0,0 +1,52 @@ +/datum/buildmode_mode/basic + key = "basic" + +/datum/buildmode_mode/basic/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Left Mouse Button = Construct / Upgrade") + to_chat(c, "Right Mouse Button = Deconstruct / Delete / Downgrade") + to_chat(c, "Left Mouse Button + ctrl = R-Window") + to_chat(c, "Left Mouse Button + alt = Airlock") + to_chat(c, "") + to_chat(c, "Use the button in the upper left corner to") + to_chat(c, "change the direction of built objects.") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/basic/handle_click(client/c, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + var/ctrl_click = pa.Find("ctrl") + var/alt_click = pa.Find("alt") + + if(istype(object,/turf) && left_click && !alt_click && !ctrl_click) + var/turf/T = object + if(isspaceturf(object)) + T.PlaceOnTop(/turf/open/floor/plating) + else if(isplatingturf(object)) + T.PlaceOnTop(/turf/open/floor/plasteel) + else if(isfloorturf(object)) + T.PlaceOnTop(/turf/closed/wall) + else if(iswallturf(object)) + T.PlaceOnTop(/turf/closed/wall/r_wall) + log_admin("Build Mode: [key_name(c)] built [T] at [AREACOORD(T)]") + return + else if(right_click) + log_admin("Build Mode: [key_name(c)] deleted [object] at [AREACOORD(object)]") + if(isturf(object)) + var/turf/T = object + T.ScrapeAway() + else if(isobj(object)) + qdel(object) + return + else if(istype(object,/turf) && alt_click && left_click) + log_admin("Build Mode: [key_name(c)] built an airlock at [AREACOORD(object)]") + new/obj/machinery/door/airlock(get_turf(object)) + else if(istype(object,/turf) && ctrl_click && left_click) + var/obj/structure/window/reinforced/window + if(BM.build_dir == NORTHWEST) + window = new /obj/structure/window/reinforced/fulltile(get_turf(object)) + else + window = new /obj/structure/window/reinforced(get_turf(object)) + window.setDir(BM.build_dir) + log_admin("Build Mode: [key_name(c)] built a window at [AREACOORD(object)]") diff --git a/code/modules/buildmode/submodes/boom.dm b/code/modules/buildmode/submodes/boom.dm new file mode 100644 index 000000000000..710352fdfc5b --- /dev/null +++ b/code/modules/buildmode/submodes/boom.dm @@ -0,0 +1,38 @@ +/datum/buildmode_mode/boom + key = "boom" + + var/devastation = -1 + var/heavy = -1 + var/light = -1 + var/flash = -1 + var/flames = -1 + +/datum/buildmode_mode/boom/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Mouse Button on obj = Kaboom") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/boom/change_settings(client/c) + devastation = input(c, "Range of total devastation. -1 to none", text("Input")) as num|null + if(devastation == null) + devastation = -1 + heavy = input(c, "Range of heavy impact. -1 to none", text("Input")) as num|null + if(heavy == null) + heavy = -1 + light = input(c, "Range of light impact. -1 to none", text("Input")) as num|null + if(light == null) + light = -1 + flash = input(c, "Range of flash. -1 to none", text("Input")) as num|null + if(flash == null) + flash = -1 + flames = input(c, "Range of flames. -1 to none", text("Input")) as num|null + if(flames == null) + flames = -1 + +/datum/buildmode_mode/boom/handle_click(client/c, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + + if(left_click) + explosion(object, devastation, heavy, light, flash, FALSE, TRUE, flames) + log_admin("Build Mode: [key_name(c)] caused an explosion(dev=[devastation], hvy=[heavy], lgt=[light], flash=[flash], flames=[flames]) at [AREACOORD(object)]") diff --git a/code/modules/buildmode/submodes/copy.dm b/code/modules/buildmode/submodes/copy.dm new file mode 100644 index 000000000000..ba415c50fc7d --- /dev/null +++ b/code/modules/buildmode/submodes/copy.dm @@ -0,0 +1,28 @@ +/datum/buildmode_mode/copy + key = "copy" + var/atom/movable/stored = null + +/datum/buildmode_mode/copy/Destroy() + stored = null + return ..() + +/datum/buildmode_mode/copy/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Left Mouse Button on obj/turf/mob = Spawn a Copy of selected target") + to_chat(c, "Right Mouse Button on obj/mob = Select target to copy") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/copy/handle_click(client/c, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + + if(left_click) + var/turf/T = get_turf(object) + if(stored) + DuplicateObject(stored, perfectcopy=1, sameloc=0,newloc=T) + log_admin("Build Mode: [key_name(c)] copied [stored] to [AREACOORD(object)]") + else if(right_click) + if(ismovableatom(object)) // No copying turfs for now. + to_chat(c, "[object] set as template.") + stored = object diff --git a/code/modules/buildmode/submodes/fill.dm b/code/modules/buildmode/submodes/fill.dm new file mode 100644 index 000000000000..58320cff7bce --- /dev/null +++ b/code/modules/buildmode/submodes/fill.dm @@ -0,0 +1,62 @@ +/datum/buildmode_mode/fill + key = "fill" + + use_corner_selection = TRUE + var/objholder = null + +/datum/buildmode_mode/fill/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Left Mouse Button on turf/obj/mob = Select corner") + to_chat(c, "Left Mouse Button + Alt on turf/obj/mob = Delete region") + to_chat(c, "Right Mouse Button on buildmode button = Select object type") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/fill/change_settings(client/c) + var/target_path = input(c, "Enter typepath:" ,"Typepath","/obj/structure/closet") + objholder = text2path(target_path) + if(!ispath(objholder)) + objholder = pick_closest_path(target_path) + if(!objholder) + alert("No path has been selected.") + return + else if(ispath(objholder, /area)) + objholder = null + alert("Area paths are not supported for this mode, use the area edit mode instead.") + return + deselect_region() + +/datum/buildmode_mode/fill/handle_click(client/c, params, obj/object) + if(isnull(objholder)) + to_chat(c, "Select an object type first.") + deselect_region() + return + ..() + +/datum/buildmode_mode/fill/handle_selected_area(client/c, params) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/alt_click = pa.Find("alt") + + if(left_click) //rectangular + if(alt_click) + var/list/deletion_area = block(get_turf(cornerA),get_turf(cornerB)) + for(var/beep in deletion_area) + var/turf/T = beep + for(var/atom/movable/AM in T) + qdel(AM) + // extreme haircut + T.ScrapeAway(INFINITY, CHANGETURF_DEFER_CHANGE) + for(var/beep in deletion_area) + var/turf/T = beep + T.AfterChange() + log_admin("Build Mode: [key_name(c)] deleted turfs from [AREACOORD(cornerA)] through [AREACOORD(cornerB)]") + // if there's an analogous proc for this on tg lmk + // empty_region(block(get_turf(cornerA),get_turf(cornerB))) + else + for(var/turf/T in block(get_turf(cornerA),get_turf(cornerB))) + if(ispath(objholder,/turf)) + T.PlaceOnTop(objholder) + else + var/obj/A = new objholder(T) + A.setDir(BM.build_dir) + log_admin("Build Mode: [key_name(c)] with path [objholder], filled the region from [AREACOORD(cornerA)] through [AREACOORD(cornerB)]") \ No newline at end of file diff --git a/code/modules/buildmode/submodes/mapgen.dm b/code/modules/buildmode/submodes/mapgen.dm new file mode 100644 index 000000000000..2b57ec1180b1 --- /dev/null +++ b/code/modules/buildmode/submodes/mapgen.dm @@ -0,0 +1,48 @@ +/datum/buildmode_mode/mapgen + key = "mapgen" + + use_corner_selection = TRUE + var/generator_path + +/datum/buildmode_mode/mapgen/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Left Mouse Button on turf/obj/mob = Select corner") + to_chat(c, "Right Mouse Button on buildmode button = Select generator") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/mapgen/change_settings(client/c) + var/list/gen_paths = subtypesof(/datum/mapGenerator) + var/list/options = list() + for(var/path in gen_paths) + var/datum/mapGenerator/MP = path + options[initial(MP.buildmode_name)] = path + var/type = input(c,"Select Generator Type","Type") as null|anything in options + if(!type) + return + + generator_path = options[type] + deselect_region() + +/datum/buildmode_mode/mapgen/handle_click(client/c, params, obj/object) + if(isnull(generator_path)) + to_chat(c, "Select generator type first.") + deselect_region() + return + ..() + +/datum/buildmode_mode/mapgen/handle_selected_area(client/c, params) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + if(left_click) + var/datum/mapGenerator/G = new generator_path + if(istype(G, /datum/mapGenerator/repair/reload_station_map)) + if(GLOB.reloading_map) + to_chat(c, "You are already reloading an area! Please wait for it to fully finish loading before trying to load another!") + deselect_region() + return + G.defineRegion(cornerA, cornerB, 1) + highlight_region(G.map) + var/confirm = alert("Are you sure you want run the map generator?", "Run generator", "Yes", "No") + if(confirm == "Yes") + G.generate() + log_admin("Build Mode: [key_name(c)] ran the map generator '[G.buildmode_name]' in the region from [AREACOORD(cornerA)] to [AREACOORD(cornerB)]") \ No newline at end of file diff --git a/code/modules/buildmode/submodes/throwing.dm b/code/modules/buildmode/submodes/throwing.dm new file mode 100644 index 000000000000..6d578c9c4670 --- /dev/null +++ b/code/modules/buildmode/submodes/throwing.dm @@ -0,0 +1,29 @@ +/datum/buildmode_mode/throwing + key = "throw" + + var/atom/movable/throw_atom = null + +/datum/buildmode_mode/throwing/Destroy() + throw_atom = null + return ..() + +/datum/buildmode_mode/throwing/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Left Mouse Button on turf/obj/mob = Select") + to_chat(c, "Right Mouse Button on turf/obj/mob = Throw") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/throwing/handle_click(client/c, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + + if(left_click) + if(isturf(object)) + return + throw_atom = object + to_chat(c, "Selected object '[throw_atom]'") + if(right_click) + if(throw_atom) + throw_atom.throw_at(object, 10, 1, c.mob) + log_admin("Build Mode: [key_name(c)] threw [throw_atom] at [object] ([AREACOORD(object)])") diff --git a/code/modules/buildmode/submodes/variable_edit.dm b/code/modules/buildmode/submodes/variable_edit.dm new file mode 100644 index 000000000000..ac4c1ef66a20 --- /dev/null +++ b/code/modules/buildmode/submodes/variable_edit.dm @@ -0,0 +1,62 @@ +/datum/buildmode_mode/varedit + key = "edit" + // Varedit mode + var/varholder = null + var/valueholder = null + +/datum/buildmode_mode/varedit/Destroy() + varholder = null + valueholder = null + return ..() + +/datum/buildmode_mode/varedit/show_help(client/c) + to_chat(c, "***********************************************************") + to_chat(c, "Right Mouse Button on buildmode button = Select var(type) & value") + to_chat(c, "Left Mouse Button on turf/obj/mob = Set var(type) & value") + to_chat(c, "Right Mouse Button on turf/obj/mob = Reset var's value") + to_chat(c, "***********************************************************") + +/datum/buildmode_mode/varedit/Reset() + . = ..() + varholder = null + valueholder = null + +/datum/buildmode_mode/varedit/change_settings(client/c) + varholder = input(c, "Enter variable name:" ,"Name", "name") + + if(!vv_varname_lockcheck(varholder)) + return + + var/temp_value = c.vv_get_value() + if(isnull(temp_value["class"])) + Reset() + to_chat(c, "Variable unset.") + return + valueholder = temp_value["value"] + +/datum/buildmode_mode/varedit/handle_click(client/c, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + + if(isnull(varholder)) + to_chat(c, "Choose a variable to modify first.") + return + if(left_click) + if(object.vars.Find(varholder)) + if(object.vv_edit_var(varholder, valueholder) == FALSE) + to_chat(c, "Your edit was rejected by the object.") + return + log_admin("Build Mode: [key_name(c)] modified [object.name]'s [varholder] to [valueholder]") + else + to_chat(c, "[initial(object.name)] does not have a var called '[varholder]'") + if(right_click) + if(object.vars.Find(varholder)) + var/reset_value = initial(object.vars[varholder]) + if(object.vv_edit_var(varholder, reset_value) == FALSE) + to_chat(c, "Your edit was rejected by the object.") + return + log_admin("Build Mode: [key_name(c)] modified [object.name]'s [varholder] to [reset_value]") + else + to_chat(c, "[initial(object.name)] does not have a var called '[varholder]'") + diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm index ac5a14a55558..814000ce4888 100644 --- a/code/modules/client/player_details.dm +++ b/code/modules/client/player_details.dm @@ -1,4 +1,6 @@ /datum/player_details var/list/player_actions = list() var/list/logging = list() + var/list/post_login_callbacks = list() + var/list/post_logout_callbacks = list() var/byond_version = "Unknown" \ No newline at end of file diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 09662406ab46..43d8b6ef49c4 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -41,12 +41,14 @@ update_client_colour() update_mouse_pointer() if(client) - client.click_intercept = null - client.change_view(CONFIG_GET(string/default_view)) // Resets the client.view in case it was changed. if(client.player_details.player_actions.len) for(var/datum/action/A in client.player_details.player_actions) A.Grant(src) + + for(var/foo in client.player_details.post_login_callbacks) + var/datum/callback/CB = foo + CB.Invoke() log_message("Client [key_name(src)] has taken ownership of mob [src]", LOG_OWNERSHIP) diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index 3e2651312614..0b3602181532 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -8,5 +8,10 @@ if(loc) loc.on_log(FALSE) + + if(client) + for(var/foo in client.player_details.post_logout_callbacks) + var/datum/callback/CB = foo + CB.Invoke() return TRUE diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi index 649a77265693..f0de428b6c55 100644 Binary files a/icons/misc/buildmode.dmi and b/icons/misc/buildmode.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 2b2018dc3f10..8fa1212fb184 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1087,7 +1087,6 @@ #include "code\modules\admin\verbs\bluespacearty.dm" #include "code\modules\admin\verbs\borgpanel.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\deadsay.dm" #include "code\modules\admin\verbs\debug.dm" @@ -1370,6 +1369,19 @@ #include "code\modules\awaymissions\mission_code\undergroundoutpost45.dm" #include "code\modules\awaymissions\mission_code\wildwest.dm" #include "code\modules\bsql\includes.dm" +#include "code\modules\buildmode\bm_mode.dm" +#include "code\modules\buildmode\buildmode.dm" +#include "code\modules\buildmode\buttons.dm" +#include "code\modules\buildmode\effects\line.dm" +#include "code\modules\buildmode\submodes\advanced.dm" +#include "code\modules\buildmode\submodes\area_edit.dm" +#include "code\modules\buildmode\submodes\basic.dm" +#include "code\modules\buildmode\submodes\boom.dm" +#include "code\modules\buildmode\submodes\copy.dm" +#include "code\modules\buildmode\submodes\fill.dm" +#include "code\modules\buildmode\submodes\mapgen.dm" +#include "code\modules\buildmode\submodes\throwing.dm" +#include "code\modules\buildmode\submodes\variable_edit.dm" #include "code\modules\cargo\bounty.dm" #include "code\modules\cargo\bounty_console.dm" #include "code\modules\cargo\console.dm"