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:
kane-f
2021-10-02 04:36:54 +01:00
committed by GitHub
parent 416f9ee0fb
commit b50bef7b88
10 changed files with 87 additions and 30 deletions

View File

@@ -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")

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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"

View File

@@ -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--

View File

@@ -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.

View File

@@ -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