mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
Map element (vault etc) updates: Item overwriting option, rotation on loading (#30957)
* First attempt at making rotated map element loading working * Fixes * Fixes * Oversight * Fixes offsets properly, ugly but works * Makes some vaults have ability to override it * Now properly sets these loaded in the exact position, if not a bit hacky * And now, the moment of truth, the actual rotation in loading itself, plus a server config * And a fix for this maybe * Overwriting of movable atoms support * Maybe like this? * Ah, the grid parsing was going counterclockwise by mistake, that's why it was doing that * Makes this show up in jump formatting * Rotated dungeons below * Initialising again after rotation is probably better * Fixing turfs ie. shuttle not rotating properly * Stops a runtime Co-authored-by: kanef <kanef9x@protonmail.com>
This commit is contained in:
@@ -183,6 +183,7 @@
|
||||
var/skip_minimap_generation = 0 //If 1, don't generate minimaps
|
||||
var/skip_holominimap_generation = 0 //If 1, don't generate holominimaps
|
||||
var/skip_vault_generation = 0 //If 1, don't generate vaults
|
||||
var/disable_vault_rotation = 0 //If 1, don't load vaults rotated
|
||||
var/shut_up_automatic_diagnostic_and_announcement_system = 0 //If 1, don't play the vox sounds at the start of every shift.
|
||||
var/no_lobby_music = 0 //If 1, don't play lobby music, regardless of client preferences.
|
||||
var/no_ambience = 0 //If 1, don't play ambience, regardless of client preferences.
|
||||
@@ -605,6 +606,8 @@
|
||||
skip_holominimap_generation = 1
|
||||
if("skip_vault_generation")
|
||||
skip_vault_generation = 1
|
||||
if("disable_vault_rotation")
|
||||
disable_vault_rotation = 1
|
||||
if("shut_up_automatic_diagnostic_and_announcement_system")
|
||||
shut_up_automatic_diagnostic_and_announcement_system = 1
|
||||
if("no_lobby_music")
|
||||
|
||||
@@ -14,6 +14,8 @@ var/list/datum/map_element/map_elements = list()
|
||||
|
||||
var/width //Width of the map element, in turfs
|
||||
var/height //Height of the map element, in turfs
|
||||
var/can_rotate = TRUE //Can this be rotated?
|
||||
var/rotation = 0 //The map's rotation value
|
||||
|
||||
/datum/map_element/proc/pre_load() //Called before loading the element
|
||||
return
|
||||
@@ -35,11 +37,12 @@ var/list/datum/map_element/map_elements = list()
|
||||
for(var/atom/A in objects)
|
||||
A.spawned_by_map_element(src, objects)
|
||||
|
||||
/datum/map_element/proc/load(x, y, z)
|
||||
/datum/map_element/proc/load(x, y, z, rotate=0)
|
||||
//Location is always lower left corner.
|
||||
//In some cases, location is set to null (when creating a new z-level, for example)
|
||||
//To account for that, location is set again in maploader's load_map() proc
|
||||
location = locate(x+1, y+1, z)
|
||||
rotation = rotate
|
||||
|
||||
if(!can_load(x,y))
|
||||
return 0
|
||||
@@ -49,7 +52,7 @@ var/list/datum/map_element/map_elements = list()
|
||||
if(file_path)
|
||||
var/file = file(file_path)
|
||||
if(isfile(file))
|
||||
var/list/L = maploader.load_map(file, z, x, y, src)
|
||||
var/list/L = maploader.load_map(file, z, x, y, src, rotate)
|
||||
initialize(L)
|
||||
return L
|
||||
else //No file specified - empty map element
|
||||
|
||||
@@ -1219,10 +1219,15 @@ var/list/admin_verbs_mod = list(
|
||||
return
|
||||
|
||||
|
||||
log_admin("[key_name(src)] is loading [ME.file_path] at [x_coord], [y_coord], [z_coord]")
|
||||
message_admins("[key_name_admin(src)] is loading [ME.file_path] at [x_coord], [y_coord], [z_coord]")
|
||||
ME.load(x_coord - 1, y_coord - 1, z_coord) //Reduce X and Y by 1 because these arguments are actually offsets, and they're added to 1;1 in the map loader. Without this, spawning something at 1;1 would result in it getting spawned at 2;2
|
||||
message_admins("[ME.file_path] loaded at [ME.location ? formatJumpTo(ME.location) : "[x_coord], [y_coord], [z_coord]"]")
|
||||
var/rotate = input(usr, "Set the rotation offset: (0, 90, 180 or 270) ", "Map element loading") as null|num
|
||||
if(rotate == null)
|
||||
return
|
||||
var/overwrite = alert("Overwrite original objects in area?","Map element loading","Yes","No") == "Yes"
|
||||
|
||||
log_admin("[key_name(src)] is loading [ME.file_path] at [x_coord], [y_coord], [z_coord] rotated by [rotate] degrees")
|
||||
message_admins("[key_name_admin(src)] is loading [ME.file_path] at [x_coord], [y_coord], [z_coord] rotated by [rotate] degrees")
|
||||
ME.load(x_coord - 1, y_coord - 1, z_coord, rotate, overwrite) //Reduce X and Y by 1 because these arguments are actually offsets, and they're added to 1;1 in the map loader. Without this, spawning something at 1;1 would result in it getting spawned at 2;2
|
||||
message_admins("[ME.file_path] loaded at [ME.location ? formatJumpTo(ME.location) : "[x_coord], [y_coord], [z_coord]"] rotated by [rotate] degrees")
|
||||
|
||||
/client/proc/create_awaymission()
|
||||
set category = "Admin"
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
var/list/vaults = list()
|
||||
|
||||
for(var/datum/map_element/V in map_elements)
|
||||
var/name = "[V.type_abbreviation] [V.name ? V.name : V.file_path] @ [V.location ? "[V.location.x],[V.location.y],[V.location.z]" : "UNKNOWN"]"
|
||||
var/name = "[V.type_abbreviation] [V.name ? V.name : V.file_path] @ [V.location ? "[V.location.x],[V.location.y],[V.location.z][V.rotation ? " (rotated by [V.rotation] degrees)" : ""]" : "UNKNOWN"]"
|
||||
|
||||
vaults[name] = V
|
||||
|
||||
|
||||
@@ -57,7 +57,13 @@ var/list/map_dimension_cache = list()
|
||||
* A list of all atoms created
|
||||
*
|
||||
*/
|
||||
/dmm_suite/load_map(var/dmm_file as file, var/z_offset as num, var/x_offset as num, var/y_offset as num, var/datum/map_element/map_element as null)
|
||||
/dmm_suite/load_map(var/dmm_file as file, var/z_offset as num, var/x_offset as num, var/y_offset as num, var/datum/map_element/map_element as null, var/rotate as num, var/overwrite as num)
|
||||
if((rotate % 90) != 0) //If not divisible by 90, make it
|
||||
rotate += (rotate % 90)
|
||||
|
||||
if(!map_element.can_rotate) //Abort rotation if disabled on map element
|
||||
rotate = 0
|
||||
|
||||
if(!z_offset)//what z_level we are creating the map on
|
||||
z_offset = world.maxz+1
|
||||
|
||||
@@ -105,6 +111,12 @@ var/list/map_dimension_cache = list()
|
||||
var/zcrd=-1
|
||||
var/ycrd=x_offset
|
||||
var/xcrd=y_offset
|
||||
var/ycrd_rotate=x_offset
|
||||
var/xcrd_rotate=y_offset
|
||||
var/ycrd_flip=x_offset
|
||||
var/xcrd_flip=y_offset
|
||||
var/ycrd_flip_rotate=y_offset
|
||||
var/xcrd_flip_rotate=x_offset
|
||||
|
||||
for(var/zpos=findtext(tfile,"\n(1,1,",lpos,0);zpos!=0;zpos=findtext(tfile,"\n(1,1,",zpos+1,0)) //in case there's several maps to load
|
||||
|
||||
@@ -118,35 +130,54 @@ var/list/map_dimension_cache = list()
|
||||
|
||||
//if exceeding the world max x or y, increase it
|
||||
var/x_depth = length(copytext(zgrid,1,findtext(zgrid,"\n",2,0))) //This is the length of an encoded line (like "aaaaaaaaBBBBaaaaccccaaa")
|
||||
var/y_depth = z_depth / (x_depth+1) //x_depth + 1 because we're counting the '\n' characters in z_depth
|
||||
var/map_width = x_depth / key_len //To get the map's width, divide the length of the line by the length of the key
|
||||
|
||||
if(world.maxx < map_width + x_offset)
|
||||
var/x_check = rotate == 0 || rotate == 180 ? map_width + x_offset : y_depth + y_offset
|
||||
var/y_check = rotate == 0 || rotate == 180 ? y_depth + y_offset : map_width + x_offset
|
||||
if(world.maxx < x_check)
|
||||
if(!map.can_enlarge)
|
||||
WARNING("Cancelled load of [map_element] due to map bounds.")
|
||||
return list()
|
||||
world.maxx = map_width + x_offset
|
||||
world.maxx = x_check
|
||||
WARNING("Loading [map_element] enlarged the map. New max x = [world.maxx]")
|
||||
|
||||
var/y_depth = z_depth / (x_depth+1) //x_depth + 1 because we're counting the '\n' characters in z_depth
|
||||
if(world.maxy < y_depth + y_offset)
|
||||
if(world.maxy < y_check)
|
||||
if(!map.can_enlarge)
|
||||
WARNING("Cancelled load of [map_element] due to map bounds.")
|
||||
return list()
|
||||
world.maxy = y_depth + y_offset
|
||||
world.maxy = y_check
|
||||
WARNING("Loading [map_element] enlarged the map. New max y = [world.maxy]")
|
||||
|
||||
//then proceed it line by line, starting from top
|
||||
ycrd = y_offset + y_depth
|
||||
ycrd_rotate = x_offset + map_width
|
||||
ycrd_flip = y_offset + 1
|
||||
ycrd_flip_rotate = x_offset + 1
|
||||
|
||||
for(var/gpos=1;gpos!=0;gpos=findtext(zgrid,"\n",gpos,0)+1)
|
||||
var/grid_line = copytext(zgrid,gpos,findtext(zgrid,"\n",gpos,0))
|
||||
|
||||
//fill the current square using the model map
|
||||
xcrd=x_offset
|
||||
xcrd_rotate=y_offset
|
||||
xcrd_flip=x_offset + map_width + 1
|
||||
xcrd_flip_rotate=y_offset + map_width + 1
|
||||
for(var/mpos=1;mpos<=x_depth;mpos+=key_len)
|
||||
xcrd++
|
||||
xcrd_rotate++
|
||||
xcrd_flip--
|
||||
xcrd_flip_rotate--
|
||||
var/model_key = copytext(grid_line,mpos,mpos+key_len)
|
||||
spawned_atoms |= parse_grid(grid_models[model_key],xcrd,ycrd,zcrd+z_offset)
|
||||
switch(rotate)
|
||||
if(0)
|
||||
spawned_atoms |= parse_grid(grid_models[model_key],xcrd,ycrd,zcrd+z_offset,rotate,overwrite)
|
||||
if(90)
|
||||
spawned_atoms |= parse_grid(grid_models[model_key],ycrd_rotate,xcrd_flip_rotate,zcrd+z_offset,rotate,overwrite)
|
||||
if(180)
|
||||
spawned_atoms |= parse_grid(grid_models[model_key],xcrd_flip,ycrd_flip,zcrd+z_offset,rotate,overwrite)
|
||||
if(270)
|
||||
spawned_atoms |= parse_grid(grid_models[model_key],ycrd_flip_rotate,xcrd_rotate,zcrd+z_offset,rotate,overwrite)
|
||||
if (remove_lag)
|
||||
CHECK_TICK
|
||||
if(map_element)
|
||||
@@ -157,6 +188,9 @@ var/list/map_dimension_cache = list()
|
||||
break
|
||||
|
||||
ycrd--
|
||||
ycrd_rotate--
|
||||
ycrd_flip++
|
||||
ycrd_flip_rotate++
|
||||
|
||||
if(remove_lag)
|
||||
CHECK_TICK
|
||||
@@ -198,7 +232,7 @@ var/list/map_dimension_cache = list()
|
||||
* A list with all spawned atoms
|
||||
*
|
||||
*/
|
||||
/dmm_suite/proc/parse_grid(var/model as text,var/xcrd as num,var/ycrd as num,var/zcrd as num)
|
||||
/dmm_suite/proc/parse_grid(var/model as text,var/xcrd as num,var/ycrd as num,var/zcrd as num,var/rotate as num,var/overwrite 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.
|
||||
@@ -286,7 +320,7 @@ var/list/map_dimension_cache = list()
|
||||
last_turf_index++
|
||||
|
||||
//instanciate the last /turf
|
||||
var/turf/T = instance_atom(members[last_turf_index],members_attributes[last_turf_index],xcrd,ycrd,zcrd)
|
||||
var/turf/T = instance_atom(members[last_turf_index],members_attributes[last_turf_index],xcrd,ycrd,zcrd,rotate)
|
||||
|
||||
if(first_turf_index != last_turf_index) //More than one turf is present - go from the lowest turf to the turf before the last one
|
||||
var/turf_index = first_turf_index
|
||||
@@ -301,8 +335,12 @@ var/list/map_dimension_cache = list()
|
||||
spawned_atoms.Add(T)
|
||||
|
||||
//finally instance all remainings objects/mobs
|
||||
if(overwrite)
|
||||
var/turf/T_old = locate(xcrd,ycrd,zcrd)
|
||||
for(var/atom/thing in T_old)
|
||||
qdel(T_old)
|
||||
for(index=1,index < first_turf_index,index++)
|
||||
var/atom/new_atom = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd)
|
||||
var/atom/new_atom = instance_atom(members[index],members_attributes[index],xcrd,ycrd,zcrd,rotate)
|
||||
spawned_atoms.Add(new_atom)
|
||||
|
||||
return spawned_atoms
|
||||
@@ -312,7 +350,7 @@ var/list/map_dimension_cache = list()
|
||||
////////////////
|
||||
|
||||
//Instance an atom at (x,y,z) and gives it the variables in attributes
|
||||
/dmm_suite/proc/instance_atom(var/path,var/list/attributes, var/x, var/y, var/z)
|
||||
/dmm_suite/proc/instance_atom(var/path,var/list/attributes, var/x, var/y, var/z, var/rotate)
|
||||
if(!path)
|
||||
return
|
||||
var/atom/instance
|
||||
@@ -325,6 +363,10 @@ var/list/map_dimension_cache = list()
|
||||
else
|
||||
instance = new path (locate(x,y,z))//first preloader pass
|
||||
|
||||
// Stolen from shuttlecode but very good to reuse here
|
||||
if(rotate && instance)
|
||||
instance.shuttle_rotate(rotate)
|
||||
|
||||
if(_preloader && instance)//second preloader pass, for those atoms that don't ..() in New()
|
||||
_preloader.load(instance)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ var/turf/dungeon_area = null
|
||||
|
||||
#define MAXIMUM_DUNGEON_WIDTH 80
|
||||
|
||||
proc/load_dungeon(dungeon_type)
|
||||
proc/load_dungeon(dungeon_type, var/rotate = 0)
|
||||
if(!dungeon_area)
|
||||
return 0
|
||||
|
||||
@@ -96,6 +96,6 @@ proc/load_dungeon(dungeon_type)
|
||||
existing_dungeons.Add(ME) //Add it now, to prevent issues occuring when two dungeons are loaded at once
|
||||
|
||||
//Reduce X and Y by 1 because these arguments are actually offsets, and they're added to 1;1 in the map loader. Without this, spawning something at 1;1 would result in it getting spawned at 2;2
|
||||
var/result = ME.load(spawn_x - 1, spawn_y - 1, dungeon_area.z)
|
||||
var/result = ME.load(spawn_x - 1, spawn_y - 1, dungeon_area.z, rotate)
|
||||
|
||||
return result
|
||||
|
||||
@@ -106,10 +106,8 @@ var/list/existing_vaults = list()
|
||||
/datum/map_element/vault/spacepond
|
||||
file_path = "maps/randomvaults/spacepond.dmm"
|
||||
|
||||
/datum/map_element/vault/spacepond/initialize(list/objects)
|
||||
..()
|
||||
|
||||
load_dungeon(/datum/map_element/dungeon/wine_cellar)
|
||||
/datum/map_element/vault/spacepond/pre_load()
|
||||
load_dungeon(/datum/map_element/dungeon/wine_cellar,rotation)
|
||||
|
||||
/datum/map_element/dungeon/wine_cellar
|
||||
file_path = "maps/randomvaults/dungeons/wine_cellar.dmm"
|
||||
@@ -139,7 +137,7 @@ var/list/existing_vaults = list()
|
||||
file_path = "maps/randomvaults/prison_ship.dmm"
|
||||
|
||||
/datum/map_element/vault/prison/pre_load()
|
||||
load_dungeon(/datum/map_element/dungeon/prison)
|
||||
load_dungeon(/datum/map_element/dungeon/prison,rotation)
|
||||
|
||||
/datum/map_element/dungeon/prison
|
||||
file_path = "maps/randomvaults/dungeons/prison.dmm"
|
||||
@@ -190,7 +188,7 @@ var/list/existing_vaults = list()
|
||||
file_path = "maps/randomvaults/spy_satellite.dmm"
|
||||
|
||||
/datum/map_element/vault/spy_sat/pre_load()
|
||||
load_dungeon(/datum/map_element/dungeon/satellite_deployment)
|
||||
load_dungeon(/datum/map_element/dungeon/satellite_deployment,rotation)
|
||||
|
||||
/datum/map_element/dungeon/satellite_deployment
|
||||
file_path = "maps/randomvaults/dungeons/satellite_deployment.dmm"
|
||||
|
||||
@@ -202,16 +202,18 @@
|
||||
var/vault_x = new_spawn_point.x
|
||||
var/vault_y = new_spawn_point.y
|
||||
var/vault_z = new_spawn_point.z
|
||||
var/vault_rotate = config.disable_vault_rotation ? 0 : pick(0,90,180,270)
|
||||
|
||||
if(population_density == POPULATION_SCARCE)
|
||||
var/turf/t1 = locate(max(1, vault_x - MAX_VAULT_WIDTH - 1), max(1, vault_y - MAX_VAULT_HEIGHT - 1), vault_z)
|
||||
var/turf/t2 = locate(vault_x + new_width, vault_y + new_height, vault_z)
|
||||
valid_spawn_points.Remove(block(t1, t2))
|
||||
|
||||
if(ME.load(vault_x, vault_y, vault_z))
|
||||
if(ME.load(vault_x, vault_y, vault_z, vault_rotate))
|
||||
spawned.Add(ME)
|
||||
message_admins("<span class='info'>Loaded [ME.file_path]: [formatJumpTo(locate(vault_x, vault_y, vault_z))].")
|
||||
|
||||
message_admins("<span class='info'>Loaded [ME.file_path]: [formatJumpTo(locate(vault_x, vault_y, vault_z))] [config.disable_vault_rotation ? "" : ", rotated by [vault_rotate] degrees"].")
|
||||
if(config.disable_vault_rotation)
|
||||
message_admins("<span class='info'>[ME.file_path] was not rotated, DISABLE_VAULT_ROTATION enabled in config.</span>")
|
||||
successes++
|
||||
if(amount > 0)
|
||||
amount--
|
||||
|
||||
@@ -313,6 +313,10 @@ SKIP_HOLOMINIMAP_GENERATION
|
||||
## Uncomment to disable generation of vaults (makes the server start faster!)
|
||||
SKIP_VAULT_GENERATION
|
||||
|
||||
## DISABLE_VAULT_ROTATION
|
||||
## Uncomment to disable rotation of vaults
|
||||
#DISABLE_VAULT_ROTATION
|
||||
|
||||
## SHUT_UP_AUTOMATIC_DIAGNOSTIC_AND_ANNOUNCEMENT_SYSTEM
|
||||
## Uncomment to disable the lovely robotic voice that tells you the time at the start of every shift.
|
||||
## Recommended for your sanity if you start the server a lot for testing things.
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
SL.file_path = pick_n_take(src.available_levels) //No duplicate levels
|
||||
SL.parent = src
|
||||
|
||||
load_dungeon(SL)
|
||||
load_dungeon(SL,rotation)
|
||||
loaded_levels.Add(SL)
|
||||
|
||||
//Load ending
|
||||
|
||||
Reference in New Issue
Block a user