diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index ed6e3cda15f5..afecabd74be0 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -123,10 +123,14 @@ SUBSYSTEM_DEF(mapping) ++i // load the maps - for (var/P in parsed_maps) - var/datum/parsed_map/pm = P - if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE)) + for (var/datum/parsed_map/pm as anything in parsed_maps) + var/cur_z = start_z + parsed_maps[pm] + if (!pm.load(1, 1, cur_z, no_changeturf = TRUE)) errorList |= pm.original_path + if(istype(z_list[cur_z], /datum/space_level)) + var/datum/space_level/cur_level = z_list[cur_z] + cur_level.x_bounds = pm.bounds[MAP_MAXX] + cur_level.y_bounds = pm.bounds[MAP_MAXY] if(!silent) INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!") return parsed_maps diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 6154bb4f8c32..20ff65ed144e 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -191,6 +191,7 @@ var/list/admin_verbs_debug = list( /client/proc/restart_controller, /client/proc/debug_controller, /client/proc/cmd_debug_toggle_should_check_for_win, + /client/proc/cmd_debug_mass_screenshot, /client/proc/enable_debug_verbs, /client/proc/toggledebuglogs, /client/proc/togglenichelogs, diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 8a017446858d..6be6b14e0247 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -92,7 +92,74 @@ else message_admins("[key_name(src)] disabled checking for round-end.") +/client/proc/cmd_debug_mass_screenshot() + set category = "Debug" + set name = "Mass Screenshot" + set background = TRUE + set waitfor = FALSE + + if(!check_rights(R_MOD)) + return + if(tgui_alert(usr, "Are you sure you want to mass screenshot this z-level? Ensure your visual settings are correct first (other ghost visibility, zoom level, etc.) and you have emptied your BYOND/screenshots folder.", "Mass Screenshot", list("Yes", "No")) != "Yes") + return + + var/sleep_duration = tgui_input_number(usr, "Enter a delay in deciseconds between screenshots to allow the client to render changes.", "Screenshot delay", 2, 10, 1, 0, TRUE) + if(!sleep_duration) + return + + if(!mob) + return + + if(!isobserver(mob)) + admin_ghost() + + mob.alpha = 0 + if(mob.hud_used) + mob.hud_used.show_hud(HUD_STYLE_NOHUD) + mob.animate_movement = NO_STEPS + + message_admins(WRAP_STAFF_LOG(usr, "started a mass screenshot operation.")) + + var/half_chunk_size = view + 1 + var/chunk_size = half_chunk_size * 2 - 1 + var/cur_x = half_chunk_size + var/cur_y = half_chunk_size + var/cur_z = mob.z + var/width + var/height + if(istype(SSmapping.z_list[cur_z], /datum/space_level)) + var/datum/space_level/cur_level = SSmapping.z_list[cur_z] + width = cur_level.x_bounds - half_chunk_size + 2 + height = cur_level.y_bounds - half_chunk_size + 2 + else + width = world.maxx - half_chunk_size + 2 + height = world.maxy - half_chunk_size + 2 + var/width_inside = width - 1 + var/height_inside = height - 1 + + while(cur_y < height) + while(cur_x < width) + mob.on_mob_jump() + mob.forceMove(locate(cur_x, cur_y, cur_z)) + sleep(sleep_duration) + winset(src, null, "command='.screenshot auto'") + if(cur_x == width_inside) + break + cur_x += chunk_size + cur_x = min(cur_x, width_inside) + if(cur_y == height_inside) + break + cur_x = half_chunk_size + cur_y += chunk_size + cur_y = min(cur_y, height_inside) + + mob.alpha = initial(mob.alpha) + if(mob.hud_used) + mob.hud_used.show_hud(HUD_STYLE_STANDARD) + mob.animate_movement = SLIDE_STEPS // Initial is incorrect + + to_chat(usr, "Provide these values when asked for the MapTileImageTool: [width] [height] [half_chunk_size] [world.icon_size]") //TODO: merge the vievars version into this or something maybe mayhaps /client/proc/cmd_debug_del_all() diff --git a/code/modules/mapping/space_management/space_level.dm b/code/modules/mapping/space_management/space_level.dm index 86958c5b41b4..861258aa20a2 100644 --- a/code/modules/mapping/space_management/space_level.dm +++ b/code/modules/mapping/space_management/space_level.dm @@ -4,11 +4,13 @@ var/list/traits var/z_value = 1 //actual z placement var/linkage = SELFLOOPING - var/xi - var/yi //imaginary placements on the grid + var/x_bounds + var/y_bounds /datum/space_level/New(new_z, new_name, list/new_traits = list()) z_value = new_z name = new_name traits = new_traits //set_linkage(new_traits[ZTRAIT_LINKAGE]) + x_bounds = world.maxx + y_bounds = world.maxy diff --git a/tools/MapTileImageTool/MapTileImageTool.py b/tools/MapTileImageTool/MapTileImageTool.py new file mode 100644 index 000000000000..cf0919c3a88b --- /dev/null +++ b/tools/MapTileImageTool/MapTileImageTool.py @@ -0,0 +1,85 @@ +#This script processes screenshots from the Mass-Screenshot Debug verb in SS13 into a full map image + +# Loosely based on https://github.com/vortex1942/telescience/blob/master/src/tools/PhotoProcessor.py + +# This script uses the Pillow library (PIL) install it with pip install pillow + +#***************************************************************** +#******ALL .pngs in the rawimages folder will be processed******** +#********Exported file may be overwritten in the output*********** +#***************************************************************** + +from PIL import Image +from os import listdir, path + +# Selection of Input/Output directories +rawimgdir = str(input("Directory of RAW images: ")) +if path.exists(rawimgdir) == False: + print("Directory could not be found!") + exit(1) + +imgdir = str(input("Directory for output image (leave blank to use RAW image directory): ")) +if imgdir == "": + imgdir = rawimgdir +elif path.exists(imgdir) == False: + print("Directory could not be found!") + exit(1) + +exportfilename = str(input("Filename for Full Image (E.g LV624_Complete): ")) +if exportfilename == "": + print("Filename is invalid!") + exit(1) + +gamearguments = str(input("Values provided after using the Mass-Screenshot verb: ")) +gamearguments = gamearguments.split() +if len(gamearguments) != 4: + print("Invalid arguments!") + exit(1) +pixelsize = int(gamearguments[3]) +halfchunksize = int(gamearguments[2]) +width = (int(gamearguments[0]) + halfchunksize - 2) +height = (int(gamearguments[1]) + halfchunksize - 2) +if width < 1 or height < 1 or pixelsize < 1 or halfchunksize < 1 or halfchunksize * 2 >= width or halfchunksize * 2 >= height: + print("Invalid arguments!") + exit(1) +width *= pixelsize +height *= pixelsize +halfchunksize *= pixelsize + +# Function for saving the image (params: name=Filename, export=Image IMG variable) +def func_exportfullimage(name, export): + print("SAVING IMAGE") + file = (imgdir+"\\"+name+".png") + print(file) + file = open(file, "wb") + export.save(file) + +# Where the magic happens, Creates a canvas and pastes RAWimages in a grid fashion +masterexport = Image.new("RGBA", (width,height), color=(0,0,0,255)) +imagelist = [file for file in sorted(listdir(rawimgdir), key=lambda x: path.getmtime(rawimgdir+"\\"+x)) if file.endswith('.png')] +imagecount = len(imagelist) +chunksize = halfchunksize * 2 - pixelsize +x = fc = 0 +y = height - chunksize + +# For loop stitches RAw images together +for p in imagelist: + file = (rawimgdir+"\\"+p) + photo = Image.open(file).convert("RGBA") + #Verbose mode [Iteration] [Image Coords] [RAW Filename] + #print("iter: " f"{fc : >2}", "IMG XY: " f"{x : >4}", f"{y : >4}", "FILE: " f"{p : >13}") + masterexport.paste(photo, (x, y)) + x += chunksize + fc += 1 + if x >= width: + x = 0 + y -= chunksize + y = max(y, 0) + progress = fc / imagecount * 100 + print("%.1f" % progress, "%") + x = min(x, width - chunksize) + +func_exportfullimage(exportfilename, masterexport) + +# Hopefully you got this far +print("COMPLETED :)")