Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements Perlin noise based map generation and jungle generation #3683

Merged
merged 21 commits into from Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions _std/map.dm
Expand Up @@ -6,3 +6,18 @@
#define Z_LEVEL_SECRET 4 //The Z-level used for secret things.
#define Z_LEVEL_MINING 5 //The mining Z-level.
#define Z_LEVEL_FOOTBALL 6 //The Z-level used for football.

///Map generation defines
#define PERLIN_LAYER_HEIGHT "perlin_height"
#define PERLIN_LAYER_HUMIDITY "perlin_humidity"
#define PERLIN_LAYER_HEAT "perlin_heat"

#define BIOME_LOW_HEAT "low_heat"
#define BIOME_LOWMEDIUM_HEAT "lowmedium_heat"
#define BIOME_HIGHMEDIUM_HEAT "highmedium_heat"
#define BIOME_HIGH_HEAT "high_heat"

#define BIOME_LOW_HUMIDITY "low_humidity"
#define BIOME_LOWMEDIUM_HUMIDITY "lowmedium_humidity"
#define BIOME_HIGHMEDIUM_HUMIDITY "highmedium_humidity"
#define BIOME_HIGH_HUMIDITY "high_humidity"
Sovexe marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions code/area.dm
Expand Up @@ -143,6 +143,9 @@ ABSTRACT_TYPE(/area) // don't instantiate this directly dummies, use /area/space
/// Local list of obj/machines found in the area
var/list/machines = list()

///This datum, if set, allows terrain generation behavior to be ran on Initialize()
Sovexe marked this conversation as resolved.
Show resolved Hide resolved
var/datum/map_generator/map_generator

proc/CanEnter(var/atom/movable/A)
if( blocked )
if( ismob(A) )
Expand Down
82 changes: 82 additions & 0 deletions code/datums/mapgen/JungleGenerator.dm
@@ -0,0 +1,82 @@
//the random offset applied to square coordinates, causes intermingling at biome borders
#define BIOME_RANDOM_SQUARE_DRIFT 2

/datum/map_generator/jungle_generator
///2D list of all biomes based on heat and humidity combos.
var/list/possible_biomes = list(
BIOME_LOW_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/plains,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/mudlands,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/mudlands,
BIOME_HIGH_HUMIDITY = /datum/biome/water
),
BIOME_LOWMEDIUM_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/plains,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/jungle,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle,
BIOME_HIGH_HUMIDITY = /datum/biome/mudlands
),
BIOME_HIGHMEDIUM_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/plains,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/plains,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle/deep,
BIOME_HIGH_HUMIDITY = /datum/biome/jungle
),
BIOME_HIGH_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/wasteland,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/plains,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle,
BIOME_HIGH_HUMIDITY = /datum/biome/jungle/deep
)
)
///Used to select "zoom" level into the perlin noise, higher numbers result in slower transitions
var/perlin_zoom = 65

///Seeds the rust-g perlin noise with a random number.
/datum/map_generator/jungle_generator/generate_terrain(var/list/turfs)
. = ..()
var/height_seed = rand(0, 50000)
var/humidity_seed = rand(0, 50000)
var/heat_seed = rand(0, 50000)

for(var/t in turfs) //Go through all the turfs and generate them
var/turf/gen_turf = t
var/drift_x = (gen_turf.x + rand(-BIOME_RANDOM_SQUARE_DRIFT, BIOME_RANDOM_SQUARE_DRIFT)) / perlin_zoom
var/drift_y = (gen_turf.y + rand(-BIOME_RANDOM_SQUARE_DRIFT, BIOME_RANDOM_SQUARE_DRIFT)) / perlin_zoom

var/height = text2num(rustg_noise_get_at_coordinates("[height_seed]", "[drift_x]", "[drift_y]"))


