Files
Bubberstation/code/modules/mapping/ruins.dm
Bloop b674e72ef1 [MISSED MIRROR] Macros multi-z code, removes the false premise of manual offsets (#76248) (#22531)
* Macros multi-z code, removes the false premise of manual offsets (#76248)

## About The Pull Request

[Removes the pretense of relative multiz
levels](0293fdc2bd)

Our multiz system does not support having a z level that is only
connected one way, or which goes down backwards or anything like that.

That's a fiction of the trait system, the actual backend has never
really supported this.

This pr removes the assumptions we were making backend around this, and
uses that to save cpu time.

I am also converting multiz_levels from an assoc list to a pure one,
which saves significantly on access times and cleans up the code
somewhat.

Also I'm making the get_below/get_above procs into macros, for the sake
of cpu time.

[Converts the starlight disease to use BYOND's directional defines
instead of our
own](7d698f02d9)

To some extent spurred on by
https://github.com/DaedalusDock/daedalusdock/pull/298, tho it was known
before

## Why It's Good For The Game

Faster multiz code, faster init, etc etc etc

* modular files how very dare you

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
2023-07-18 02:28:15 +00:00

196 lines
7.2 KiB
Plaintext

/datum/map_template/ruin/proc/try_to_place(z, list/allowed_areas_typecache, turf/forced_turf, clear_below)
var/sanity = forced_turf ? 1 : PLACEMENT_TRIES
if(SSmapping.level_trait(z,ZTRAIT_ISOLATED_RUINS))
return place_on_isolated_level(z)
while(sanity > 0)
sanity--
var/width_border = TRANSITIONEDGE + SPACERUIN_MAP_EDGE_PAD + round(width / 2)
var/height_border = TRANSITIONEDGE + SPACERUIN_MAP_EDGE_PAD + round(height / 2)
var/turf/central_turf = forced_turf ? forced_turf : locate(rand(width_border, world.maxx - width_border), rand(height_border, world.maxy - height_border), z)
var/valid = TRUE
var/list/affected_turfs = get_affected_turfs(central_turf,1)
var/list/affected_areas = list()
for(var/turf/check in affected_turfs)
// Use assoc lists to move this out, it's easier that way
if(check.turf_flags & NO_RUINS)
valid = FALSE // set to false before we check
break
var/area/new_area = get_area(check)
affected_areas[new_area] = TRUE
// This is faster yes. Only BARELY but it is faster
for(var/area/affct_area as anything in affected_areas)
if(!allowed_areas_typecache[affct_area.type])
valid = FALSE
break
if(!valid)
continue
testing("Ruin \"[name]\" placed at ([central_turf.x], [central_turf.y], [central_turf.z])")
if(clear_below)
var/list/static/clear_below_typecache = typecacheof(list(
/obj/structure/spawner,
/mob/living/simple_animal,
/obj/structure/flora
))
for(var/turf/T as anything in affected_turfs)
for(var/atom/thing as anything in T)
if(clear_below_typecache[thing.type])
qdel(thing)
load(central_turf,centered = TRUE)
loaded++
for(var/turf/T in affected_turfs)
T.turf_flags |= NO_RUINS
new /obj/effect/landmark/ruin(central_turf, src)
return central_turf
/datum/map_template/ruin/proc/place_on_isolated_level(z)
var/datum/turf_reservation/reservation = SSmapping.RequestBlockReservation(width, height, z) //Make the new level creation work with different traits.
if(!reservation)
return
var/turf/placement = locate(reservation.bottom_left_coords[1],reservation.bottom_left_coords[2],reservation.bottom_left_coords[3])
load(placement)
loaded++
for(var/turf/T in get_affected_turfs(placement))
T.turf_flags |= NO_RUINS
var/turf/center = locate(placement.x + round(width/2),placement.y + round(height/2),placement.z)
new /obj/effect/landmark/ruin(center, src)
return center
/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = list(/area/space), list/potentialRuins, clear_below = FALSE)
if(!z_levels || !z_levels.len)
WARNING("No Z levels provided - Not generating ruins")
return
var/list/whitelist_typecache = typecacheof(whitelist)
for(var/zl in z_levels)
var/turf/T = locate(1, 1, zl)
if(!T)
WARNING("Z level [zl] does not exist - Not generating ruins")
return
var/list/ruins = potentialRuins.Copy()
var/list/forced_ruins = list() //These go first on the z level associated (same random one by default) or if the assoc value is a turf to the specified turf.
var/list/ruins_available = list() //we can try these in the current pass
if(PERFORM_ALL_TESTS(log_mapping))
log_mapping("All ruins being loaded for map testing.")
//Set up the starting ruin list
for(var/key in ruins)
var/datum/map_template/ruin/R = ruins[key]
if(PERFORM_ALL_TESTS(log_mapping))
R.cost = 0
R.allow_duplicates = FALSE // no multiples for testing
R.always_place = !R.unpickable // unpickable ruin means it spawns as a set with another ruin
if(R.cost > budget) //Why would you do that
continue
if(R.always_place)
forced_ruins[R] = -1
if(R.unpickable)
continue
ruins_available[R] = R.placement_weight
while(budget > 0 && (ruins_available.len || forced_ruins.len))
var/datum/map_template/ruin/current_pick
var/forced = FALSE
var/forced_z //If set we won't pick z level and use this one instead.
var/forced_turf //If set we place the ruin centered on the given turf
if(forced_ruins.len) //We have something we need to load right now, so just pick it
for(var/ruin in forced_ruins)
current_pick = ruin
if(isturf(forced_ruins[ruin]))
var/turf/T = forced_ruins[ruin]
forced_z = T.z //In case of chained ruins
forced_turf = T
else if(forced_ruins[ruin] > 0) //Load into designated z
forced_z = forced_ruins[ruin]
forced = TRUE
break
else //Otherwise just pick random one
current_pick = pick_weight(ruins_available)
var/placement_tries = forced_turf ? 1 : PLACEMENT_TRIES //Only try once if we target specific turf
var/failed_to_place = TRUE
var/target_z = 0
var/turf/placed_turf //Where the ruin ended up if we succeeded
outer:
while(placement_tries > 0)
placement_tries--
target_z = pick(z_levels)
if(forced_z)
target_z = forced_z
if(current_pick.always_spawn_with) //If the ruin has part below, make sure that z exists.
for(var/v in current_pick.always_spawn_with)
if(current_pick.always_spawn_with[v] == PLACE_BELOW)
var/turf/T = locate(1,1,target_z)
if(!GET_TURF_BELOW(T))
if(forced_z)
continue outer
else
break outer
placed_turf = current_pick.try_to_place(target_z,whitelist_typecache,forced_turf,clear_below)
if(!placed_turf)
continue
else
failed_to_place = FALSE
break
//That's done remove from priority even if it failed
if(forced)
//TODO : handle forced ruins with multiple variants
forced_ruins -= current_pick
forced = FALSE
if(failed_to_place)
for(var/datum/map_template/ruin/R in ruins_available)
if(R.id == current_pick.id)
ruins_available -= R
log_world("Failed to place [current_pick.name] ruin.")
else
budget -= current_pick.cost
if(!current_pick.allow_duplicates)
for(var/datum/map_template/ruin/R in ruins_available)
if(R.id == current_pick.id)
ruins_available -= R
if(current_pick.never_spawn_with)
for(var/blacklisted_type in current_pick.never_spawn_with)
for(var/possible_exclusion in ruins_available)
if(istype(possible_exclusion,blacklisted_type))
ruins_available -= possible_exclusion
if(current_pick.always_spawn_with)
for(var/v in current_pick.always_spawn_with)
for(var/ruin_name in SSmapping.ruins_templates) //Because we might want to add space templates as linked of lava templates.
var/datum/map_template/ruin/linked = SSmapping.ruins_templates[ruin_name] //why are these assoc, very annoying.
if(istype(linked,v))
switch(current_pick.always_spawn_with[v])
if(PLACE_SAME_Z)
forced_ruins[linked] = target_z //I guess you might want a chain somehow
if(PLACE_LAVA_RUIN)
forced_ruins[linked] = pick(SSmapping.levels_by_trait(ZTRAIT_LAVA_RUINS))
if(PLACE_SPACE_RUIN)
forced_ruins[linked] = pick(SSmapping.levels_by_trait(ZTRAIT_SPACE_RUINS))
if(PLACE_DEFAULT)
forced_ruins[linked] = -1
if(PLACE_BELOW)
forced_ruins[linked] = GET_TURF_BELOW(placed_turf)
if(PLACE_ISOLATED)
forced_ruins[linked] = SSmapping.get_isolated_ruin_z()
//Update the available list
for(var/datum/map_template/ruin/R in ruins_available)
if(R.cost > budget)
ruins_available -= R
log_world("Ruin loader finished with [budget] left to spend.")