mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
Adds proc for filling an area with map elements, raised vault amount to 5-15 (#12910)
* Smart vault placement * Raised vault amount to 5-15, moved vault spwaning to new system * Fix define * Fix if statement
This commit is contained in:
@@ -152,3 +152,31 @@
|
||||
T.ChangeTurf(wall_type)
|
||||
|
||||
sleep(1)
|
||||
|
||||
|
||||
//
|
||||
/datum/map_element/customizable/vault_placement
|
||||
file_path = null
|
||||
|
||||
width = 0
|
||||
height = 0
|
||||
|
||||
/datum/map_element/customizable/vault_placement/pre_load()
|
||||
if(usr && (!width || !height))
|
||||
width = input(usr, "Enter the area's width (4-400). The starting point is the lower left corner. Enter an invalid value to cancel.", "Vault Generator", 100) as num
|
||||
if(width < 4 || width > 400)
|
||||
width = 0
|
||||
return
|
||||
|
||||
height = input(usr, "Enter the area's height (4-400). The starting point is the lower left corner. Enter an invalid value to cancel.", "Vault Generator", 100) as num
|
||||
if(height < 4 || height > 400)
|
||||
height = 0
|
||||
return
|
||||
|
||||
/datum/map_element/customizable/vault_placement/initialize()
|
||||
if(!location)
|
||||
return
|
||||
if(!width || !height)
|
||||
return
|
||||
|
||||
populate_area_with_vaults(block(location, locate(location.x + width, location.y + height, location.z)))
|
||||
|
||||
@@ -6,9 +6,25 @@
|
||||
//2. add the map's name to the vault_map_names list
|
||||
//3. the game will handle the rest
|
||||
|
||||
#define MINIMUM_VAULT_AMOUNT 1 //Amount of guaranteed vault spawns
|
||||
#define MINIMUM_VAULT_AMOUNT 5 //Amount of guaranteed vault spawns
|
||||
#define MAXIMUM_VAULT_AMOUNT 15
|
||||
|
||||
//#define SPAWN_ALL_VAULTS //Uncomment to spawn all existing vaults (otherwise only some will spawn)!
|
||||
#define MAX_VAULT_WIDTH 80 //Vaults bigger than that have a slight chance of overlapping with other vaults
|
||||
#define MAX_VAULT_HEIGHT 80
|
||||
|
||||
//For the populate_area_with_vaults() proc
|
||||
#define POPULATION_DENSE 1 //Performs large calculations to make vaults able to spawn right next to each other and not overlap. Recommended with smaller areas - may lag bigly in big areas
|
||||
#define POPULATION_SCARCE 2 //Performs less calculations by cheating a bit and assuming that every vault's size is 100x100. Vaults are farther away from each other - recommended with big areas
|
||||
|
||||
|
||||
//#define SPAWN_ALL_VAULTS //Uncomment to spawn every hecking vault in the game
|
||||
//#define SPAWN_MAX_VAULTS //Uncomment to spawn as many vaults as the code supports
|
||||
|
||||
#ifdef SPAWN_MAX_VAULTS
|
||||
#warning Spawning maximum amount of vaults!
|
||||
#undef MINIMUM_VAULT_AMOUNT
|
||||
#define MINIMUM_VAULT_AMOUNT MAXIMUM_VAULT_AMOUNT
|
||||
#endif
|
||||
|
||||
//List of spawnable vaults is in code/modules/randomMaps/vault_definitions.dm
|
||||
|
||||
@@ -17,107 +33,149 @@
|
||||
desc = "Spawn a vault in there somewhere"
|
||||
icon_state = "random_vault"
|
||||
|
||||
//Because areas are shit and it's easier that way!
|
||||
//This a random vault spawns somewhere in this area. Then this area is replaced with space!
|
||||
/area/random_vault
|
||||
|
||||
//Each of these areas can only create ONE vault. Only using /area/random_vault/v1 for the entire map will result in ONE vault being created.
|
||||
//Placing them over (or even near) shuttle docking ports will sometimes result in a vault spawning on top of a shuttle docking port. This isn't a big problem, since
|
||||
//shuttles can destroy the vaults, but it's better to avoid that
|
||||
//If you want more vaults, feel free to add more subtypes of /area/random_vault. You don't have to add these subtypes to any lists or anything - just map it and the game will handle the rest.
|
||||
/proc/get_map_element_objects(base_type = /datum/map_element/vault)
|
||||
var/list/list_of_vaults = typesof(base_type) - base_type
|
||||
|
||||
//"/area/random_vault" DOESN'T spawn any vaults!!!
|
||||
/area/random_vault/v1
|
||||
/area/random_vault/v2
|
||||
/area/random_vault/v3
|
||||
/area/random_vault/v4
|
||||
/area/random_vault/v5
|
||||
/area/random_vault/v6
|
||||
/area/random_vault/v7
|
||||
/area/random_vault/v8
|
||||
/area/random_vault/v9
|
||||
/area/random_vault/v10
|
||||
for(var/V in list_of_vaults) //Turn list of paths into list of objects
|
||||
list_of_vaults.Add(new V)
|
||||
list_of_vaults.Remove(V)
|
||||
|
||||
/proc/generate_vaults()
|
||||
var/area/space = get_space_area()
|
||||
//Compare all objects with the map and remove non-compactible ones
|
||||
for(var/datum/map_element/vault/V in list_of_vaults)
|
||||
//See code/modules/randomMaps/dungeons.dm
|
||||
if(V.require_dungeons && !dungeon_area)
|
||||
list_of_vaults.Remove(V)
|
||||
continue
|
||||
|
||||
var/list/list_of_vault_spawners = shuffle(typesof(/area/random_vault) - /area/random_vault)
|
||||
var/list/list_of_vaults = typesof(/datum/map_element/vault) - /datum/map_element/vault
|
||||
|
||||
for(var/vault_path in list_of_vaults) //Turn a list of paths into a list of objects
|
||||
list_of_vaults.Add(new vault_path)
|
||||
list_of_vaults.Remove(vault_path)
|
||||
|
||||
//Start processing the list of vaults
|
||||
|
||||
if(map.only_spawn_map_exclusive_vaults) //If the map spawns only map-exclusive vaults - remove all vaults that aren't exclusive to this map
|
||||
for(var/datum/map_element/vault/V in list_of_vaults)
|
||||
|
||||
if(V.exclusive_to_maps.Find(map.nameShort) || V.exclusive_to_maps.Find(map.nameLong))
|
||||
if(map.only_spawn_map_exclusive_vaults || V.exclusive_to_maps.len) //Remove this vault if it isn't exclusive to this map
|
||||
if(!V.exclusive_to_maps.Find(map.nameShort) && !V.exclusive_to_maps.Find(map.nameLong))
|
||||
list_of_vaults.Remove(V)
|
||||
continue
|
||||
|
||||
list_of_vaults.Remove(V)
|
||||
else //Map spawns all vaults - remove all vaults that are exclusive to other maps
|
||||
for(var/datum/map_element/vault/V in list_of_vaults)
|
||||
|
||||
if(V.exclusive_to_maps.len)
|
||||
if(!V.exclusive_to_maps.Find(map.nameShort) && !V.exclusive_to_maps.Find(map.nameLong))
|
||||
list_of_vaults.Remove(V)
|
||||
|
||||
for(var/datum/map_element/vault/V in list_of_vaults) //Remove all vaults that can't spawn on this map
|
||||
if(V.map_blacklist.len)
|
||||
if(V.map_blacklist.Find(map.nameShort) || V.map_blacklist.Find(map.nameLong))
|
||||
list_of_vaults.Remove(V)
|
||||
continue
|
||||
|
||||
//See code/modules/randomMaps/dungeons.dm
|
||||
if(V.require_dungeons)
|
||||
if(!dungeon_area)
|
||||
list_of_vaults.Remove(V)
|
||||
continue
|
||||
return list_of_vaults
|
||||
|
||||
var/failures = 0
|
||||
var/successes = 0
|
||||
var/vault_number = rand(MINIMUM_VAULT_AMOUNT, min(list_of_vaults.len, list_of_vault_spawners.len))
|
||||
/proc/generate_vaults()
|
||||
var/area/space = get_space_area()
|
||||
|
||||
var/list/list_of_vaults = get_map_element_objects()
|
||||
|
||||
var/vault_number = rand(MINIMUM_VAULT_AMOUNT, min(list_of_vaults.len, MAXIMUM_VAULT_AMOUNT))
|
||||
|
||||
#ifdef SPAWN_ALL_VAULTS
|
||||
#warning Spawning all vaults!
|
||||
vault_number = min(list_of_vaults.len, list_of_vault_spawners.len)
|
||||
#warning Spawning ALL vaults!
|
||||
vault_number = list_of_vaults.len
|
||||
#endif
|
||||
|
||||
message_admins("<span class='info'>Spawning [vault_number] vaults (in [list_of_vault_spawners.len] areas)...</span>")
|
||||
message_admins("<span class='info'>Spawning [vault_number] vaults in space!</span>")
|
||||
|
||||
for(var/T in list_of_vault_spawners) //Go through all subtypes of /area/random_vault
|
||||
var/area/A = locate(T) //Find the area
|
||||
var/area/A = locate(/area/random_vault)
|
||||
var/result = populate_area_with_vaults(A, amount = vault_number, population_density = POPULATION_SCARCE)
|
||||
|
||||
if(!A || !A.contents.len) //Area is empty and doesn't exist - skip
|
||||
for(var/turf/TURF in A) //Replace all of the temporary areas with space
|
||||
TURF.set_area(space)
|
||||
|
||||
message_admins("<span class='info'>Loaded [result] out of [vault_number] vaults.</span>")
|
||||
|
||||
|
||||
//Proc that populates a single area with many vaults, randomly
|
||||
//A is the area OR a list of turfs where the placement happens
|
||||
//map_element_objects is a list of vaults that have to be placed. Defaults to subtypes of /datum/map_element/vault (meaning all vaults are spawned)
|
||||
//amount is the maximum amount of vaults placed. If -1, it will place as many vaults as it can
|
||||
|
||||
//NOTE: Vaults may be placed partially outside of the area. Only the lower left corner is guaranteed to be in the area
|
||||
|
||||
/proc/populate_area_with_vaults(area/A, list/map_element_objects, var/amount = -1, population_density = POPULATION_DENSE)
|
||||
var/list/area_turfs
|
||||
|
||||
if(ispath(A, /area))
|
||||
A = locate(A)
|
||||
if(isarea(A))
|
||||
area_turfs = A.get_turfs()
|
||||
else if(istype(A, /list))
|
||||
area_turfs = A
|
||||
ASSERT(area_turfs)
|
||||
|
||||
if(!map_element_objects)
|
||||
map_element_objects = get_map_element_objects()
|
||||
|
||||
message_admins("<span class='info'>Starting populating [isarea(A) ? "an area ([A])" : "a list of [area_turfs.len] turfs"] with vaults.")
|
||||
|
||||
var/list/spawned = list()
|
||||
var/successes = 0
|
||||
|
||||
while(map_element_objects.len)
|
||||
var/datum/map_element/ME = pick(map_element_objects)
|
||||
map_element_objects.Remove(ME)
|
||||
|
||||
if(!istype(ME))
|
||||
continue
|
||||
|
||||
if(list_of_vaults.len > 0 && vault_number>0)
|
||||
vault_number--
|
||||
var/list/dimensions = ME.get_dimensions() //List with the element's width and height
|
||||
var/new_width = dimensions[1]
|
||||
var/new_height = dimensions[2]
|
||||
|
||||
var/vault_x
|
||||
var/vault_y
|
||||
var/vault_z
|
||||
var/list/valid_spawn_points
|
||||
switch(population_density)
|
||||
if(POPULATION_DENSE)
|
||||
//Copy the list of all turfs
|
||||
valid_spawn_points = area_turfs.Copy()
|
||||
|
||||
var/turf/TURF = get_turf(pick(A.contents))
|
||||
//While going through every already spawned map element - remove all potential locations which would cause the new element to overlap the already spawned one
|
||||
for(var/datum/map_element/conflict in spawned)
|
||||
if(!valid_spawn_points.len)
|
||||
break
|
||||
if(!isturf(conflict.location))
|
||||
continue
|
||||
|
||||
vault_x = TURF.x
|
||||
vault_y = TURF.y
|
||||
vault_z = TURF.z
|
||||
var/turf/T = conflict.location
|
||||
var/x1 = max(1, T.x - new_width - 1)
|
||||
var/y1 = max(1, T.y - new_height- 1)
|
||||
var/turf/t1 = locate(x1, y1, T.z)
|
||||
var/turf/t2 = locate(T.x + conflict.width, T.y + conflict.height, T.z)
|
||||
|
||||
var/datum/map_element/vault/new_vault = pick(list_of_vaults) //Pick a random path from list_of_vaults (like /datum/vault/spacegym)
|
||||
valid_spawn_points.Remove(block(t1, t2))
|
||||
|
||||
if(new_vault.only_spawn_once)
|
||||
list_of_vaults.Remove(new_vault)
|
||||
if(POPULATION_SCARCE)
|
||||
valid_spawn_points = area_turfs
|
||||
|
||||
if(new_vault.load(vault_x, vault_y, vault_z))
|
||||
message_admins("<span class='info'>Loaded [new_vault.file_path]: [formatJumpTo(locate(vault_x, vault_y, vault_z))].")
|
||||
successes++
|
||||
else
|
||||
message_admins("<span class='danger'>Can't find [new_vault.file_path]!</span>")
|
||||
failures++
|
||||
if(!valid_spawn_points.len)
|
||||
if(population_density == POPULATION_SCARCE)
|
||||
message_admins("<span class='info'>Ran out of free space for vaults.</span>")
|
||||
break
|
||||
continue
|
||||
|
||||
for(var/turf/TURF in A) //Replace all of the temporary areas with space
|
||||
space.contents.Add(TURF)
|
||||
TURF.change_area(A, space)
|
||||
var/turf/new_spawn_point = pick(valid_spawn_points)
|
||||
var/vault_x = new_spawn_point.x
|
||||
var/vault_y = new_spawn_point.y
|
||||
var/vault_z = new_spawn_point.z
|
||||
|
||||
message_admins("<span class='info'>Loaded [successes] vaults successfully, [failures] failures.</span>")
|
||||
if(population_density == POPULATION_SCARCE)
|
||||
valid_spawn_points.Remove(block(new_spawn_point, locate(vault_x - MAX_VAULT_WIDTH, vault_y - MAX_VAULT_HEIGHT, vault_z)))
|
||||
|
||||
if(ME.load(vault_x, vault_y, vault_z))
|
||||
spawned.Add(ME)
|
||||
message_admins("<span class='info'>Loaded [ME.file_path]: [formatJumpTo(locate(vault_x, vault_y, vault_z))].")
|
||||
|
||||
successes++
|
||||
if(amount > 0)
|
||||
amount--
|
||||
|
||||
if(amount == 0)
|
||||
break
|
||||
else
|
||||
message_admins("<span class='danger'>Can't find [ME.file_path]!</span>")
|
||||
|
||||
sleep(-1)
|
||||
|
||||
return successes
|
||||
|
||||
#undef POPULATION_DENSE
|
||||
#undef POPULATION_SCARCE
|
||||
|
||||
Reference in New Issue
Block a user