var/datum/biome/selected_biome
if(height <= 0.85) //If height is less than 0.85, we generate biomes based on the heat and humidity of the area.
var/humidity = text2num(rustg_noise_get_at_coordinates("[humidity_seed]", "[drift_x]", "[drift_y]"))
var/heat = text2num(rustg_noise_get_at_coordinates("[heat_seed]", "[drift_x]", "[drift_y]"))
var/heat_level //Type of heat zone we're in LOW-MEDIUM-HIGH
var/humidity_level //Type of humidity zone we're in LOW-MEDIUM-HIGH

switch(heat)
if(0 to 0.25)
heat_level = BIOME_LOW_HEAT
if(0.25 to 0.5)
heat_level = BIOME_LOWMEDIUM_HEAT
if(0.5 to 0.75)
heat_level = BIOME_HIGHMEDIUM_HEAT
if(0.75 to 1)
heat_level = BIOME_HIGH_HEAT
switch(humidity)
if(0 to 0.25)
humidity_level = BIOME_LOW_HUMIDITY
if(0.25 to 0.5)
humidity_level = BIOME_LOWMEDIUM_HUMIDITY
if(0.5 to 0.75)
humidity_level = BIOME_HIGHMEDIUM_HUMIDITY
if(0.75 to 1)
humidity_level = BIOME_HIGH_HUMIDITY
selected_biome = possible_biomes[heat_level][humidity_level]
else //Over 0.85; It's a mountain
selected_biome = /datum/biome/mountain
selected_biome = biomes[selected_biome] //Get the instance of this biome from SSmapping
selected_biome.generate_turf(gen_turf)
LAGCHECK(LAG_HIGH)


45 changes: 45 additions & 0 deletions code/datums/mapgen/_MapGenerator.dm
@@ -0,0 +1,45 @@
///All possible biomes in assoc list as type || instance
var/list/biomes = list()
Sovexe marked this conversation as resolved.
Show resolved Hide resolved

///Initialize all biomes, assoc as type || instance
proc/initialize_biomes()
for(var/biome_path in concrete_typesof(/datum/biome))
var/datum/biome/biome_instance = new biome_path()
biomes[biome_path] += biome_instance

///This type is responsible for any map generation behavior that is done in areas, override this to allow for area-specific map generation. This generation is ran by areas in initialize.
ZeWaka marked this conversation as resolved.
Show resolved Hide resolved
/datum/map_generator

///This proc will be ran by areas on Initialize, and provides the areas turfs as argument to allow for generation.
Sovexe marked this conversation as resolved.
Show resolved Hide resolved
/datum/map_generator/proc/generate_terrain(var/list/turfs)
return

ABSTRACT_TYPE(area/map_gen)
area/map_gen
name = "map gen"
icon = 'icons/turf/map_gen.dmi'
icon_state = "genarea"

New()
. = ..()
START_TRACKING

disposing()
STOP_TRACKING
. = ..()

proc/generate_perlin_noise_terrain()
if(src.map_generator)
map_generator = new map_generator()
map_generator.generate_terrain(get_area_turfs(src))

/area/map_gen/jungle
name = "planet generation area"
icon = 'icons/turf/areas.dmi'
map_generator = /datum/map_generator/jungle_generator

/turf/map_gen
name = "ungenerated turf"
desc = "If you see this, and you're not a ghost, yell at coders"
icon = 'icons/turf/map_gen.dmi'
icon_state = "genturf"
50 changes: 50 additions & 0 deletions code/datums/mapgen/biomes/_biome.dm
@@ -0,0 +1,50 @@
///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
var/turf_type
///Chance of having a structure from the flora types list spawn
var/flora_density = 0
///Chance of having a mob from the fauna types list spawn
var/fauna_density = 0
///list of type paths of objects that can be spawned when the turf spawns flora
var/list/flora_types = list(/obj/tree1)
///list of type paths of mobs that can be spawned when the turf spawns fauna
var/list/fauna_types = list()
Sovexe marked this conversation as resolved.
Show resolved Hide resolved

