diff --git a/code/modules/mapping/ruins.dm b/code/modules/mapping/ruins.dm index d88c7543f0..9c578badb1 100644 --- a/code/modules/mapping/ruins.dm +++ b/code/modules/mapping/ruins.dm @@ -1,171 +1,171 @@ -/datum/map_template/ruin/proc/try_to_place(z,allowed_areas,turf/forced_turf) - 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 - - for(var/turf/check in get_affected_turfs(central_turf,1)) - var/area/new_area = get_area(check) - if(!(istype(new_area, allowed_areas)) || check.flags_1 & NO_RUINS_1) - valid = FALSE - break - - if(!valid) - continue - - testing("Ruin \"[name]\" placed at ([central_turf.x], [central_turf.y], [central_turf.z])") - - for(var/i in get_affected_turfs(central_turf, 1)) - var/turf/T = i - for(var/mob/living/simple_animal/monster in T) - qdel(monster) - for(var/obj/structure/flora/ash/plant in T) - qdel(plant) - - load(central_turf,centered = TRUE) - loaded++ - - for(var/turf/T in get_affected_turfs(central_turf, 1)) - T.flags_1 |= NO_RUINS_1 - - 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.flags_1 |= NO_RUINS_1 - 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 = /area/space, list/potentialRuins) - if(!z_levels || !z_levels.len) - WARNING("No Z levels provided - Not generating ruins") - return - - 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_availible = list() //we can try these in the current pass - - //Set up the starting ruin list - for(var/key in ruins) - var/datum/map_template/ruin/R = ruins[key] - if(R.cost > budget) //Why would you do that - continue - if(R.always_place) - forced_ruins[R] = -1 - if(R.unpickable) - continue - ruins_availible[R] = R.placement_weight - - while(budget > 0 && (ruins_availible.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 = pickweight(ruins_availible) - - 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(!SSmapping.get_turf_below(T)) - if(forced_z) - continue outer - else - break outer - - placed_turf = current_pick.try_to_place(target_z,whitelist,forced_turf) - 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_availible) - if(R.id == current_pick.id) - ruins_availible -= 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_availible) - if(R.id == current_pick.id) - ruins_availible -= R - if(current_pick.never_spawn_with) - for(var/blacklisted_type in current_pick.never_spawn_with) - for(var/possible_exclusion in ruins_availible) - if(istype(possible_exclusion,blacklisted_type)) - ruins_availible -= 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] = SSmapping.get_turf_below(placed_turf) - if(PLACE_ISOLATED) - forced_ruins[linked] = SSmapping.get_isolated_ruin_z() - - //Update the availible list - for(var/datum/map_template/ruin/R in ruins_availible) - if(R.cost > budget) - ruins_availible -= R - - log_world("Ruin loader finished with [budget] left to spend.") +/datum/map_template/ruin/proc/try_to_place(z,allowed_areas,turf/forced_turf) + 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 + + for(var/turf/check in get_affected_turfs(central_turf,1)) + var/area/new_area = get_area(check) + if(!(istype(new_area, allowed_areas)) || check.flags_1 & NO_RUINS_1) + valid = FALSE + break + + if(!valid) + continue + + testing("Ruin \"[name]\" placed at ([central_turf.x], [central_turf.y], [central_turf.z])") + + for(var/i in get_affected_turfs(central_turf, 1)) + var/turf/T = i + for(var/mob/living/simple_animal/monster in T) + qdel(monster) + for(var/obj/structure/flora/ash/plant in T) + qdel(plant) + + load(central_turf,centered = TRUE) + loaded++ + + for(var/turf/T in get_affected_turfs(central_turf, 1)) + T.flags_1 |= NO_RUINS_1 + + 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.flags_1 |= NO_RUINS_1 + 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 = /area/space, list/potentialRuins) + if(!z_levels || !z_levels.len) + WARNING("No Z levels provided - Not generating ruins") + return + + 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_availible = list() //we can try these in the current pass + + //Set up the starting ruin list + for(var/key in ruins) + var/datum/map_template/ruin/R = ruins[key] + if(R.cost > budget) //Why would you do that + continue + if(R.always_place) + forced_ruins[R] = -1 + if(R.unpickable) + continue + ruins_availible[R] = R.placement_weight + + while(budget > 0 && (ruins_availible.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 = pickweight(ruins_availible) + + 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(!SSmapping.get_turf_below(T)) + if(forced_z) + continue outer + else + break outer + + placed_turf = current_pick.try_to_place(target_z,whitelist,forced_turf) + 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_availible) + if(R.id == current_pick.id) + ruins_availible -= 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_availible) + if(R.id == current_pick.id) + ruins_availible -= R + if(current_pick.never_spawn_with) + for(var/blacklisted_type in current_pick.never_spawn_with) + for(var/possible_exclusion in ruins_availible) + if(istype(possible_exclusion,blacklisted_type)) + ruins_availible -= 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] = SSmapping.get_turf_below(placed_turf) + if(PLACE_ISOLATED) + forced_ruins[linked] = SSmapping.get_isolated_ruin_z() + + //Update the availible list + for(var/datum/map_template/ruin/R in ruins_availible) + if(R.cost > budget) + ruins_availible -= R + + log_world("Ruin loader finished with [budget] left to spend.") diff --git a/code/modules/mapping/space_management/space_reservation.dm b/code/modules/mapping/space_management/space_reservation.dm index 43fe69d633..b514796bc5 100644 --- a/code/modules/mapping/space_management/space_reservation.dm +++ b/code/modules/mapping/space_management/space_reservation.dm @@ -1,85 +1,85 @@ - -//Yes, they can only be rectangular. -//Yes, I'm sorry. -/datum/turf_reservation - var/list/reserved_turfs = list() - var/width = 0 - var/height = 0 - var/bottom_left_coords[3] - var/top_right_coords[3] - var/wipe_reservation_on_release = TRUE - var/turf_type = /turf/open/space - var/borderturf - -/datum/turf_reservation/transit - turf_type = /turf/open/space/transit - borderturf = /turf/open/space/transit/border - -/datum/turf_reservation/proc/Release() - var/v = reserved_turfs.Copy() - for(var/i in reserved_turfs) - reserved_turfs -= i - SSmapping.used_turfs -= i - SSmapping.reserve_turfs(v) - -/datum/turf_reservation/transit/Release() - for(var/turf/open/space/transit/T in reserved_turfs) - for(var/atom/movable/AM in T) - T.throw_atom(AM) - . = ..() - -/datum/turf_reservation/proc/Reserve(width, height, zlevel) - if(width > world.maxx || height > world.maxy || width < 1 || height < 1) - return FALSE - var/list/avail = SSmapping.unused_turfs["[zlevel]"] - var/turf/BL - var/turf/TR - var/list/turf/final = list() - var/passing = FALSE - for(var/i in avail) - CHECK_TICK - BL = i - if(!(BL.flags_1 & UNUSED_RESERVATION_TURF_1)) - continue - if(BL.x + width > world.maxx || BL.y + height > world.maxy) - continue - TR = locate(BL.x + width - 1, BL.y + height - 1, BL.z) - if(!(TR.flags_1 & UNUSED_RESERVATION_TURF_1)) - continue - final = block(BL, TR) - if(!final) - continue - passing = TRUE - for(var/I in final) - var/turf/checking = I - if(!(checking.flags_1 & UNUSED_RESERVATION_TURF_1)) - passing = FALSE - break - if(!passing) - continue - break - if(!passing || !istype(BL) || !istype(TR)) - return FALSE - bottom_left_coords = list(BL.x, BL.y, BL.z) - top_right_coords = list(TR.x, TR.y, TR.z) - for(var/i in final) - var/turf/T = i - reserved_turfs |= T - T.flags_1 &= ~UNUSED_RESERVATION_TURF_1 - SSmapping.unused_turfs["[T.z]"] -= T - SSmapping.used_turfs[T] = src - if(borderturf && (T.x == BL.x || T.x == TR.x || T.y == BL.y || T.y == TR.y)) - T.ChangeTurf(borderturf, borderturf) - else - T.ChangeTurf(turf_type, turf_type) - src.width = width - src.height = height - return TRUE - -/datum/turf_reservation/New() - LAZYADD(SSmapping.turf_reservations, src) - -/datum/turf_reservation/Destroy() - Release() - LAZYREMOVE(SSmapping.turf_reservations, src) - return ..() + +//Yes, they can only be rectangular. +//Yes, I'm sorry. +/datum/turf_reservation + var/list/reserved_turfs = list() + var/width = 0 + var/height = 0 + var/bottom_left_coords[3] + var/top_right_coords[3] + var/wipe_reservation_on_release = TRUE + var/turf_type = /turf/open/space + var/borderturf + +/datum/turf_reservation/transit + turf_type = /turf/open/space/transit + borderturf = /turf/open/space/transit/border + +/datum/turf_reservation/proc/Release() + var/v = reserved_turfs.Copy() + for(var/i in reserved_turfs) + reserved_turfs -= i + SSmapping.used_turfs -= i + SSmapping.reserve_turfs(v) + +/datum/turf_reservation/transit/Release() + for(var/turf/open/space/transit/T in reserved_turfs) + for(var/atom/movable/AM in T) + T.throw_atom(AM) + . = ..() + +/datum/turf_reservation/proc/Reserve(width, height, zlevel) + if(width > world.maxx || height > world.maxy || width < 1 || height < 1) + return FALSE + var/list/avail = SSmapping.unused_turfs["[zlevel]"] + var/turf/BL + var/turf/TR + var/list/turf/final = list() + var/passing = FALSE + for(var/i in avail) + CHECK_TICK + BL = i + if(!(BL.flags_1 & UNUSED_RESERVATION_TURF_1)) + continue + if(BL.x + width > world.maxx || BL.y + height > world.maxy) + continue + TR = locate(BL.x + width - 1, BL.y + height - 1, BL.z) + if(!(TR.flags_1 & UNUSED_RESERVATION_TURF_1)) + continue + final = block(BL, TR) + if(!final) + continue + passing = TRUE + for(var/I in final) + var/turf/checking = I + if(!(checking.flags_1 & UNUSED_RESERVATION_TURF_1)) + passing = FALSE + break + if(!passing) + continue + break + if(!passing || !istype(BL) || !istype(TR)) + return FALSE + bottom_left_coords = list(BL.x, BL.y, BL.z) + top_right_coords = list(TR.x, TR.y, TR.z) + for(var/i in final) + var/turf/T = i + reserved_turfs |= T + T.flags_1 &= ~UNUSED_RESERVATION_TURF_1 + SSmapping.unused_turfs["[T.z]"] -= T + SSmapping.used_turfs[T] = src + if(borderturf && (T.x == BL.x || T.x == TR.x || T.y == BL.y || T.y == TR.y)) + T.ChangeTurf(borderturf, borderturf) + else + T.ChangeTurf(turf_type, turf_type) + src.width = width + src.height = height + return TRUE + +/datum/turf_reservation/New() + LAZYADD(SSmapping.turf_reservations, src) + +/datum/turf_reservation/Destroy() + Release() + LAZYREMOVE(SSmapping.turf_reservations, src) + return ..()