mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-19 20:15:47 +01:00
219 lines
7.3 KiB
Plaintext
219 lines
7.3 KiB
Plaintext
#define CAVE_SPAWN_MOB "mob"
|
|
#define CAVE_SPAWN_FEATURE "feature"
|
|
#define CAVE_SPAWN_TENDRIL "tendril"
|
|
#define CAVE_SPAWN_MEGAFAUNA "megafauna"
|
|
|
|
///This datum handles the transitioning from a turf to a specific biome, and handles spawning decorative structures and mobs.
|
|
/datum/biome
|
|
/// Type of turf this biome creates for open turfs
|
|
var/open_turf_type
|
|
/// Type of turf this biome creates for closed turfs
|
|
var/closed_turf_type
|
|
/// Chance of having a structure from the flora types list spawn
|
|
var/flora_density = 0
|
|
/// Chance of spawning special features, such as geysers.
|
|
var/feature_density = 0
|
|
/// Chance of having a mob from the fauna types list spawn
|
|
var/fauna_density = 0
|
|
/// Weighted list of type paths of flora that can be spawned when the
|
|
/// turf spawns flora.
|
|
var/list/flora_types = list()
|
|
/// Weighted list of extra features that can spawn in the biome, such as
|
|
/// geysers. Gets expanded automatically.
|
|
var/list/feature_types = list()
|
|
/// Weighted list of type paths of fauna that can be spawned when the
|
|
/// turf spawns fauna.
|
|
var/list/fauna_types = list()
|
|
/// Weighted list of megafauna that can spawn from SPAWN_MEGAFAUNA fauna entry
|
|
/// Defaults to GLOB.megafauna_spawn_list
|
|
var/list/megafauna_types = null
|
|
/// Radius around features within which we avoid spawning other features
|
|
var/feature_exclusion_radius = 7
|
|
/// Radius around mobs which we avoid spawning other mobs
|
|
var/mob_exclusion_radius = 12
|
|
/// Radius around megafauna within which we avoid spawning tendrils
|
|
var/megafauna_exclusion_radius = 7
|
|
/// Minimum distance between tendril spawns
|
|
var/tendril_exclusion_radius = 12
|
|
|
|
/datum/biome/New()
|
|
. = ..()
|
|
if(length(flora_types))
|
|
flora_types = expand_weights(fill_with_ones(flora_types))
|
|
|
|
if(length(fauna_types))
|
|
fauna_types = expand_weights(fill_with_ones(fauna_types))
|
|
|
|
if(length(feature_types))
|
|
feature_types = expand_weights(feature_types)
|
|
|
|
if(isnull(megafauna_types))
|
|
megafauna_types = GLOB.megafauna_spawn_list
|
|
|
|
///This proc handles the creation of a turf of a specific biome type
|
|
/datum/biome/proc/generate_turf(turf/gen_turf, closed)
|
|
if (closed)
|
|
gen_turf.ChangeTurf(closed_turf_type, null, CHANGETURF_DEFER_CHANGE)
|
|
return
|
|
|
|
gen_turf.ChangeTurf(open_turf_type, null, CHANGETURF_DEFER_CHANGE)
|
|
|
|
if(length(flora_types) && prob(flora_density))
|
|
var/obj/structure/flora = pick(flora_types)
|
|
new flora(gen_turf)
|
|
return
|
|
|
|
if(length(feature_types) && prob(feature_density))
|
|
var/atom/picked_feature = pick(feature_types)
|
|
new picked_feature(gen_turf)
|
|
return
|
|
|
|
if(length(fauna_types) && prob(fauna_density))
|
|
var/mob/fauna = pick(fauna_types)
|
|
new fauna(gen_turf)
|
|
|
|
|
|
/// This proc handles the creation of a turf of a specific biome type, assuming
|
|
/// that the turf has not been initialized yet. Don't call this unless you know
|
|
/// what you're doing.
|
|
/datum/biome/proc/generate_turf_for_terrain(turf/gen_turf, closed)
|
|
var/turf_type = closed ? closed_turf_type : open_turf_type
|
|
var/turf/new_turf = new turf_type(gen_turf)
|
|
return new_turf
|
|
|
|
|
|
/**
|
|
* This proc handles the sequential creation of turfs of a specific biome type
|
|
* in order to optimize the generation for large amount of turfs.
|
|
*
|
|
* Arguments:
|
|
* * gen_turfs - List of turfs to use for turf generation.
|
|
*
|
|
* Returns a new list of turfs that were generated by the biome.
|
|
*/
|
|
/datum/biome/proc/generate_turfs_for_terrain(list/turf/gen_turfs)
|
|
var/list/turf/new_turfs = list()
|
|
|
|
for(var/turf/gen_turf as anything in gen_turfs)
|
|
var/closed = gen_turfs[gen_turf]
|
|
var/turf_type = closed ? closed_turf_type : open_turf_type
|
|
var/turf/new_turf = new turf_type(gen_turf)
|
|
new_turfs[new_turf] = turf_type
|
|
|
|
if(gen_turf.turf_flags & NO_RUINS)
|
|
new_turf.turf_flags |= NO_RUINS
|
|
|
|
CHECK_TICK
|
|
|
|
return new_turfs
|
|
|
|
|
|
/**
|
|
* This proc handles populating the given turfs based on whether flora, features
|
|
* and fauna are allowed. Does not take megafauna into account.
|
|
*
|
|
* Does nothing if `flora_allowed`, `features_allowed` and `fauna_allowed` are
|
|
* `FALSE`, or if there's no flora, feature or fauna types for the matching
|
|
* allowed type. Aka, we return early if the proc wouldn't do anything anyway.
|
|
*/
|
|
/datum/biome/proc/populate_turfs(list/turf/target_turfs, flora_allowed, features_allowed, fauna_allowed)
|
|
var/has_flora = flora_allowed && length(flora_types)
|
|
var/has_features = features_allowed && length(feature_types)
|
|
var/has_fauna = fauna_allowed && length(fauna_types)
|
|
|
|
if(!has_flora && !has_features && !has_fauna)
|
|
return
|
|
|
|
// Assoc list of spawned categories to
|
|
// Static as to be shared between all biomes
|
|
var/static/list/spawn_data
|
|
if (isnull(spawn_data))
|
|
spawn_data = list(
|
|
CAVE_SPAWN_FEATURE = list(),
|
|
CAVE_SPAWN_TENDRIL = list(),
|
|
CAVE_SPAWN_MOB = list(),
|
|
CAVE_SPAWN_MEGAFAUNA = list(),
|
|
)
|
|
|
|
for(var/turf/target_turf as anything in target_turfs)
|
|
// Only put stuff on open turfs we generated, so closed walls and rivers and stuff are skipped
|
|
if(!istype(target_turf, open_turf_type))
|
|
continue
|
|
|
|
CHECK_TICK
|
|
if (!(target_turf.turf_flags & TURF_BLOCKS_POPULATE_TERRAIN_FLORAFEATURES))
|
|
if (flora_allowed && prob(flora_density))
|
|
var/flora_type = pick(flora_types)
|
|
new flora_type(target_turf)
|
|
continue
|
|
|
|
if (features_allowed && prob(feature_density))
|
|
var/can_spawn = TRUE
|
|
for(var/turf/spawn_turf as anything in spawn_data[CAVE_SPAWN_FEATURE])
|
|
if (get_dist(spawn_turf, target_turf) <= feature_exclusion_radius)
|
|
can_spawn = FALSE
|
|
break
|
|
|
|
if (can_spawn)
|
|
var/picked_feature = pick(feature_types)
|
|
new picked_feature(target_turf)
|
|
spawn_data[CAVE_SPAWN_FEATURE] += target_turf
|
|
continue
|
|
|
|
if (!fauna_allowed || !prob(fauna_density))
|
|
continue
|
|
|
|
var/picked_mob = pick(fauna_types)
|
|
var/is_megafauna = FALSE
|
|
if (picked_mob == SPAWN_MEGAFAUNA)
|
|
picked_mob = pick_weight(megafauna_types)
|
|
is_megafauna = TRUE
|
|
|
|
var/can_spawn = TRUE
|
|
if(ispath(picked_mob, /mob/living/basic/mining/tendril))
|
|
for(var/turf/spawn_turf as anything in spawn_data[CAVE_SPAWN_TENDRIL])
|
|
if (get_dist(spawn_turf, target_turf) <= tendril_exclusion_radius)
|
|
can_spawn = FALSE
|
|
break
|
|
|
|
if (!can_spawn)
|
|
continue
|
|
|
|
// Also avoid spawning them next to megafauna
|
|
for(var/turf/spawn_turf as anything in spawn_data[CAVE_SPAWN_MEGAFAUNA])
|
|
if (get_dist(spawn_turf, target_turf) <= megafauna_exclusion_radius)
|
|
can_spawn = FALSE
|
|
break
|
|
|
|
else if (is_megafauna)
|
|
// Megafauna can spawn wherever it wants as long as its not next to another mega
|
|
for(var/turf/spawn_turf as anything in spawn_data[CAVE_SPAWN_MEGAFAUNA])
|
|
if (get_dist(spawn_turf, target_turf) <= megafauna_exclusion_radius)
|
|
can_spawn = FALSE
|
|
break
|
|
else
|
|
for(var/turf/spawn_turf as anything in spawn_data[CAVE_SPAWN_MOB])
|
|
if (get_dist(spawn_turf, target_turf) <= mob_exclusion_radius)
|
|
can_spawn = FALSE
|
|
break
|
|
|
|
if (!can_spawn)
|
|
continue
|
|
|
|
if (ispath(picked_mob, /mob/living/basic/mining/tendril))
|
|
spawn_data[CAVE_SPAWN_TENDRIL] += target_turf
|
|
else if (is_megafauna)
|
|
spawn_data[CAVE_SPAWN_MEGAFAUNA] += target_turf
|
|
spawn_data[CAVE_SPAWN_MOB] += target_turf
|
|
|
|
new picked_mob(target_turf)
|
|
|
|
// There can be only one Bubblegum, so don't waste spawns on it
|
|
if(ispath(picked_mob, /mob/living/simple_animal/hostile/megafauna/bubblegum))
|
|
megafauna_types.Remove(picked_mob)
|
|
|
|
#undef CAVE_SPAWN_MOB
|
|
#undef CAVE_SPAWN_FEATURE
|
|
#undef CAVE_SPAWN_TENDRIL
|
|
#undef CAVE_SPAWN_MEGAFAUNA
|