///This proc handles the creation of a turf of a specific biome type
/datum/biome/proc/generate_turf(var/turf/gen_turf)
gen_turf.ReplaceWith(turf_type)
if(length(fauna_types) && prob(fauna_density))
var/mob/fauna = pick(fauna_types)
new fauna(gen_turf)

if(length(flora_types) && prob(flora_density))
var/obj/structure/flora = pick(flora_types)
new flora(gen_turf)

/datum/biome/mudlands
turf_type = /turf/unsimulated/dirt
flora_types = list(/obj/stone/random, /obj/decal/fakeobjects/rockpile, /obj/decal/fakeobjects/smallrocks)
flora_density = 3

/datum/biome/plains
turf_type = /turf/unsimulated/floor/setpieces/swampgrass
flora_types = list(/obj/tree1/random, /obj/shrub/random, /obj/stone/random, /obj/decal/fakeobjects/rockpile, /obj/decal/fakeobjects/smallrocks)
flora_density = 15

/datum/biome/jungle
turf_type = /turf/unsimulated/floor/grass/leafy
flora_types = list(/obj/tree1/random, /obj/shrub/random, /obj/stone/random, /obj/decal/fakeobjects/rockpile, /obj/decal/fakeobjects/smallrocks)
flora_density = 30

/datum/biome/jungle/deep
flora_density = 45

/datum/biome/wasteland
turf_type = /turf/unsimulated/greek/beach

/datum/biome/water
turf_type = /turf/unsimulated/wall/water

/datum/biome/mountain
turf_type = /turf/simulated/wall/asteroid
15 changes: 15 additions & 0 deletions code/obj/decorations.dm
Expand Up @@ -54,6 +54,11 @@
density = 1
opacity = 0 // this causes some of the super ugly lighting issues too

random
New()
. = ..()
src.dir = pick(cardinal)

// what the hell is all this and why wasn't it just using a big icon? the lighting system gets all fucked up with this stuff

/*
Expand Down Expand Up @@ -112,6 +117,11 @@
anchored = 1
density=1

random
New()
. = ..()
src.dir = pick(alldirs)

/obj/shrub
name = "shrub"
icon = 'icons/misc/worlds.dmi'
Expand Down Expand Up @@ -207,6 +217,11 @@
qdel(src)
return

random
New()
. = ..()
src.dir = pick(alldirs)

/obj/shrub/captainshrub
name = "\improper Captain's bonsai tree"
icon = 'icons/misc/worlds.dmi'
Expand Down
9 changes: 9 additions & 0 deletions code/world.dm
Expand Up @@ -583,6 +583,15 @@ var/f_color_selector_handler/F_Color_Selector
makeMiningLevel()
#endif

UPDATE_TITLE_STATUS("Initializing biomes")
Z_LOG_DEBUG("World/Init", "Setting up biomes...")
initialize_biomes()

UPDATE_TITLE_STATUS("Generating terrain")
Z_LOG_DEBUG("World/Init", "Setting perlin noise terrain...")
for (var/area/map_gen/A in by_type[/area/map_gen])
A.generate_perlin_noise_terrain()

UPDATE_TITLE_STATUS("Calculating cameras")
Z_LOG_DEBUG("World/Init", "Updating camera visibility...")
aiDirty = 2
Expand Down
3 changes: 3 additions & 0 deletions goonstation.dme
Expand Up @@ -382,6 +382,9 @@ var/datum/preMapLoad/preMapLoad = new
#include "code\datums\hud\vision_impair.dm"
#include "code\datums\hud\wraith.dm"
#include "code\datums\hud\zone_sel.dm"
#include "code\datums\mapgen\_MapGenerator.dm"
#include "code\datums\mapgen\JungleGenerator.dm"
#include "code\datums\mapgen\biomes\_biome.dm"
#include "code\datums\movement_controller\colosseum_putt.dm"
#include "code\datums\movement_controller\movement_controller.dm"
#include "code\datums\movement_controller\obj_control.dm"
Expand Down
Binary file added icons/turf/map_gen.dmi
Binary file not shown.