diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 4612c8cdce3..a4bcbcadc4b 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -373,4 +373,8 @@ #define RETURN_TO_LOBBY 2 //Melting Temperatures for various specific objects -#define GIRDER_MELTING_TEMP 5000 \ No newline at end of file +#define GIRDER_MELTING_TEMP 5000 + +// Area selection defines +#define AREASELECT_CORNERA "corner A" +#define AREASELECT_CORNERB "corner B" diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 1080a4f628d..e01a1fd9895 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1785,28 +1785,99 @@ var/mob/dview/dview_mob = new for(var/type in types) var/typename = "[type]" var/static/list/TYPES_SHORTCUTS = list( + //longest paths comes first - otherwise they get shadowed by the more generic ones /obj/effect/decal/cleanable = "CLEANABLE", - /obj/item/radio/headset = "HEADSET", - /obj/item/clothing/head/helmet/space = "SPESSHELMET", - /obj/item/book/manual = "MANUAL", - /obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first - /obj/item/reagent_containers/food = "FOOD", - /obj/item/reagent_containers = "REAGENT_CONTAINERS", - /obj/item = "WEAPON", - /obj/machinery/atmospherics = "ATMOS_MECH", - /obj/machinery/portable_atmospherics = "PORT_ATMOS", - /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK", - /obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP", - /obj/item/organ = "ORGAN", - /obj/item = "ITEM", - /obj/machinery = "MACHINERY", /obj/effect = "EFFECT", + /obj/item/ammo_casing = "AMMO", + /obj/item/book/manual = "MANUAL", + /obj/item/borg/upgrade = "BORG_UPGRADE", + /obj/item/cartridge = "PDA_CART", + /obj/item/clothing/head/helmet/space = "SPESSHELMET", + /obj/item/clothing/head = "HEAD", + /obj/item/clothing/under = "UNIFORM", + /obj/item/clothing/shoes = "SHOES", + /obj/item/clothing/suit = "SUIT", + /obj/item/clothing/gloves = "GLOVES", + /obj/item/clothing/mask/cigarette = "CIGARRETE", // oof + /obj/item/clothing/mask = "MASK", + /obj/item/clothing/glasses = "GLASSES", + /obj/item/clothing = "CLOTHING", + /obj/item/grenade/clusterbuster = "CLUSTERBUSTER", + /obj/item/grenade = "GRENADE", + /obj/item/gun = "GUN", + /obj/item/implant = "IMPLANT", + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK", + /obj/item/mecha_parts/mecha_equipment/weapon = "MECHA_WEAPON", + /obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP", + /obj/item/melee = "MELEE", + /obj/item/mmi = "MMI", + /obj/item/nullrod = "NULLROD", + /obj/item/organ/external = "EXT_ORG", + /obj/item/organ/internal/cyberimp = "CYBERIMP", + /obj/item/organ/internal = "INT_ORG", + /obj/item/organ = "ORGAN", + /obj/item/pda = "PDA", + /obj/item/projectile = "PROJ", + /obj/item/radio/headset = "HEADSET", + /obj/item/reagent_containers/glass/beaker = "BEAKER", + /obj/item/reagent_containers/glass/bottle = "BOTTLE", + /obj/item/reagent_containers/food/pill/patch = "PATCH", + /obj/item/reagent_containers/food/pill = "PILL", + /obj/item/reagent_containers/food/drinks = "DRINK", + /obj/item/reagent_containers/food = "FOOD", + /obj/item/reagent_containers/syringe = "SYRINGE", + /obj/item/reagent_containers = "REAGENT_CONTAINERS", + /obj/item/robot_parts = "ROBOT_PARTS", + /obj/item/seeds = "SEED", + /obj/item/slime_extract = "SLIME_CORE", + /obj/item/spacepod_equipment/weaponry = "POD_WEAPON", + /obj/item/spacepod_equipment = "POD_EQUIP", + /obj/item/stack/sheet/mineral = "MINERAL", + /obj/item/stack/sheet = "SHEET", + /obj/item/stack/tile = "TILE", + /obj/item/stack = "STACK", + /obj/item/stock_parts/cell = "POWERCELL", + /obj/item/stock_parts = "STOCK_PARTS", + /obj/item/storage/firstaid = "FIRSTAID", + /obj/item/storage = "STORAGE", + /obj/item/tank = "GAS_TANK", + /obj/item/toy/crayon = "CRAYON", + /obj/item/toy = "TOY", + /obj/item = "ITEM", + /obj/machinery/atmospherics = "ATMOS_MACH", + /obj/machinery/computer = "CONSOLE", + /obj/machinery/door/airlock = "AIRLOCK", + /obj/machinery/door = "DOOR", + /obj/machinery/kitchen_machine = "KITCHEN", + /obj/machinery/portable_atmospherics/canister = "CANISTER", + /obj/machinery/portable_atmospherics = "PORT_ATMOS", + /obj/machinery/power = "POWER", + /obj/machinery/telecomms = "TCOMMS", + /obj/machinery = "MACHINERY", + /obj/mecha = "MECHA", + /obj/structure/closet/crate = "CRATE", + /obj/structure/closet = "CLOSET", + /obj/structure/statue = "STATUE", + /obj/structure/chair = "CHAIR", // oh no + /obj/structure/stool/bed = "BED", + /obj/structure/stool = "STOOL", + /obj/structure/table = "TABLE", + /obj/structure = "STRUCTURE", + /obj/vehicle = "VEHICLE", /obj = "O", /datum = "D", - /turf/simulated/floor = "FLOOR", - /turf/simulated/wall = "WALL", + /turf/simulated/floor = "SIM_FLOOR", + /turf/simulated/wall = "SIM_WALL", + /turf/unsimulated/floor = "UNSIM_FLOOR", + /turf/unsimulated/wall = "UNSIM_WALL", /turf = "T", + /mob/living/carbon/alien = "XENO", + /mob/living/carbon/human = "HUMAN", /mob/living/carbon = "CARBON", + /mob/living/silicon/robot = "CYBORG", + /mob/living/silicon/ai = "AI", + /mob/living/silicon = "SILICON", + /mob/living/simple_animal/bot = "BOT", /mob/living/simple_animal = "SIMPLE", /mob/living = "LIVING", /mob = "M" diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index b2521527a98..0b51e52d3ea 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -11,7 +11,8 @@ */ /mob/living/silicon/ai/DblClickOn(var/atom/A, params) if(client.click_intercept) - client.click_intercept.InterceptClickOn(src, params, A) + // Not doing a click intercept here, because otherwise we double-tap with the `ClickOn` proc. + // But we return here since we don't want to do regular dblclick handling return if(control_disabled || stat) return diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index d04abfe5a87..797384b8336 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -1,6 +1,7 @@ /mob/dead/observer/DblClickOn(var/atom/A, var/params) if(client.click_intercept) - client.click_intercept.InterceptClickOn(src, params, A) + // Not doing a click intercept here, because otherwise we double-tap with the `ClickOn` proc. + // But we return here since we don't want to do regular dblclick handling return if(can_reenter_corpse && mind && mind.current) diff --git a/code/datums/click_intercept.dm b/code/datums/click_intercept.dm new file mode 100644 index 00000000000..d3e9bccbda0 --- /dev/null +++ b/code/datums/click_intercept.dm @@ -0,0 +1,31 @@ +/datum/click_intercept + var/client/holder = null + var/list/obj/screen/buttons = list() + +/datum/click_intercept/New(client/C) + create_buttons() + enter(C) + return ..() + +/datum/click_intercept/Destroy() + holder.screen -= buttons + holder.click_intercept = null + holder.show_popup_menus = TRUE + holder = null + QDEL_LIST(buttons) + return ..() + +/datum/click_intercept/proc/enter(client/C) + holder = C + holder.click_intercept = src + holder.show_popup_menus = FALSE + holder.screen += buttons + +/datum/click_intercept/proc/quit() + qdel(src) + +/datum/click_intercept/proc/create_buttons() + return + +/datum/click_intercept/proc/InterceptClickOn(user,params,atom/object) + return \ No newline at end of file diff --git a/code/modules/admin/buildmode.dm b/code/modules/admin/buildmode.dm deleted file mode 100644 index b04b9d2b96a..00000000000 --- a/code/modules/admin/buildmode.dm +++ /dev/null @@ -1,656 +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 AREAEDIT_BUILDMODE 7 -#define FILL_BUILDMODE 8 -#define LINK_BUILDMODE 9 -#define BOOM_BUILDMODE 10 -#define SAVE_BUILDMODE 11 -#define NUM_BUILDMODES 11 - -/obj/screen/buildmode - icon = 'icons/misc/buildmode.dmi' - var/datum/click_intercept/buildmode/bd - layer = HUD_LAYER_BUILDMODE - -/obj/screen/buildmode/New(bld) - ..() - bd = bld - -/obj/screen/buildmode/mode - name = "Toggle Mode" - icon_state = "buildmode1" - 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() - dir = bd.build_dir - return - -/obj/screen/buildmode/bdir/Click() - bd.change_dir() - update_icon() - 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 - -/obj/screen/buildmode/dir/Click() - bd.change_dir() - update_icon() - return 1 - -/obj/effect/buildmode_reticule - var/image/I - var/client/cl - anchored = TRUE - -/obj/effect/buildmode_reticule/New(var/turf/t, var/client/c) - loc = t - I = image('icons/mob/blob.dmi', t, "marker",19.0,2) // Sprite reuse wooo - if(c) - cl = c - cl.images += I - else - log_runtime(EXCEPTION("Buildmode reticule created without a client!"), src) - -/obj/effect/buildmode_reticule/proc/deselect() - qdel(src) - -/obj/effect/buildmode_reticule/Destroy() - cl.images -= I - cl = null - qdel(I) - return ..() - -/obj/effect/buildmode_line - var/image/I - var/client/cl - -/obj/effect/buildmode_line/New(var/client/c, var/atom/atom_a, var/atom/atom_b, var/linename) - name = linename - loc = get_turf(atom_a) - I = image('icons/misc/mark.dmi', src, "line", 19.0) - var/x_offset = ((atom_b.x * 32) + atom_b.pixel_x) - ((atom_a.x * 32) + atom_a.pixel_x) - var/y_offset = ((atom_b.y * 32) + atom_b.pixel_y) - ((atom_a.y * 32) + atom_a.pixel_y) - - var/matrix/M = matrix() - M.Translate(0, 16) - M.Scale(1, sqrt((x_offset * x_offset) + (y_offset * y_offset)) / 32) - M.Turn(90 - Atan2(x_offset, y_offset)) // So... You pass coords in order x,y to this version of atan2. It should be called acsc2. - M.Translate(atom_a.pixel_x, atom_a.pixel_y) - - transform = M - cl = c - cl.images += I - -/obj/effect/buildmode_line/Destroy() - if(I) - if(istype(cl)) - cl.images -= I - cl = null - QDEL_NULL(I) - return ..() - -/datum/click_intercept - var/client/holder = null - var/list/obj/screen/buttons = list() - -/datum/click_intercept/New(client/c) - create_buttons() - holder = c - holder.click_intercept = src - holder.show_popup_menus = 0 - holder.screen += buttons - -/datum/click_intercept/Destroy() - QDEL_LIST(buttons) - return ..() - - -/datum/click_intercept/proc/create_buttons() - return - -/datum/click_intercept/proc/InterceptClickOn(user,params,atom/object) - return - -/datum/click_intercept/proc/quit() - holder.screen -= buttons - holder.click_intercept = null - holder.show_popup_menus = 1 - qdel(src) - - - -/datum/click_intercept/buildmode - var/mode = BASIC_BUILDMODE - var/build_dir = SOUTH - var/atom/movable/throw_atom = null - var/obj/effect/buildmode_reticule/cornerA = null - var/obj/effect/buildmode_reticule/cornerB = null - var/generator_path = null - var/varholder = "name" - var/valueholder = "derp" - var/objholder = /obj/structure/closet - var/area/storedarea = null - var/image/areaimage - var/atom/movable/stored = null - var/list/link_lines = list() - var/obj/link_obj - var/valid_links = 0 - //Explosion mode - var/devastation = -1 - var/heavy = -1 - var/light = -1 - var/flash = -1 - var/flames = -1 - // Saving mode - var/use_json = TRUE - -/datum/click_intercept/buildmode/New(client/c) - ..() - areaimage = image('icons/turf/areas.dmi',null,"yellow") - holder.images += areaimage - -/datum/click_intercept/buildmode/Destroy() - stored = null - Reset() - areaimage.loc = null - qdel(areaimage) - return ..() - -/datum/click_intercept/buildmode/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/click_intercept/buildmode/proc/toggle_modes() - mode = (mode % NUM_BUILDMODES) +1 - Reset() - return - -/datum/click_intercept/buildmode/proc/show_help(mob/user) - switch(mode) - if(BASIC_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button = Construct / Upgrade") - to_chat(user, "Right Mouse Button = Deconstruct / Delete / Downgrade") - to_chat(user, "Left Mouse Button + ctrl = R-Window") - to_chat(user, "Left Mouse Button + alt = Airlock") - to_chat(user, "") - to_chat(user, "Use the button in the upper left corner to") - to_chat(user, "change the direction of built objects.") - to_chat(user, "***********************************************************") - if(ADV_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Right Mouse Button on buildmode button = Set object type") - to_chat(user, "Left Mouse Button on turf/obj = Place objects") - to_chat(user, "Right Mouse Button = Delete objects") - to_chat(user, "") - to_chat(user, "Use the button in the upper left corner to") - to_chat(user, "change the direction of built objects.") - to_chat(user, "***********************************************************") - if(VAR_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Right Mouse Button on buildmode button = Select var(type) & value") - to_chat(user, "Left Mouse Button on turf/obj/mob = Set var(type) & value") - to_chat(user, "Right Mouse Button on turf/obj/mob = Reset var's value") - to_chat(user, "***********************************************************") - if(THROW_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button on turf/obj/mob = Select") - to_chat(user, "Right Mouse Button on turf/obj/mob = Throw") - to_chat(user, "***********************************************************") - if(AREA_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button on turf/obj/mob = Select corner") - to_chat(user, "Right Mouse Button on buildmode button = Select generator") - to_chat(user, "***********************************************************") - if(COPY_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button on obj/turf/mob = Spawn a Copy of selected target") - to_chat(user, "Right Mouse Button on obj/mob = Select target to copy") - to_chat(user, "***********************************************************") - if(AREAEDIT_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button on obj/turf/mob = Paint area") - to_chat(user, "Right Mouse Button on obj/turf/mob = Select area to paint") - to_chat(user, "Right Mouse Button on buildmode button = Create new area") - to_chat(user, "***********************************************************") - if(FILL_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button on turf/obj/mob = Select corner") - to_chat(user, "Left Mouse Button + Alt on turf/obj/mob = Delete region") - to_chat(user, "Right Mouse Button on buildmode button = Select object type") - to_chat(user, "***********************************************************") - if(LINK_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button on obj = Select button to link") - to_chat(user, "Right Mouse Button on obj = Link/unlink to selected button") - to_chat(user, "***********************************************************") - if(BOOM_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Mouse Button on obj = Kaboom") - to_chat(user, "***********************************************************") - if(SAVE_BUILDMODE) - to_chat(user, "***********************************************************") - to_chat(user, "Left Mouse Button on turf/obj/mob = Select corner") - to_chat(user, "***********************************************************") - - - - -/datum/click_intercept/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 || ispath(objholder, /area)) - 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 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/type = input(user,"Select Generator Type","Type") as null|anything in gen_paths - if(!type) return - - generator_path = type - cornerA = null - cornerB = null - if(AREAEDIT_BUILDMODE) - var/target_path = input(user,"Enter typepath:", "Typepath", "/area") - var/areatype = text2path(target_path) - if(ispath(areatype,/area)) - var/areaname = input(user,"Enter area name:", "Area name", "Area") - if(!areaname || !length(areaname)) - return - storedarea = new areatype - storedarea.power_equip = 0 - storedarea.power_light = 0 - storedarea.power_environ = 0 - storedarea.always_unpowered = 0 - storedarea.name = areaname - areaimage.loc = storedarea - if(FILL_BUILDMODE) - var/target_path = input(user,"Enter typepath:" ,"Typepath","/obj/structure/closet") - objholder = text2path(target_path) - if(!ispath(objholder)) - objholder = pick_closest_path(target_path) - if(!objholder || ispath(objholder, /area)) - objholder = /obj/structure/closet - return - else - if(ispath(objholder,/mob) && !check_rights(R_DEBUG,0)) - objholder = /obj/structure/closet - deselect_region() - if(BOOM_BUILDMODE) - devastation = input("Range of total devastation. -1 to none", text("Input")) as num|null - if(devastation == null) devastation = -1 - heavy = input("Range of heavy impact. -1 to none", text("Input")) as num|null - if(heavy == null) heavy = -1 - light = input("Range of light impact. -1 to none", text("Input")) as num|null - if(light == null) light = -1 - flash = input("Range of flash. -1 to none", text("Input")) as num|null - if(flash == null) flash = -1 - flames = input("Range of flames. -1 to none", text("Input")) as num|null - if(flames == null) flames = -1 - - if(SAVE_BUILDMODE) - use_json = (alert("Would you like to use json (Default is \"Yes\")?",,"Yes","No") == "Yes") - -/datum/click_intercept/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/click_intercept/buildmode/proc/deselect_region() - QDEL_NULL(cornerA) - QDEL_NULL(cornerB) - -/datum/click_intercept/buildmode/proc/Reset()//Reset temporary variables - deselect_region() - if(mode == AREAEDIT_BUILDMODE) - areaimage.loc = storedarea - else - areaimage.loc = null - for(var/obj/effect/buildmode_line/L in link_lines) - qdel(L) - link_lines -= L - -/datum/click_intercept/buildmode/proc/select_tile(var/turf/T) - return new /obj/effect/buildmode_reticule(T, holder) - -/proc/togglebuildmode(mob/M as mob in player_list) - set name = "Toggle Build Mode" - set category = "Event" - - if(M.client) - if(istype(M.client.click_intercept,/datum/click_intercept/buildmode)) - var/datum/click_intercept/buildmode/B = M.client.click_intercept - B.quit() - log_admin("[key_name(usr)] has left build mode.") - else - new/datum/click_intercept/buildmode(M.client) - message_admins("[key_name_admin(usr)] has entered build mode.") - log_admin("[key_name(usr)] has entered build mode.") - -/datum/click_intercept/buildmode/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") - - . = 1 - switch(mode) - if(BASIC_BUILDMODE) - if(istype(object,/turf) && left_click && !alt_click && !ctrl_click) - var/turf/T = object - if(istype(object,/turf/space)) - T.ChangeTurf(/turf/simulated/floor/plasteel) - else if(istype(object,/turf/simulated/floor)) - T.ChangeTurf(/turf/simulated/wall) - else if(istype(object,/turf/simulated/wall)) - T.ChangeTurf(/turf/simulated/wall/r_wall) - log_admin("Build Mode: [key_name(user)] built [T] at ([T.x],[T.y],[T.z])") - return - else if(right_click) - log_admin("Build Mode: [key_name(user)] deleted [object] at ([object.x],[object.y],[object.z])") - if(istype(object,/turf/simulated/wall)) - var/turf/T = object - T.ChangeTurf(/turf/simulated/floor/plasteel) - else if(istype(object,/turf/simulated/floor)) - var/turf/T = object - T.ChangeTurf(/turf/space) - else if(istype(object,/turf/simulated/wall/r_wall)) - var/turf/T = object - T.ChangeTurf(/turf/simulated/wall) - else if(istype(object,/obj)) - qdel(object) - return - else if(istype(object,/turf) && alt_click && left_click) - log_admin("Build Mode: [key_name(user)] built an airlock at ([object.x],[object.y],[object.z])") - new/obj/machinery/door/airlock(get_turf(object)) - else if(istype(object,/turf) && ctrl_click && left_click) - var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object)) - WIN.setDir(build_dir) - log_admin("Build Mode: [key_name(user)] built a window at ([object.x],[object.y],[object.z])") - - if(ADV_BUILDMODE) - if(left_click) - if(ispath(objholder,/turf)) - var/turf/T = get_turf(object) - log_admin("Build Mode: [key_name(user)] modified [T] ([T.x],[T.y],[T.z]) to [objholder]") - T.ChangeTurf(objholder) - else if(!isnull(objholder)) - var/obj/A = new objholder (get_turf(object)) - A.setDir(build_dir) - log_admin("Build Mode: [key_name(user)] modified [A]'s ([A.x],[A.y],[A.z]) dir to [build_dir]") - else - to_chat(user, "Select object type first.") - else if(right_click) - if(isobj(object)) - log_admin("Build Mode: [key_name(user)] deleted [object] at ([object.x],[object.y],[object.z])") - qdel(object) - - if(VAR_BUILDMODE) - if(left_click) //I cant believe this shit actually compiles. - if(object.vars.Find(varholder)) - log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [valueholder]") - object.vars[varholder] = valueholder - else - to_chat(user, "[initial(object.name)] does not have a var called '[varholder]'") - if(right_click) - if(object.vars.Find(varholder)) - log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [valueholder]") - object.vars[varholder] = initial(object.vars[varholder]) - 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] ([object.x],[object.y],[object.z])") - if(AREA_BUILDMODE) - if(!cornerA) - cornerA = select_tile(get_turf(object)) - return - if(cornerA && !cornerB) - cornerB = select_tile(get_turf(object)) - if(left_click) //rectangular - if(cornerA && cornerB) - if(!generator_path) - to_chat(user, "Select generator type first.") - else - var/datum/mapGenerator/G = new generator_path - G.defineRegion(cornerA.loc,cornerB.loc,1) - G.generate() - deselect_region() - return - - //Something wrong - Reset - deselect_region() - if(COPY_BUILDMODE) - if(left_click) - var/turf/T = get_turf(object) - if(stored) - DuplicateObject(stored, perfectcopy=1, sameloc=0,newloc=T) - else if(right_click) - if(ismovableatom(object)) // No copying turfs for now. - to_chat(user, "[object] set as template.") - stored = object - if(AREAEDIT_BUILDMODE) - if(left_click) - if(!storedarea) - return - var/turf/T = get_turf(object) - if(get_area(T) != storedarea) - storedarea.contents.Add(T) - else if(right_click) - var/turf/T = get_turf(object) - storedarea = get_area(T) - areaimage.loc = storedarea - if(FILL_BUILDMODE) - if(!cornerA) - cornerA = select_tile(get_turf(object)) - return - if(cornerA && !cornerB) - cornerB = select_tile(get_turf(object)) - if(left_click) //rectangular - if(cornerA && cornerB) - if(alt_click) - empty_region(block(get_turf(cornerA),get_turf(cornerB))) - deselect_region() - else - if(!objholder) - to_chat(user, "Select object type first.") - else - for(var/turf/T in block(get_turf(cornerA),get_turf(cornerB))) - if(ispath(objholder,/turf)) - T.ChangeTurf(objholder) - else - var/obj/A = new objholder(T) - A.setDir(build_dir) - deselect_region() - return - - //Something wrong - Reset - deselect_region() - if(LINK_BUILDMODE) - if(left_click && istype(object, /obj/machinery)) - link_obj = object - if(right_click && istype(object, /obj/machinery)) - if(istype(link_obj, /obj/machinery/door_control) && istype(object, /obj/machinery/door/airlock)) - var/obj/machinery/door_control/M = link_obj - var/obj/machinery/door/airlock/P = object - if(!M.id || M.id == "") - M.id = input(holder, "Please select an ID for the button", "Buildmode", "") - if(!M.id || M.id == "") - goto(line_jump) - if(P.id_tag == M.id && (P in range(M.range, M)) && P.id_tag && P.id_tag != "") - P.id_tag = null - to_chat(holder, "[P] unlinked.") - goto(line_jump) - if(!M.normaldoorcontrol) - if(link_lines.len && alert(holder, "Warning: This will disable links to connected pod doors. Continue?", "Buildmode", "Yes", "No") == "No") - goto(line_jump) - M.normaldoorcontrol = 1 - if(P.id_tag && alert(holder, "Warning: This will unlink something else from the door. Continue?", "Buildmode", "Yes", "No") == "No") - goto(line_jump) - P.id_tag = M.id - if(istype(link_obj, /obj/machinery/door_control) && istype(object, /obj/machinery/door/poddoor)) - var/obj/machinery/door_control/M = link_obj - var/obj/machinery/door/poddoor/P = object - if(!M.id || M.id == "") - M.id = input(holder, "Please select an ID for the button", "Buildmode", "") - if(!M.id || M.id == "") - goto(line_jump) - if(P.id_tag == M.id && P.id_tag && P.id_tag != "") - P.id_tag = null - to_chat(holder, "[P] unlinked.") - goto(line_jump) - if(M.normaldoorcontrol) - if(link_lines.len && alert(holder, "Warning: This will disable links to connected airlocks. Continue?", "Buildmode", "Yes", "No") == "No") - goto(line_jump) - M.normaldoorcontrol = 0 - if(!M.id || M.id == "") - M.id = input(holder, "Please select an ID for the button", "Buildmode", "") - if(!M.id || M.id == "") - goto(line_jump) - if(P.id_tag && P.id_tag != 1 && alert(holder, "Warning: This will unlink something else from the door. Continue?", "Buildmode", "Yes", "No") == "No") - goto(line_jump) - P.id_tag = M.id - - line_jump // For the goto - valid_links = 0 - for(var/obj/effect/buildmode_line/L in link_lines) - qdel(L) - link_lines -= L - - if(istype(link_obj, /obj/machinery/door_control)) - var/obj/machinery/door_control/M = link_obj - for(var/obj/machinery/door/airlock/P in range(M.range,M)) - if(P.id_tag == M.id) - var/obj/effect/buildmode_line/L = new(holder, M, P, "[M.name] to [P.name]") - L.color = M.normaldoorcontrol ? "#339933" : "#993333" - if(M.normaldoorcontrol) - valid_links = 1 - link_lines += L - var/obj/effect/buildmode_line/L2 = new(holder, P, M, "[M.name] to [P.name]") // Yes, reversed one so that you can see it from both sides. - L2.color = L.color - link_lines += L2 - for(var/obj/machinery/door/poddoor/P in airlocks) - if(P.id_tag == M.id) - var/obj/effect/buildmode_line/L = new(holder, M, P, "[M.name] to [P.name]") - L.color = M.normaldoorcontrol ? "#993333" : "#339933" - if(M.normaldoorcontrol) - valid_links = 0 - link_lines += L - var/obj/effect/buildmode_line/L2 = new(holder, P, M, "[M.name] to [P.name]") // Yes, reversed one so that you can see it from both sides. - L2.color = L.color - link_lines += L2 - if(BOOM_BUILDMODE) - explosion(object, devastation, heavy, light, flash, null, TRUE, flames) - if(SAVE_BUILDMODE) - if(!cornerA) - cornerA = select_tile(get_turf(object)) - return - if(!cornerB) - cornerB = select_tile(get_turf(object)) - if(left_click) - if(cornerA && cornerB) - var/turf/A = get_turf(cornerA) - var/turf/B = get_turf(cornerB) - deselect_region() // So we don't read our own reticules - var/map_name = input(holder, "Please select a name for your map", "Buildmode", "") - if(map_name == "") - return - var/map_flags = 0 - if(use_json) - map_flags = 32 // Magic number defined in `writer.dm` that I can't use directly - // because #defines are for some reason our coding standard - var/our_map = maploader.save_map(A,B,map_name,map_flags) - holder << ftp(our_map) // send the map they've made! Or are stealing, whatever - to_chat(holder, "Map saving complete! [our_map]") - return - - deselect_region() diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index c1e28a48f8d..d899fda5b56 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -516,6 +516,24 @@ var/list/VVpixelmovement = list("step_x", "step_y", "step_size", "bound_height", 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 VVlocked) + if(!check_rights(R_DEBUG)) + return FALSE + if(param_var_name in VVckey_edit) + if(!check_rights(R_EVENT | R_DEBUG)) + return FALSE + if(param_var_name in VVicon_edit_lock) + if(!check_rights(R_EVENT | R_DEBUG)) + return FALSE + if(param_var_name in 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 @@ -544,25 +562,11 @@ var/list/VVpixelmovement = list("step_x", "step_y", "step_size", "bound_height", if(!O.can_vv_get(variable)) return + if(!vv_varname_lockcheck(variable)) + return + var_value = O.vars[variable] - if(variable in VVlocked) - if(!check_rights(R_DEBUG)) - return - if(variable in VVckey_edit) - if(!check_rights(R_EVENT | R_DEBUG)) - return - if(variable in VVicon_edit_lock) - if(!check_rights(R_EVENT | R_DEBUG)) - return - if(variable in 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(var_value) if(isnull(default)) diff --git a/code/modules/buildmode/README.md b/code/modules/buildmode/README.md new file mode 100644 index 00000000000..37ce2ce6b1b --- /dev/null +++ b/code/modules/buildmode/README.md @@ -0,0 +1,297 @@ +# 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. + + + *Alt+Left click a turf, object, or mob*: + + Select the type of the object clicked. + + + *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. + ++ Atmos + + **Description**: + + Fills a region with configurable atmos. By default, ignores unsimulated turfs, but is able to "overwrite" the atmos of unsimulated turfs with a special control input. + + By default, fills a region with a breathable, standard atmosphere. + + **Controls**: + + + *Right click on the mode selector icon*: + + Set the following traits: + + + Total Pressure + + Temperature + + Partial Pressure Ratio (PPR) Oxygen + + PPR Nitrogen + + PPR Plasma + + PPR CO2 + + PPR N2O + + + *Left click a region*: + + Fill the region with the configured atmos. + + + *Control+Left click a region*: + + As with the regular left click, but also "overwrites" the base atmos of any unsimulated turfs in the region - such as space turfs. + + + *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. + ++ Link + + **Description**: + + Form links between door control buttons and either airlocks or pod bay doors. + + The selected button will be highlighted, and visible lines will be drawn between the doors it is linked to and itself. + + **Controls**: + + + *Left click a door control button*: + + Makes the button active, and show what doors it is linked to. + + + *Right click an airlock* (requires active button): + + Links the airlock to the active button. Will remove all links from the button first, if the button is linked to pod bay doors. + + + *Right click a pod bay door* (requires active button): + + Links the pod bay door to the active button. Will remove all links from the button first, if the button is linked to regular airlocks. + ++ 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. + ++ Save + + **Description**: + + Captures a rectangular region in a `.dmm` format, which can be loaded back later using the "Place Map Template" debug verb. + + Keep in mind this feature is somewhat experimental, and may not always work. + + **Controls**: + + + *Right click on the mode selector*: + + Configure whether to save in either JSON mode or not. + + + *Left click two corners of an area*: + + Save the region to a `.dmm` file. You will be prompted for where to save this - a copy will be saved in the `_maps/quicksave` folder. + + + *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 00000000000..de4c09a192d --- /dev/null +++ b/code/modules/buildmode/bm_mode.dm @@ -0,0 +1,87 @@ +/datum/buildmode_mode + var/key = "oops" + + var/datum/click_intercept/buildmode/BM + + var/use_corner_selection = FALSE + var/processing_selection = FALSE + var/list/preview + var/turf/cornerA + var/turf/cornerB + +/datum/buildmode_mode/New(datum/click_intercept/buildmode/newBM) + BM = newBM + preview = list() + return ..() + +/datum/buildmode_mode/Destroy() + Reset() + return ..() + +/datum/buildmode_mode/proc/enter_mode(datum/click_intercept/buildmode/BM) + return + +/datum/buildmode_mode/proc/exit_mode(datum/click_intercept/buildmode/BM) + return + +/datum/buildmode_mode/proc/get_button_iconstate() + return "buildmode_[key]" + +/datum/buildmode_mode/proc/show_help(mob/user) + CRASH("No help defined, yell at a coder") + to_chat(user, "There is no help defined for this mode, this is a bug.") + +/datum/buildmode_mode/proc/change_settings(mob/user) + to_chat(user, "There is no configuration available for this mode") + +/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" + preview += image('icons/turf/overlays.dmi', T, overlaystate) + BM.holder.images += preview + return T + +/datum/buildmode_mode/proc/highlight_region(region) + BM.holder.images -= preview + for(var/t in region) + preview += image('icons/turf/overlays.dmi', T, "redOverlay") + BM.holder.images += preview + +/datum/buildmode_mode/proc/deselect_region() + BM.holder.images -= preview + QDEL_LIST(preview) + cornerA = null + cornerB = null + +/datum/buildmode_mode/proc/handle_click(user, 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 + else if(!cornerB) + cornerB = select_tile(get_turf(object), AREASELECT_CORNERB) + to_chat(user, "Region selected, if you're happy with your selection left click again, otherwise right click.") + return + if(processing_selection) + return + processing_selection = TRUE + handle_selected_region(user, params) + processing_selection = FALSE + deselect_region() + else if(cornerA || cornerB) + to_chat(user, "Region selection canceled!") + deselect_region() + +/datum/buildmode_mode/proc/handle_selected_region(mob/user, params) + return \ 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 00000000000..934eba8117c --- /dev/null +++ b/code/modules/buildmode/buildmode.dm @@ -0,0 +1,127 @@ +#define BM_SWITCHSTATE_NONE 0 +#define BM_SWITCHSTATE_MODE 1 +#define BM_SWITCHSTATE_DIR 2 + +/datum/click_intercept/buildmode + var/build_dir = SOUTH + var/datum/buildmode_mode/mode + + // SECTION UI + + // 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/click_intercept/buildmode/New() + mode = new /datum/buildmode_mode/basic(src) + . = ..() + mode.enter_mode(src) + +/datum/click_intercept/buildmode/Destroy() + close_switchstates() + QDEL_NULL(mode) + QDEL_LIST(modeswitch_buttons) + QDEL_LIST(dirswitch_buttons) + return ..() + +/datum/click_intercept/buildmode/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 list of modeswitching 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) + +/datum/click_intercept/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/click_intercept/buildmode/proc/close_switchstates() + switch(switch_state) + if(BM_SWITCHSTATE_MODE) + close_modeswitch() + if(BM_SWITCHSTATE_DIR) + close_dirswitch() + +/datum/click_intercept/buildmode/proc/toggle_modeswitch() + if(switch_state == BM_SWITCHSTATE_MODE) + close_modeswitch() + else + close_switchstates() + open_modeswitch() + +/datum/click_intercept/buildmode/proc/open_modeswitch() + switch_state = BM_SWITCHSTATE_MODE + holder.screen += modeswitch_buttons + +/datum/click_intercept/buildmode/proc/close_modeswitch() + switch_state = BM_SWITCHSTATE_NONE + holder.screen -= modeswitch_buttons + +/datum/click_intercept/buildmode/proc/toggle_dirswitch() + if(switch_state == BM_SWITCHSTATE_DIR) + close_dirswitch() + else + close_switchstates() + open_dirswitch() + +/datum/click_intercept/buildmode/proc/open_dirswitch() + switch_state = BM_SWITCHSTATE_DIR + holder.screen += dirswitch_buttons + +/datum/click_intercept/buildmode/proc/close_dirswitch() + switch_state = BM_SWITCHSTATE_NONE + holder.screen -= dirswitch_buttons + +/datum/click_intercept/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/click_intercept/buildmode/proc/change_dir(newdir) + build_dir = newdir + close_dirswitch() + dirbutton.update_icon() + return TRUE + +/datum/click_intercept/buildmode/InterceptClickOn(user, params, atom/object) + mode.handle_click(user, params, object) + +/proc/togglebuildmode(mob/M in player_list) + set name = "Toggle Build Mode" + set category = "Event" + + if(M.client) + if(istype(M.client.click_intercept, /datum/click_intercept/buildmode)) + var/datum/click_intercept/buildmode/B = M.client.click_intercept + B.quit() + log_admin("[key_name(usr)] has left build mode.") + else + new/datum/click_intercept/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 00000000000..c07be97a9eb --- /dev/null +++ b/code/modules/buildmode/buttons.dm @@ -0,0 +1,88 @@ +/obj/screen/buildmode + icon = 'icons/misc/buildmode.dmi' + var/datum/click_intercept/buildmode/bd + layer = HUD_LAYER_BUILDMODE + +/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) + update_icon() + return TRUE + +/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() + bd.mode.show_help(usr) + return TRUE + +/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 + +/obj/screen/buildmode/bdir/Click() + bd.toggle_dirswitch() + update_icon() + return TRUE + +// 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 TRUE + +// used to switch between dirs +/obj/screen/buildmode/dirswitch + icon_state = "build" + +/obj/screen/buildmode/dirswitch/New(bld, newdir) + dir = newdir + name = dir2text(dir) + return ..(bld) + +/obj/screen/buildmode/dirswitch/Click() + bd.change_dir(dir) + return TRUE + +/obj/screen/buildmode/quit + icon_state = "buildquit" + screen_loc = "NORTH,WEST+3" + name = "Quit Buildmode" + +/obj/screen/buildmode/quit/Click() + bd.quit() + return TRUE \ 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 00000000000..4b59e8a673c --- /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 00000000000..fadd46753bb --- /dev/null +++ b/code/modules/buildmode/submodes/advanced.dm @@ -0,0 +1,59 @@ +/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(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Right Mouse Button on buildmode button = Set object type") + to_chat(user, "Left Mouse Button + alt on turf/obj = Copy object type") + to_chat(user, "Left Mouse Button on turf/obj = Place objects") + to_chat(user, "Right Mouse Button = Delete objects") + to_chat(user, "") + to_chat(user, "Use the button in the upper left corner to") + to_chat(user, "change the direction of built objects.") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/advanced/change_settings(mob/user) + 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) + 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(user, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + var/alt_click = pa.Find("alt") + + if(left_click && alt_click) + if (isturf(object) || isobj(object) || ismob(object)) + objholder = object.type + to_chat(user, "[initial(object.name)] ([object.type]) selected.") + else + to_chat(user, "[initial(object.name)] is not a turf, object, or mob! Please select again.") + else if(left_click) + if(ispath(objholder,/turf)) + var/turf/T = get_turf(object) + log_admin("Build Mode: [key_name(user)] modified [T] ([T.x],[T.y],[T.z]) 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(user)] modified [A]'s ([A.x],[A.y],[A.z]) dir to [BM.build_dir]") + else + to_chat(user, "Select object type first.") + else if(right_click) + if(isobj(object)) + log_admin("Build Mode: [key_name(user)] deleted [object] at ([object.x],[object.y],[object.z])") + 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 00000000000..d60950d294f --- /dev/null +++ b/code/modules/buildmode/submodes/area_edit.dm @@ -0,0 +1,59 @@ +/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/click_intercept/buildmode/BM) + BM.holder.images += areaimage + +/datum/buildmode_mode/area_edit/exit_mode(datum/click_intercept/buildmode/BM) + areaimage.loc = null // de-color the area + BM.holder.images -= areaimage + return ..() + +/datum/buildmode_mode/area_edit/Destroy() + QDEL_NULL(areaimage) + return ..() + +/datum/buildmode_mode/area_edit/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on obj/turf/mob = Paint area") + to_chat(user, "Right Mouse Button on obj/turf/mob = Select area to paint") + to_chat(user, "Right Mouse Button on buildmode button = Create new area") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/area_edit/change_settings(mob/user) + var/target_path = input(user,"Enter typepath:", "Typepath", "/area") + var/areatype = text2path(target_path) + if(ispath(areatype,/area)) + var/areaname = input(user,"Enter area name:", "Area name", "Area") + if(!areaname || !length(areaname)) + return + storedarea = new areatype + storedarea.power_equip = 0 + storedarea.power_light = 0 + storedarea.power_environ = 0 + storedarea.always_unpowered = 0 + storedarea.name = areaname + areaimage.loc = storedarea // color our area + +/datum/buildmode_mode/area_edit/handle_click(user, 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(user, "Configure or select the area you want to paint first!") + return + var/turf/T = get_turf(object) + if(get_area(T) != storedarea) + storedarea.contents.Add(T) + else if(right_click) + var/turf/T = get_turf(object) + storedarea = get_area(T) + areaimage.loc = storedarea // color our area diff --git a/code/modules/buildmode/submodes/atmos.dm b/code/modules/buildmode/submodes/atmos.dm new file mode 100644 index 00000000000..f12fdb1eb1a --- /dev/null +++ b/code/modules/buildmode/submodes/atmos.dm @@ -0,0 +1,72 @@ +/datum/buildmode_mode/atmos + key = "atmos" + + use_corner_selection = TRUE + var/pressure = ONE_ATMOSPHERE + var/temperature = T20C + var/oxygen = O2STANDARD + var/nitrogen = N2STANDARD + var/plasma = 0 + var/cdiox = 0 + var/nitrox = 0 + + +/datum/buildmode_mode/atmos/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on turf = Select corner") + to_chat(user, "Left Mouse Button + Ctrl on turf = Set 'base atmos conditions' for unsimulated turfs in region") + to_chat(user, "Right Mouse Button on buildmode button = Adjust target atmos") + to_chat(user, "Notice: Starts out with standard breathable/liveable defaults") + to_chat(user, "***********************************************************") + +// FIXME this is a little tedious, something where you don't have to fill in each field would be cooler +// maybe some kind of stat panel thing? +/datum/buildmode_mode/atmos/change_settings(mob/user) + pressure = input(user, "Atmospheric Pressure", "Input", ONE_ATMOSPHERE) as num|null + temperature = input(user, "Temperature", "Input", T20C) as num|null + oxygen = input(user, "Oxygen ratio", "Input", O2STANDARD) as num|null + nitrogen = input(user, "Nitrogen ratio", "Input", N2STANDARD) as num|null + plasma = input(user, "Plasma ratio", "Input", 0) as num|null + cdiox = input(user, "CO2 ratio", "Input", 0) as num|null + nitrox = input(user, "N2O ratio", "Input", 0) as num|null + +/datum/buildmode_mode/atmos/proc/ppratio_to_moles(ppratio) + // ideal gas equation: Pressure * Volume = Moles * r * Temperature + // air datum fields are in moles, we have partial pressure ratios + // Moles = (Pressure * Volume) / (r * Temperature) + return ((ppratio * pressure) * CELL_VOLUME) / (temperature * R_IDEAL_GAS_EQUATION) + +/datum/buildmode_mode/atmos/handle_selected_region(mob/user, params) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/ctrl_click = pa.Find("ctrl") + if(left_click) //rectangular + for(var/turf/T in block(cornerA,cornerB)) + if(istype(T, /turf/simulated)) + // fill the turf with the appropriate gasses + // this feels slightly icky + var/turf/simulated/S = T + if(S.air) + S.air.temperature = temperature + S.air.oxygen = ppratio_to_moles(oxygen) + S.air.nitrogen = ppratio_to_moles(nitrogen) + S.air.toxins = ppratio_to_moles(plasma) + S.air.carbon_dioxide = ppratio_to_moles(cdiox) + S.air.trace_gases.Cut() + if(nitrox) + var/datum/gas/TG = new /datum/gas/sleeping_agent + TG.moles = ppratio_to_moles(nitrox) + S.air.trace_gases += TG + S.update_visuals() + S.air_update_turf() + else if(ctrl_click) // overwrite "default" unsimulated air + T.temperature = temperature + T.oxygen = ppratio_to_moles(oxygen) + T.nitrogen = ppratio_to_moles(nitrogen) + T.toxins = ppratio_to_moles(plasma) + T.carbon_dioxide = ppratio_to_moles(cdiox) + // no interface for trace gases on unsim turfs + T.air_update_turf() + + // admin log + log_admin("Build Mode: [key_name(user)] changed the atmos of region [COORD(cornerA)] to [COORD(cornerB)]. T: [temperature], P: [pressure], Ox: [oxygen]%, N2: [nitrogen]%, Plsma: [plasma]%, CO2: [cdiox]%, N2O: [nitrox]%. [ctrl_click ? "Overwrote base unsimulated turf gases." : ""]") \ No newline at end of file diff --git a/code/modules/buildmode/submodes/basic.dm b/code/modules/buildmode/submodes/basic.dm new file mode 100644 index 00000000000..1ca36920c64 --- /dev/null +++ b/code/modules/buildmode/submodes/basic.dm @@ -0,0 +1,50 @@ +/datum/buildmode_mode/basic + key = "basic" + +/datum/buildmode_mode/basic/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button = Construct / Upgrade") + to_chat(user, "Right Mouse Button = Deconstruct / Delete / Downgrade") + to_chat(user, "Left Mouse Button + ctrl = R-Window") + to_chat(user, "Left Mouse Button + alt = Airlock") + to_chat(user, "") + to_chat(user, "Use the button in the upper left corner to") + to_chat(user, "change the direction of built objects.") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/basic/handle_click(user, 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(istype(object,/turf/space)) + T.ChangeTurf(/turf/simulated/floor/plasteel) + else if(istype(object,/turf/simulated/floor)) + T.ChangeTurf(/turf/simulated/wall) + else if(istype(object,/turf/simulated/wall)) + T.ChangeTurf(/turf/simulated/wall/r_wall) + log_admin("Build Mode: [key_name(user)] built [T] at ([T.x],[T.y],[T.z])") + else if(right_click) + log_admin("Build Mode: [key_name(user)] deleted [object] at ([object.x],[object.y],[object.z])") + if(istype(object,/turf/simulated/wall)) + var/turf/T = object + T.ChangeTurf(/turf/simulated/floor/plasteel) + else if(istype(object,/turf/simulated/floor)) + var/turf/T = object + T.ChangeTurf(/turf/space) + else if(istype(object,/turf/simulated/wall/r_wall)) + var/turf/T = object + T.ChangeTurf(/turf/simulated/wall) + else if(istype(object,/obj)) + qdel(object) + else if(istype(object,/turf) && alt_click && left_click) + log_admin("Build Mode: [key_name(user)] built an airlock at ([object.x],[object.y],[object.z])") + new/obj/machinery/door/airlock(get_turf(object)) + else if(istype(object,/turf) && ctrl_click && left_click) + var/obj/structure/window/reinforced/WIN = new/obj/structure/window/reinforced(get_turf(object)) + WIN.setDir(BM.build_dir) + log_admin("Build Mode: [key_name(user)] built a window at ([object.x],[object.y],[object.z])") diff --git a/code/modules/buildmode/submodes/boom.dm b/code/modules/buildmode/submodes/boom.dm new file mode 100644 index 00000000000..271e5c01bc5 --- /dev/null +++ b/code/modules/buildmode/submodes/boom.dm @@ -0,0 +1,32 @@ +/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(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Mouse Button on obj = Kaboom") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/boom/change_settings(mob/user) + devastation = input("Range of total devastation. -1 to none", text("Input")) as num|null + if(devastation == null) devastation = -1 + heavy = input("Range of heavy impact. -1 to none", text("Input")) as num|null + if(heavy == null) heavy = -1 + light = input("Range of light impact. -1 to none", text("Input")) as num|null + if(light == null) light = -1 + flash = input("Range of flash. -1 to none", text("Input")) as num|null + if(flash == null) flash = -1 + flames = input("Range of flames. -1 to none", text("Input")) as num|null + if(flames == null) flames = -1 + +/datum/buildmode_mode/boom/handle_click(user, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + + if(left_click) + explosion(object, devastation, heavy, light, flash, null, TRUE, flames) diff --git a/code/modules/buildmode/submodes/copy.dm b/code/modules/buildmode/submodes/copy.dm new file mode 100644 index 00000000000..48cbb2c3cf0 --- /dev/null +++ b/code/modules/buildmode/submodes/copy.dm @@ -0,0 +1,27 @@ +/datum/buildmode_mode/copy + key = "copy" + var/atom/movable/stored = null + +/datum/buildmode_mode/copy/exit_mode() + stored = null + return ..() + +/datum/buildmode_mode/copy/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on obj/turf/mob = Spawn a Copy of selected target") + to_chat(user, "Right Mouse Button on obj/mob = Select target to copy") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/copy/handle_click(user, 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) + else if(right_click) + if(ismovableatom(object)) // No copying turfs for now. + to_chat(user, "[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 00000000000..b143b2c9b90 --- /dev/null +++ b/code/modules/buildmode/submodes/fill.dm @@ -0,0 +1,49 @@ +/datum/buildmode_mode/fill + key = "fill" + + use_corner_selection = TRUE + var/objholder = null + +/datum/buildmode_mode/fill/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on turf/obj/mob = Select corner") + to_chat(user, "Left Mouse Button + Alt on turf/obj/mob = Delete region") + to_chat(user, "Right Mouse Button on buildmode button = Select object type") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/fill/change_settings(mob/user) + 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) + 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(mob/user, params, obj/object) + if(isnull(objholder)) + to_chat(user, "Select an object type first.") + deselect_region() + return + ..() + +/datum/buildmode_mode/fill/handle_selected_region(mob/user, 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) + empty_region(block(cornerA,cornerB)) + else + for(var/turf/T in block(cornerA,cornerB)) + if(ispath(objholder,/turf)) + T.ChangeTurf(objholder) + else + var/obj/A = new objholder(T) + A.setDir(BM.build_dir) \ No newline at end of file diff --git a/code/modules/buildmode/submodes/link.dm b/code/modules/buildmode/submodes/link.dm new file mode 100644 index 00000000000..153b5a7698e --- /dev/null +++ b/code/modules/buildmode/submodes/link.dm @@ -0,0 +1,94 @@ +/datum/buildmode_mode/link + key = "link" + + var/list/link_lines = list() + var/obj/link_obj + + +/datum/buildmode_mode/link/proc/clear_lines() + QDEL_LIST(link_lines) + +/datum/buildmode_mode/link/proc/form_connection(atom/source, atom/dest, valid) + var/obj/effect/buildmode_line/L = new(BM.holder, source, dest, "[source.name] to [dest.name]") + L.color = valid ? "#339933" : "#993333" + link_lines += L + var/obj/effect/buildmode_line/L2 = new(BM.holder, dest, source, "[dest.name] to [source.name]") // Yes, reversed one so that you can see it source both sides. + L2.color = L.color + link_lines += L2 + +/datum/buildmode_mode/link/Destroy() + clear_lines() + link_obj = null + return ..() + +/datum/buildmode_mode/link/Reset() + clear_lines() + link_obj = null + ..() + +/datum/buildmode_mode/link/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on obj = Select button to link") + to_chat(user, "Right Mouse Button on obj = Link/unlink to selected button") + to_chat(user, "***********************************************************") + +// FIXME: this probably would work better with something component-based +/datum/buildmode_mode/link/handle_click(mob/user, params, obj/object) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + var/right_click = pa.Find("right") + if(left_click && istype(object, /obj/machinery)) + link_obj = object + if(right_click && istype(object, /obj/machinery)) + if(istype(link_obj, /obj/machinery/door_control) && istype(object, /obj/machinery/door/airlock)) + var/obj/machinery/door_control/M = link_obj + var/obj/machinery/door/airlock/P = object + if(!M.id || M.id == "") + M.id = input(user, "Please select an ID for the button", "Buildmode", "") + if(!M.id || M.id == "") + goto(line_jump) + if(P.id_tag == M.id && (P in range(M.range, M)) && P.id_tag && P.id_tag != "") + P.id_tag = null + to_chat(user, "[P] unlinked.") + goto(line_jump) + if(!M.normaldoorcontrol) + if(link_lines.len && alert(user, "Warning: This will disable links to connected pod doors. Continue?", "Buildmode", "Yes", "No") == "No") + goto(line_jump) + M.normaldoorcontrol = 1 + if(P.id_tag && alert(user, "Warning: This will unlink something else from the door. Continue?", "Buildmode", "Yes", "No") == "No") + goto(line_jump) + P.id_tag = M.id + if(istype(link_obj, /obj/machinery/door_control) && istype(object, /obj/machinery/door/poddoor)) + var/obj/machinery/door_control/M = link_obj + var/obj/machinery/door/poddoor/P = object + if(!M.id || M.id == "") + M.id = input(user, "Please select an ID for the button", "Buildmode", "") + if(!M.id || M.id == "") + goto(line_jump) + if(P.id_tag == M.id && P.id_tag && P.id_tag != "") + P.id_tag = null + to_chat(user, "[P] unlinked.") + goto(line_jump) + if(M.normaldoorcontrol) + if(link_lines.len && alert(user, "Warning: This will disable links to connected airlocks. Continue?", "Buildmode", "Yes", "No") == "No") + goto(line_jump) + M.normaldoorcontrol = 0 + if(!M.id || M.id == "") + M.id = input(user, "Please select an ID for the button", "Buildmode", "") + if(!M.id || M.id == "") + goto(line_jump) + if(P.id_tag && P.id_tag != 1 && alert(user, "Warning: This will unlink something else from the door. Continue?", "Buildmode", "Yes", "No") == "No") + goto(line_jump) + P.id_tag = M.id + + line_jump // For the goto + clear_lines() + + if(istype(link_obj, /obj/machinery/door_control)) + var/obj/machinery/door_control/M = link_obj + for(var/obj/machinery/door/airlock/P in range(M.range,M)) + if(P.id_tag == M.id) + form_connection(M, P, M.normaldoorcontrol) + for(var/obj/machinery/door/poddoor/P in airlocks) + if(P.id_tag == M.id) + form_connection(M, P, !M.normaldoorcontrol) diff --git a/code/modules/buildmode/submodes/mapgen.dm b/code/modules/buildmode/submodes/mapgen.dm new file mode 100644 index 00000000000..22be429c2ce --- /dev/null +++ b/code/modules/buildmode/submodes/mapgen.dm @@ -0,0 +1,40 @@ +/datum/buildmode_mode/mapgen + key = "mapgen" + + use_corner_selection = TRUE + var/generator_path + +/datum/buildmode_mode/mapgen/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on turf/obj/mob = Select corner") + to_chat(user, "Right Mouse Button on buildmode button = Select generator") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/mapgen/change_settings(mob/user) + var/list/gen_paths = subtypesof(/datum/mapGenerator) + + var/type = input(user,"Select Generator Type","Type") as null|anything in gen_paths + if(!type) return + + generator_path = type + deselect_region() + +/datum/buildmode_mode/mapgen/handle_click(mob/user, params, obj/object) + if(isnull(generator_path)) + to_chat(user, "Select generator type first.") + deselect_region() + return + ..() + +/datum/buildmode_mode/mapgen/handle_selected_region(mob/user, params) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + + if(left_click) //rectangular + if(cornerA && cornerB) + var/datum/mapGenerator/G = new generator_path + 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() \ No newline at end of file diff --git a/code/modules/buildmode/submodes/save.dm b/code/modules/buildmode/submodes/save.dm new file mode 100644 index 00000000000..43a1f9af174 --- /dev/null +++ b/code/modules/buildmode/submodes/save.dm @@ -0,0 +1,28 @@ +/datum/buildmode_mode/save + key = "save" + + use_corner_selection = TRUE + var/use_json = TRUE + +/datum/buildmode_mode/save/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on turf/obj/mob = Select corner") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/save/change_settings(mob/user) + use_json = (alert("Would you like to use json (Default is \"Yes\")?",,"Yes","No") == "Yes") + +/datum/buildmode_mode/save/handle_selected_region(mob/user, params) + var/list/pa = params2list(params) + var/left_click = pa.Find("left") + if(left_click) + var/map_name = input(user, "Please select a name for your map", "Buildmode", "") + if(map_name == "") + return + var/map_flags = 0 + if(use_json) + map_flags = 32 // Magic number defined in `writer.dm` that I can't use directly + // because #defines are for some reason our coding standard + var/our_map = maploader.save_map(cornerA, cornerB, map_name, map_flags) + user << ftp(our_map) // send the map they've made! Or are stealing, whatever + to_chat(user, "Map saving complete! [our_map]") diff --git a/code/modules/buildmode/submodes/sdql.dm b/code/modules/buildmode/submodes/sdql.dm new file mode 100644 index 00000000000..104b7bd7af6 --- /dev/null +++ b/code/modules/buildmode/submodes/sdql.dm @@ -0,0 +1,12 @@ +// SKELETON CODE, not yet functional + +/datum/buildmode_mode/sdql + key = "sdql" + + var/sdql_command = "SELECT /turf IN" + +/datum/buildmode_mode/sdql/show_help(mob/user) + +/datum/buildmode_mode/sdql/change_settings(mob/user) + +/datum/buildmode_mode/sdql/handle_click(mob/user, params, obj/object) diff --git a/code/modules/buildmode/submodes/throwing.dm b/code/modules/buildmode/submodes/throwing.dm new file mode 100644 index 00000000000..24470a680b5 --- /dev/null +++ b/code/modules/buildmode/submodes/throwing.dm @@ -0,0 +1,25 @@ +/datum/buildmode_mode/throwing + key = "throw" + + var/atom/movable/throw_atom = null + +/datum/buildmode_mode/throwing/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Left Mouse Button on turf/obj/mob = Select") + to_chat(user, "Right Mouse Button on turf/obj/mob = Throw") + to_chat(user, "***********************************************************") + +/datum/buildmode_mode/throwing/handle_click(user, 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(user, "Selected object '[throw_atom]'") + 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] ([object.x],[object.y],[object.z])") diff --git a/code/modules/buildmode/submodes/variable_edit.dm b/code/modules/buildmode/submodes/variable_edit.dm new file mode 100644 index 00000000000..ebf0035bccf --- /dev/null +++ b/code/modules/buildmode/submodes/variable_edit.dm @@ -0,0 +1,55 @@ +/datum/buildmode_mode/varedit + key = "edit" + // Varedit mode + var/varholder = "name" + var/valueholder = "value" + +/datum/buildmode_mode/varedit/show_help(mob/user) + to_chat(user, "***********************************************************") + to_chat(user, "Right Mouse Button on buildmode button = Select var(type) & value") + to_chat(user, "Left Mouse Button on turf/obj/mob = Set var(type) & value") + to_chat(user, "Right Mouse Button on turf/obj/mob = Reset var's value") + to_chat(user, "***********************************************************") + +// FIXME: This needs to use a standard var-editing interface instead of +// doing its own thing here +/datum/buildmode_mode/varedit/change_settings(mob/user) + var/temp_varname = input(user,"Enter variable name:", "Name", "name") + if(!vv_varname_lockcheck(temp_varname)) + return + + var/temp_value = user.client.vv_get_value() + if(isnull(temp_value["class"])) + Reset() + to_chat(user, "Variable unset.") + return + // we assign this once all user input is done, since things could get wonky otherwise + varholder = temp_varname + valueholder = temp_value["value"] + +/datum/buildmode_mode/varedit/handle_click(user, 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(user, "Choose a variable to modify first.") + return + if(left_click) + if(object.vars.Find(varholder)) + if(!object.vv_edit_var(varholder, valueholder)) + to_chat(user, "Your edit was rejected by [object].") + return + log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [valueholder]") + else + to_chat(user, "[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)) + to_chat(user, "Your edit was rejected by [object].") + return + log_admin("Build Mode: [key_name(user)] modified [object.name]'s [varholder] to [reset_value]") + else + to_chat(user, "[initial(object.name)] does not have a var called '[varholder]'") + diff --git a/icons/misc/buildmode.dmi b/icons/misc/buildmode.dmi index cc54e5aec0f..f0de428b6c5 100644 Binary files a/icons/misc/buildmode.dmi and b/icons/misc/buildmode.dmi differ diff --git a/icons/turf/overlays.dmi b/icons/turf/overlays.dmi index 03b0743f95d..add518c139b 100644 Binary files a/icons/turf/overlays.dmi and b/icons/turf/overlays.dmi differ diff --git a/paradise.dme b/paradise.dme index 59435f302a8..6a89af06354 100644 --- a/paradise.dme +++ b/paradise.dme @@ -224,6 +224,7 @@ #include "code\datums\beam.dm" #include "code\datums\browser.dm" #include "code\datums\callback.dm" +#include "code\datums\click_intercept.dm" #include "code\datums\datacore.dm" #include "code\datums\datum.dm" #include "code\datums\datumvars.dm" @@ -1076,7 +1077,6 @@ #include "code\modules\admin\admin_verbs.dm" #include "code\modules\admin\banappearance.dm" #include "code\modules\admin\banjob.dm" -#include "code\modules\admin\buildmode.dm" #include "code\modules\admin\create_mob.dm" #include "code\modules\admin\create_object.dm" #include "code\modules\admin\create_poll.dm" @@ -1207,6 +1207,22 @@ #include "code\modules\awaymissions\mission_code\stationCollision.dm" #include "code\modules\awaymissions\mission_code\UO71-terrorspiders.dm" #include "code\modules\awaymissions\mission_code\wildwest.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\atmos.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\link.dm" +#include "code\modules\buildmode\submodes\mapgen.dm" +#include "code\modules\buildmode\submodes\save.dm" +#include "code\modules\buildmode\submodes\throwing.dm" +#include "code\modules\buildmode\submodes\variable_edit.dm" #include "code\modules\busy_space\air_traffic.dm" #include "code\modules\busy_space\loremaster.dm" #include "code\modules\busy_space\organizations.dm"