Files
Paradise/code/game/objects/effects/spawners/dynamic_bridge_spawner.dm
2025-05-25 16:45:52 +00:00

337 lines
11 KiB
Plaintext

#define LONG_BRIDGE_THEME_CULT "cult"
#define LONG_BRIDGE_THEME_HIERO "hiero"
#define LONG_BRIDGE_THEME_CLOCKWORK "clockwork"
#define LONG_BRIDGE_THEME_STONE "stone"
#define LONG_BRIDGE_THEME_WOOD "wood"
#define LONG_BRIDGE_THEME_CATWALK "catwalk"
/**
* A spawner for dynamic bridges, largely with hardcoded expectations to be
* operating on Lavaland.
*
* It does this by starting at its spawn point, placed by a
* [/datum/river_spawner] during generation, and walking in each direction
* "forwards" and "backwards" until it reaches the maximum possible length of
* the bridge, or a tile that doesn't appear to be a valid "passage"
* (essentially a tile that doesn't have lava on both sides and thus wouldn't
* look good or make an effective bridge). If it manages to do this and find two
* tiles that work as the start and end of the bridge, it places the paths,
* pillars, and "cleans up" the tiles contiguous to its entrance and exit turfs,
* removing any lava if present.
*
* It attempts this first in the vertical direction, and then the horizontal. So
* "fowards" and "backwards" can mean NORTH/SOUTH or EAST/WEST depending on the
* direction it's attempting.
*
* There are several bridge "themes" implemented in `make_walkway()` and
* `make_pillar()`, and more can be added if desired.
*/
/obj/effect/spawner/dynamic_bridge
var/max_length = 8
var/min_length = 4
var/bridge_theme
var/list/forwards_backwards
var/list/side_to_side
var/turf/forward_goal
var/turf/backward_goal
/obj/effect/spawner/dynamic_bridge/Initialize(mapload)
. = ..()
if(!bridge_theme)
bridge_theme = pick(
LONG_BRIDGE_THEME_CULT,
LONG_BRIDGE_THEME_HIERO,
LONG_BRIDGE_THEME_CLOCKWORK,
LONG_BRIDGE_THEME_STONE,
LONG_BRIDGE_THEME_WOOD,
LONG_BRIDGE_THEME_CATWALK,
)
return INITIALIZE_HINT_LATELOAD
/obj/effect/spawner/dynamic_bridge/LateInitialize()
forwards_backwards = list(NORTH, SOUTH)
side_to_side = list(EAST, WEST)
if(attempt_bridge() != BRIDGE_SPAWN_SUCCESS)
forward_goal = null
backward_goal = null
forwards_backwards = list(EAST, WEST)
side_to_side = list(NORTH, SOUTH)
attempt_bridge()
qdel(src)
/// Returns whether the passed in turf is a valid "landing". A valid landing is
/// a tile that hasn't been reserved by another bridge, and has a non-lava tile
/// leading directly to it.
/obj/effect/spawner/dynamic_bridge/proc/valid_landing(turf/T, direction)
if(T.flags & LAVA_BRIDGE || T.flags & NO_LAVA_GEN)
return FALSE
var/turf/end = get_step(T, direction)
if(end.flags & LAVA_BRIDGE || !(ismineralturf(end) || istype(end, /turf/simulated/floor/plating/asteroid)))
return FALSE
var/area/A = get_area(end)
if(istype(A, /area/lavaland/surface/gulag_rock))
return FALSE
if(istype(A, /area/lavaland/surface/outdoors/outpost))
return FALSE
if(istype(A, /area/mine/outpost))
return FALSE
if(istype(A, /area/shuttle))
return FALSE
return TRUE
/obj/effect/spawner/dynamic_bridge/proc/bridgeable_turf(turf/T)
// Pre SSlatemapping, before we've replaced mapping turfs with their river theme
if(istype(T, /turf/simulated/floor/lava/mapping_lava))
return TRUE
// Everything else
if(istype(T, /turf/simulated/floor/chasm))
return TRUE
if(istype(T, /turf/simulated/floor/lava))
return TRUE
/// Returns whether the passed in turf is a valid "passage". A valid passage is
/// a lava tile that has lava on both sides of it. Invalid passage tiles do not
/// look good as bridge walkways and defeat the purpose of there is floor right
/// next to it.
/obj/effect/spawner/dynamic_bridge/proc/valid_passage(turf/T)
if(T.flags & LAVA_BRIDGE)
return FALSE
if(!bridgeable_turf(T))
return FALSE
if(!bridgeable_turf(get_step(T, side_to_side[1])))
return FALSE
if(!bridgeable_turf(get_step(T, side_to_side[2])))
return FALSE
var/area/A = get_area(T)
if(istype(A, /area/lavaland/surface/gulag_rock))
return FALSE
return TRUE
/obj/effect/spawner/dynamic_bridge/proc/make_pillar(turf/T)
for(var/obj/structure/spawner/S in T)
qdel(S)
for(var/mob/living/M in T)
qdel(M)
for(var/obj/structure/flora/F in T)
qdel(F)
switch(bridge_theme)
if(LONG_BRIDGE_THEME_CULT)
T.ChangeTurf(/turf/simulated/wall/cult)
if(LONG_BRIDGE_THEME_HIERO)
T.ChangeTurf(/turf/simulated/wall/indestructible/hierophant)
if(LONG_BRIDGE_THEME_CLOCKWORK)
T.ChangeTurf(/turf/simulated/wall/clockwork)
if(LONG_BRIDGE_THEME_STONE)
T.ChangeTurf(/turf/simulated/wall/cult)
if(LONG_BRIDGE_THEME_WOOD)
T.ChangeTurf(/turf/simulated/wall/mineral/wood/nonmetal)
if(LONG_BRIDGE_THEME_CATWALK)
new /obj/structure/lattice/catwalk/mining(T)
new /obj/structure/marker_beacon/dock_marker/collision(T)
T.flags |= LAVA_BRIDGE
/obj/structure/bridge_walkway
name = "floor"
icon = 'icons/turf/floors.dmi'
layer = ABOVE_OPEN_TURF_LAYER
anchored = TRUE
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/structure/bridge_walkway/Destroy()
var/turf/T = get_turf(src)
if(T)
T.layer = PLATING_LAYER
T.clear_filters()
return ..()
/obj/structure/bridge_walkway/cult
icon_state = "cult"
/obj/structure/bridge_walkway/hiero
icon = 'icons/turf/floors/hierophant_floor.dmi'
icon_state = "floor"
/obj/structure/bridge_walkway/clockwork
name = "clockwork floor"
icon_state = "clockwork_floor"
/obj/structure/bridge_walkway/clockwork/Initialize(mapload)
. = ..()
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_crossed)
)
AddElement(/datum/element/connect_loc, loc_connections)
// Pretend to be a normal clockwork floor and duplicate its visual effect
/obj/structure/bridge_walkway/clockwork/proc/on_crossed(atom/crosser)
var/counter = 0
for(var/obj/effect/temp_visual/ratvar/floor/floor in contents)
if(++counter == 3)
return
if(!. && isliving(crosser))
addtimer(CALLBACK(src, PROC_REF(spawn_visual)), 0.2 SECONDS, TIMER_DELETE_ME)
/obj/structure/bridge_walkway/clockwork/proc/spawn_visual()
new /obj/effect/temp_visual/ratvar/floor(loc)
/obj/structure/bridge_walkway/wood
icon_state = "wood"
/obj/effect/spawner/dynamic_bridge/proc/make_walkway(turf/T)
for(var/obj/structure/spawner/S in T)
qdel(S)
for(var/mob/living/M in T)
qdel(M)
for(var/obj/structure/flora/F in T)
qdel(F)
switch(bridge_theme)
if(LONG_BRIDGE_THEME_CULT)
new /obj/structure/bridge_walkway/cult(T)
if(LONG_BRIDGE_THEME_HIERO)
new /obj/structure/bridge_walkway/hiero(T)
if(LONG_BRIDGE_THEME_CLOCKWORK)
new /obj/structure/bridge_walkway/clockwork(T)
if(LONG_BRIDGE_THEME_STONE)
// Stone tiles are different sizes and shapes so these are
// "safe-looking" arrangements.
switch(rand(1, 5))
if(1)
new /obj/structure/stone_tile/block(T)
var/obj/structure/stone_tile/block/cracked/C = new(T)
C.dir = NORTH
if(2)
new /obj/structure/stone_tile/slab(T)
if(3)
new /obj/structure/stone_tile/surrounding(T)
new /obj/structure/stone_tile/center(T)
if(4)
new /obj/structure/stone_tile/slab/cracked(T)
if(5)
new /obj/structure/stone_tile/burnt(T)
var/obj/structure/stone_tile/surrounding_tile/ST = new(T)
ST.dir = WEST
var/obj/structure/stone_tile/block/B = new(T)
B.dir = NORTH
if(LONG_BRIDGE_THEME_WOOD)
var/obj/structure/bridge_walkway/wood/tile = new(T)
if(prob(20))
tile.icon_state = pick("wood-broken", "wood-broken2", "wood-broken3", "wood-broken4", "wood-broken5", "wood-broken6", "wood-broken7")
if(LONG_BRIDGE_THEME_CATWALK)
new /obj/structure/lattice/catwalk/mining(T)
T.flags |= LAVA_BRIDGE
/// Make a tile safe for player passage, for use at the bridge entrance and exits
/obj/effect/spawner/dynamic_bridge/proc/cleanup_edge(turf/T)
if(bridgeable_turf(T))
T.ChangeTurf(/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface)
T.icon_state = "basalt" // hate
/obj/effect/spawner/dynamic_bridge/proc/attempt_bridge()
var/count = 1
var/walk_dir = forwards_backwards[1]
var/turf/forward_step = get_turf(src)
var/turf/backward_step = get_turf(src)
var/bad_passage = FALSE
while(count <= max_length && !(forward_goal && backward_goal) && !bad_passage)
if(walk_dir == forwards_backwards[1])
if(!forward_goal)
if(out_of_bounds(walk_dir, forward_step))
break // Out of bounds
forward_step = get_step(forward_step, walk_dir)
if(valid_landing(forward_step, walk_dir))
forward_goal = forward_step
else if(!valid_passage(forward_step))
bad_passage = TRUE
count++
walk_dir = forwards_backwards[2]
else
if(!backward_goal)
if(out_of_bounds(walk_dir, backward_step))
break // Out of bounds
backward_step = get_step(backward_step, walk_dir)
if(valid_landing(backward_step, walk_dir))
backward_goal = backward_step
else if(!valid_passage(backward_step))
bad_passage = TRUE
count++
walk_dir = forwards_backwards[1]
if(bad_passage)
return BRIDGE_SPAWN_BAD_TERRAIN
if(count < min_length)
return BRIDGE_SPAWN_TOO_NARROW
if(count > max_length)
return BRIDGE_SPAWN_TOO_WIDE
if(!bad_passage && count >= min_length && forward_goal && backward_goal)
for(var/turf/T in get_line(forward_goal, backward_goal))
make_walkway(T)
for(var/turf/T in list(
get_step(forward_goal, side_to_side[1]),
get_step(forward_goal, side_to_side[2]),
get_step(backward_goal, side_to_side[1]),
get_step(backward_goal, side_to_side[2])))
make_pillar(T)
for(var/turf/T in get_line(
get_step(get_step(forward_goal, side_to_side[1]), forwards_backwards[1]),
get_step(get_step(forward_goal, side_to_side[2]), forwards_backwards[1])))
cleanup_edge(T)
for(var/turf/T in get_line(
get_step(get_step(backward_goal, side_to_side[1]), forwards_backwards[2]),
get_step(get_step(backward_goal, side_to_side[2]), forwards_backwards[2])))
cleanup_edge(T)
return BRIDGE_SPAWN_SUCCESS
/// Checks if we are going out of bounds. Returns TRUE if we are close (less than or equal to 2 turfs) to a border
/obj/effect/spawner/dynamic_bridge/proc/out_of_bounds(direction, turf/current_turf)
if(!direction || !current_turf)
return TRUE
switch(direction)
if(NORTH)
return current_turf.y >= world.maxy - 2
if(EAST)
return current_turf.x >= world.maxx - 2
if(SOUTH)
return current_turf.y <= 2
if(WEST)
return current_turf.x <= 2
return TRUE
/obj/effect/spawner/dynamic_bridge/capsule
bridge_theme = LONG_BRIDGE_THEME_CATWALK
/obj/effect/spawner/dynamic_bridge/capsule/Initialize(mapload, thrown_dir)
. = ..()
if(thrown_dir in list(EAST, WEST))
forwards_backwards = list(EAST, WEST)
side_to_side = list(NORTH, SOUTH)
else
forwards_backwards = list(NORTH, SOUTH)
side_to_side = list(EAST, WEST)
return INITIALIZE_HINT_NORMAL
#undef LONG_BRIDGE_THEME_CULT
#undef LONG_BRIDGE_THEME_HIERO
#undef LONG_BRIDGE_THEME_CLOCKWORK
#undef LONG_BRIDGE_THEME_STONE
#undef LONG_BRIDGE_THEME_WOOD
#undef LONG_BRIDGE_THEME_CATWALK