diff --git a/code/game/objects/items/poi_items.dm b/code/game/objects/items/poi_items.dm index 394212e4c48..af1b6c9c7aa 100644 --- a/code/game/objects/items/poi_items.dm +++ b/code/game/objects/items/poi_items.dm @@ -54,7 +54,7 @@ name = "SCP" /obj/structure/largecrate/animal/crashedshuttle/initialize() - starts_with = pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble, /obj/item/weapon/deadringer) + starts_with = list(pick(/mob/living/simple_animal/hostile/statue, /obj/item/cursed_marble, /obj/item/weapon/deadringer)) // Starts_with has to be a list name = pick("Spicy Crust Pizzeria", "Soap and Care Products", "Sally's Computer Parts", "Steve's Chocolate Pastries", "Smith & Christian's Plastics","Standard Containers & Packaging Co.", "Sanitary Chemical Purgation (LTD)") name += " delivery crate" return ..() diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm index 7fde6c58e13..d0504e0223c 100644 --- a/code/modules/admin/verbs/map_template_loadverb.dm +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -10,13 +10,17 @@ return template = map_templates[map] + var/orientation = text2dir(input(usr, "Choose an orientation for this Map Template.", "Orientation") as null|anything in list("North", "South", "East", "West")) + if(!orientation) + return + var/turf/T = get_turf(mob) if(!T) return var/list/preview = list() - template.preload_size(template.mappath) - for(var/S in template.get_affected_turfs(T,centered = TRUE)) + template.preload_size(template.mappath, orientation) + for(var/S in template.get_affected_turfs(T,centered = TRUE, orientation=orientation)) preview += image('icons/misc/debug_group.dmi',S ,"red") usr.client.images += preview if(alert(usr,"Confirm location.", "Template Confirm","No","Yes") == "Yes") @@ -25,7 +29,7 @@ usr.client.images -= preview return - if(template.load(T, centered = TRUE)) + if(template.load(T, centered = TRUE, orientation=orientation)) message_admins("[key_name_admin(usr)] has placed a map template ([template.name]).") else to_chat(usr, "Failed to place map") @@ -41,14 +45,18 @@ if(!map) return template = map_templates[map] - - if(template.width > world.maxx || template.height > world.maxy) + + var/orientation = text2dir(input(usr, "Choose an orientation for this Map Template.", "Orientation") as null|anything in list("North", "South", "East", "West")) + if(!orientation) + return + + if(((orientation & (NORTH|SOUTH) && template.width > world.maxx || template.height > world.maxy) || ((orientation & (EAST|WEST)) && template.width > world.maxy || template.height > world.maxx))) if(alert(usr,"This template is larger than the existing z-levels. It will EXPAND ALL Z-LEVELS to match the size of the template. This may cause chaos. Are you sure you want to do this?","DANGER!!!","Cancel","Yes") == "Cancel") to_chat(usr,"Template placement aborted.") return - + if(alert(usr,"Confirm map load.", "Template Confirm","No","Yes") == "Yes") - if(template.load_new_z()) + if(template.load_new_z(orientation=orientation)) message_admins("[key_name_admin(usr)] has placed a map template ([template.name]) on Z level [world.maxz].") else to_chat(usr, "Failed to place map") diff --git a/code/modules/maps/tg/map_template.dm b/code/modules/maps/tg/map_template.dm index 2eb5aab12f6..65286578c6b 100644 --- a/code/modules/maps/tg/map_template.dm +++ b/code/modules/maps/tg/map_template.dm @@ -37,8 +37,8 @@ var/list/global/map_templates = list() if(rename) name = rename -/datum/map_template/proc/preload_size(path) - var/bounds = maploader.load_map(file(path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE) +/datum/map_template/proc/preload_size(path, orientation = SOUTH) + var/bounds = maploader.load_map(file(path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE, orientation=orientation) if(bounds) width = bounds[MAP_MAXX] // Assumes all templates are rectangular, have a single Z level, and begin at 1,1,1 height = bounds[MAP_MAXY] @@ -82,7 +82,7 @@ var/list/global/map_templates = list() admin_notice("Submap initializations finished.", R_DEBUG) -/datum/map_template/proc/load_new_z(var/centered = FALSE) +/datum/map_template/proc/load_new_z(var/centered = FALSE, var/orientation = SOUTH) var/x = 1 var/y = 1 @@ -90,7 +90,7 @@ var/list/global/map_templates = list() x = round((world.maxx - width)/2) y = round((world.maxy - height)/2) - var/list/bounds = maploader.load_map(file(mappath), x, y, no_changeturf = TRUE) + var/list/bounds = maploader.load_map(file(mappath), x, y, no_changeturf = TRUE, orientation=orientation) if(!bounds) return FALSE @@ -101,10 +101,10 @@ var/list/global/map_templates = list() log_game("Z-level [name] loaded at at [x],[y],[world.maxz]") return TRUE -/datum/map_template/proc/load(turf/T, centered = FALSE) +/datum/map_template/proc/load(turf/T, centered = FALSE, orientation = SOUTH) var/old_T = T if(centered) - T = locate(T.x - round(width/2) , T.y - round(height/2) , T.z) + T = locate(T.x - round(((orientation & NORTH|SOUTH) ? width : height)/2) , T.y - round(((orientation & NORTH|SOUTH) ? height : width)/2) , T.z) if(!T) return if(T.x+width > world.maxx) @@ -113,9 +113,9 @@ var/list/global/map_templates = list() return if(annihilate) - annihilate_bounds(old_T, centered) + annihilate_bounds(old_T, centered, orientation) - var/list/bounds = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE) + var/list/bounds = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE, orientation = orientation) if(!bounds) return @@ -129,18 +129,18 @@ var/list/global/map_templates = list() loaded++ return TRUE -/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE) +/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE, orientation = SOUTH) var/turf/placement = T if(centered) - var/turf/corner = locate(placement.x - round(width/2), placement.y - round(height/2), placement.z) + var/turf/corner = locate(placement.x - round(((orientation & NORTH|SOUTH) ? width : height)/2), placement.y - round(((orientation & NORTH|SOUTH) ? height : width)/2), placement.z) if(corner) placement = corner - return block(placement, locate(placement.x+width-1, placement.y+height-1, placement.z)) + return block(placement, locate(placement.x+((orientation & NORTH|SOUTH) ? width : height)-1, placement.y+((orientation & NORTH|SOUTH) ? height : width)-1, placement.z)) -/datum/map_template/proc/annihilate_bounds(turf/origin, centered = FALSE) +/datum/map_template/proc/annihilate_bounds(turf/origin, centered = FALSE, orientation = SOUTH) var/deleted_atoms = 0 admin_notice("Annihilating objects in submap loading locatation.", R_DEBUG) - var/list/turfs_to_clean = get_affected_turfs(origin, centered) + var/list/turfs_to_clean = get_affected_turfs(origin, centered, orientation) if(turfs_to_clean.len) for(var/turf/T in turfs_to_clean) for(var/atom/movable/AM in T) @@ -151,9 +151,9 @@ var/list/global/map_templates = list() //for your ever biggening badminnery kevinz000 //❤ - Cyberboss -/proc/load_new_z_level(var/file, var/name) +/proc/load_new_z_level(var/file, var/name, var/orientation = SOUTH) var/datum/map_template/template = new(file, name) - template.load_new_z() + template.load_new_z(orientation) // Very similar to the /tg/ version. /proc/seed_submaps(var/list/z_levels, var/budget = 0, var/whitelist = /area/space, var/desired_map_template_type = null) @@ -225,17 +225,19 @@ var/list/global/map_templates = list() var/specific_sanity = 100 // A hundred chances to place the chosen submap. while(specific_sanity > 0) specific_sanity-- - var/width_border = TRANSITIONEDGE + SUBMAP_MAP_EDGE_PAD + round(chosen_template.width / 2) - var/height_border = TRANSITIONEDGE + SUBMAP_MAP_EDGE_PAD + round(chosen_template.height / 2) + var/orientation = pick(cardinal) + chosen_template.preload_size(chosen_template.mappath, orientation) + var/width_border = TRANSITIONEDGE + SUBMAP_MAP_EDGE_PAD + round(((orientation & NORTH|SOUTH) ? chosen_template.width : chosen_template.height) / 2) + var/height_border = TRANSITIONEDGE + SUBMAP_MAP_EDGE_PAD + round(((orientation & NORTH|SOUTH) ? chosen_template.height : chosen_template.width) / 2) var/z_level = pick(z_levels) var/turf/T = locate(rand(width_border, world.maxx - width_border), rand(height_border, world.maxy - height_border), z_level) var/valid = TRUE - for(var/turf/check in chosen_template.get_affected_turfs(T,1)) + for(var/turf/check in chosen_template.get_affected_turfs(T,TRUE,orientation)) var/area/new_area = get_area(check) if(!(istype(new_area, whitelist))) valid = FALSE // Probably overlapping something important. - // world << "Invalid due to overlapping with area [new_area.type], when wanting area [whitelist]." + // world << "Invalid due to overlapping with area [new_area.type] at ([check.x], [check.y], [check.z]), when attempting to place at ([T.x], [T.y], [T.z])." break CHECK_TICK @@ -244,10 +246,10 @@ var/list/global/map_templates = list() if(!valid) continue - admin_notice("Submap \"[chosen_template.name]\" placed at ([T.x], [T.y], [T.z])", R_DEBUG) + admin_notice("Submap \"[chosen_template.name]\" placed at ([T.x], [T.y], [T.z])\n", R_DEBUG) // Do loading here. - chosen_template.load(T, centered = TRUE) // This is run before the main map's initialization routine, so that can initilize our submaps for us instead. + chosen_template.load(T, centered = TRUE, orientation=orientation) // This is run before the main map's initialization routine, so that can initilize our submaps for us instead. CHECK_TICK diff --git a/code/modules/maps/tg/reader.dm b/code/modules/maps/tg/reader.dm index 027d1c4cae1..ff66d4bdd2b 100644 --- a/code/modules/maps/tg/reader.dm +++ b/code/modules/maps/tg/reader.dm @@ -35,7 +35,7 @@ var/global/use_preloader = FALSE * 2) Read the map line by line, parsing the result (using parse_grid) * */ -/dmm_suite/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num, no_changeturf as num) +/dmm_suite/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num, no_changeturf as num, orientation as num) //How I wish for RAII if(!measureOnly) Master.StartLoadingMap() @@ -43,7 +43,7 @@ var/global/use_preloader = FALSE #ifdef TESTING turfsSkipped = 0 #endif - . = load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf) + . = load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, orientation) #ifdef TESTING if(turfsSkipped) testing("Skipped loading [turfsSkipped] default turfs") @@ -51,7 +51,7 @@ var/global/use_preloader = FALSE if(!measureOnly) Master.StopLoadingMap() -/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf) +/dmm_suite/proc/load_map_impl(dmm_file, x_offset, y_offset, z_offset, cropMap, measureOnly, no_changeturf, orientation) var/tfile = dmm_file//the map file we're creating if(isfile(tfile)) tfile = file2text(tfile) @@ -63,6 +63,10 @@ var/global/use_preloader = FALSE if(!z_offset) z_offset = world.maxz + 1 + // If it's not a single dir, default to north (Default orientation) + if(!orientation in cardinal) + orientation = SOUTH + var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF) var/list/grid_models = list() var/key_len = 0 @@ -132,14 +136,71 @@ var/global/use_preloader = FALSE bounds[MAP_MAXY] = max(bounds[MAP_MAXY], min(ycrd, world.maxy)) var/maxx = xcrdStart + + // Assemble the grid of keys + var/list/key_list = list() + for(var/line in gridLines) + var/list/line_keys = list() + xcrd = 1 + for(var/tpos = 1 to length(line) - key_len + 1 step key_len) + if(xcrd > world.maxx) + if(cropMap) + break + else + world.maxx = xcrd + + if(xcrd >= 1) + var/model_key = copytext(line, tpos, tpos + key_len) + line_keys[++line_keys.len] = model_key + #ifdef TESTING + else + ++turfsSkipped + #endif + CHECK_TICK + maxx = max(maxx, ++xcrd) + key_list[++key_list.len] = line_keys + + // Rotate the list according to orientation + if(orientation != SOUTH) + var/num_cols = key_list[1].len + var/num_rows = key_list.len + var/list/new_key_list = list() + // If it's rotated 180 degrees, the dimensions are the same + if(orientation == NORTH) + new_key_list.len = num_rows + for(var/i = 1 to new_key_list.len) + new_key_list[i] = list() + new_key_list[i].len = num_cols + // Else, the dimensions are swapped + else + new_key_list.len = num_cols + for(var/i = 1 to new_key_list.len) + new_key_list[i] = list() + new_key_list[i].len = num_rows + + num_rows++ // Buffering against the base index of 1 + num_cols++ + // Populate the new list + for(var/i = 1 to new_key_list.len) + for(var/j = 1 to new_key_list[i].len) + switch(orientation) + if(NORTH) + new_key_list[i][j] = key_list[num_rows - i][num_cols - j] + if(EAST) + new_key_list[i][j] = key_list[num_rows - j][i] + if(WEST) + new_key_list[i][j] = key_list[j][num_cols - i] + + key_list = new_key_list + if(measureOnly) - for(var/line in gridLines) - maxx = max(maxx, xcrdStart + length(line) / key_len - 1) + for(var/list/line in key_list) + maxx = max(maxx, line.len) else - for(var/line in gridLines) + for(var/i = 1 to key_list.len) if(ycrd <= world.maxy && ycrd >= 1) xcrd = xcrdStart - for(var/tpos = 1 to length(line) - key_len + 1 step key_len) + for(var/j = 1 to key_list[1].len) if(xcrd > world.maxx) if(cropMap) break @@ -147,12 +208,11 @@ var/global/use_preloader = FALSE world.maxx = xcrd if(xcrd >= 1) - var/model_key = copytext(line, tpos, tpos + key_len) var/no_afterchange = no_changeturf || zexpansion - if(!no_afterchange || (model_key != space_key)) - if(!grid_models[model_key]) - throw EXCEPTION("Undefined model key in DMM.") - parse_grid(grid_models[model_key], model_key, xcrd, ycrd, zcrd, no_changeturf || zexpansion) + if(!no_afterchange || (key_list[i][j] != space_key)) + if(!grid_models[key_list[i][j]]) + throw EXCEPTION("Undefined model key in DMM: [dmm_file], [key_list[i][j]]") + parse_grid(grid_models[key_list[i][j]], key_list[i][j], xcrd, ycrd, zcrd, no_afterchange, orientation) #ifdef TESTING else ++turfsSkipped @@ -194,7 +254,7 @@ var/global/use_preloader = FALSE * 4) Instanciates the atom with its variables * */ -/dmm_suite/proc/parse_grid(model as text, model_key as text, xcrd as num,ycrd as num,zcrd as num, no_changeturf as num) +/dmm_suite/proc/parse_grid(model as text, model_key as text, xcrd as num,ycrd as num,zcrd as num, no_changeturf as num, orientation as num) /*Method parse_grid() - Accepts a text string containing a comma separated list of type paths of the same construction as those contained in a .dmm file, and instantiates them. @@ -248,6 +308,12 @@ var/global/use_preloader = FALSE if(istext(value)) fields[I] = apply_text_macros(value) + // Rotate dir if orientation isn't south (default) + if(fields["dir"]) + fields["dir"] = turn(fields["dir"], dir2angle(orientation) + 180) + else + fields["dir"] = turn(SOUTH, dir2angle(orientation) + 180) + //then fill the members_attributes list with the corresponding variables members_attributes.len++ members_attributes[index++] = fields