Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7751 from RemieRichards/ProceduralGeneration
Procedural Map Generator System
- Loading branch information
Showing
10 changed files
with
442 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
|
||
/datum/mapGenerator | ||
|
||
//Map information | ||
var/list/map = list() | ||
var/turf/bottomLeft = null | ||
var/turf/topRight = null | ||
|
||
//mapGeneratorModule information | ||
var/list/modules = list() | ||
|
||
/datum/mapGenerator/New() | ||
..() | ||
initialiseModules() | ||
|
||
//Defines the region the map represents, sets map, bottomLeft, topRight | ||
//Returns the map | ||
/datum/mapGenerator/proc/defineRegion(var/turf/Start, var/turf/End) | ||
if(!checkRegion(Start, End)) | ||
return 0 | ||
|
||
if(!Start || !End) | ||
return 0 | ||
bottomLeft = Start | ||
topRight = End | ||
|
||
map = block(bottomLeft,topRight) | ||
return map | ||
|
||
|
||
//Checks for and Rejects bad region coordinates | ||
//Returns 1/0 | ||
/datum/mapGenerator/proc/checkRegion(var/turf/Start, var/turf/End) | ||
. = 1 | ||
|
||
if(!Start || !End) | ||
return 0 //Just bail | ||
|
||
if(Start.x > world.maxx || End.x > world.maxx) | ||
. = 0 | ||
if(Start.y > world.maxy || End.y > world.maxy) | ||
. = 0 | ||
if(Start.z > world.maxz || End.z > world.maxz) | ||
. = 0 | ||
|
||
|
||
//Requests the mapGeneratorModule(s) to (re)generate | ||
/datum/mapGenerator/proc/generate() | ||
set background = 1 //this can get beefy | ||
|
||
syncModules() | ||
if(!modules || !modules.len) | ||
return | ||
for(var/datum/mapGeneratorModule/mod in modules) | ||
mod.generate() | ||
|
||
|
||
//Requests the mapGeneratorModule(s) to (re)generate this one turf | ||
/datum/mapGenerator/proc/generateOneTurf(var/turf/T) | ||
if(!T) | ||
return | ||
syncModules() | ||
if(!modules || !modules.len) | ||
return | ||
for(var/datum/mapGeneratorModule/mod in modules) | ||
mod.place(T) | ||
|
||
|
||
//Replaces all paths in the module list with actual module datums | ||
/datum/mapGenerator/proc/initialiseModules() | ||
for(var/path in modules) | ||
if(ispath(path)) | ||
modules.Remove(path) | ||
modules |= new path | ||
syncModules() | ||
|
||
|
||
//Sync mapGeneratorModule(s) to mapGenerator | ||
/datum/mapGenerator/proc/syncModules() | ||
for(var/datum/mapGeneratorModule/mod in modules) | ||
mod.sync(src) | ||
|
||
|
||
|
||
/////////////////////////// | ||
// HERE BE DEBUG DRAGONS // | ||
/////////////////////////// | ||
|
||
/client/proc/debugNatureMapGenerator() | ||
set name = "Test Nature Map Generator" | ||
set category = "Debug" | ||
|
||
var/datum/mapGenerator/nature/N = new() | ||
var/startInput = input(usr,"Start turf of Map, (X;Y;Z)", "Map Gen Settings", "1;1;1") as text | ||
var/endInput = input(usr,"End turf of Map (X;Y;Z)", "Map Gen Settings", "[world.maxx];[world.maxy];[mob ? mob.z : 1]") as text | ||
//maxx maxy and current z so that if you fuck up, you only fuck up one entire z level instead of the entire universe | ||
if(!startInput || !endInput) | ||
src << "Missing Input" | ||
return | ||
|
||
var/list/startCoords = text2list(startInput, ";") | ||
var/list/endCoords = text2list(endInput, ";") | ||
if(!startCoords || !endCoords) | ||
src << "Invalid Coords" | ||
src << "Start Input: [startInput]" | ||
src << "End Input: [endInput]" | ||
return | ||
|
||
var/turf/Start = locate(text2num(startCoords[1]),text2num(startCoords[2]),text2num(startCoords[3])) | ||
var/turf/End = locate(text2num(endCoords[1]),text2num(endCoords[2]),text2num(endCoords[3])) | ||
if(!Start || !End) | ||
src << "Invalid Turfs" | ||
src << "Start Coords: [startCoords[1]] - [startCoords[2]] - [startCoords[3]]" | ||
src << "End Coords: [endCoords[1]] - [endCoords[2]] - [endCoords[3]]" | ||
return | ||
|
||
src << "Defining Region" | ||
N.defineRegion(Start, End) | ||
src << "Region Defined" | ||
src << "Generating Region" | ||
N.generate() | ||
src << "Generated Region" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
|
||
#define CLUSTER_CHECK_NONE 0 //No checks are done, cluster as much as possible | ||
#define CLUSTER_CHECK_ATOMS 2 //Don't let atoms cluster, based on clusterMin and clusterMax as guides | ||
#define CLUSTER_CHECK_TURFS 4 //Don't let turfs cluster, based on clusterMin and clusterMax as guides | ||
#define CLUSTER_CHECK_ALL 6 //Don't let anything cluster, based on clusterMind and clusterMax as guides | ||
|
||
/datum/mapGeneratorModule | ||
var/datum/mapGenerator/mother = null | ||
var/list/spawnableAtoms = list() | ||
var/list/spawnableTurfs = list() | ||
var/clusterMax = 5 | ||
var/clusterMin = 1 | ||
var/clusterCheckFlags = CLUSTER_CHECK_ALL | ||
|
||
|
||
//Syncs the module up with it's mother | ||
/datum/mapGeneratorModule/proc/sync(var/datum/mapGenerator/mum) | ||
mother = null | ||
if(mum) | ||
mother = mum | ||
|
||
|
||
//Generates it's spawnable atoms and turfs | ||
/datum/mapGeneratorModule/proc/generate() | ||
if(!mother) | ||
return | ||
var/list/map = mother.map | ||
for(var/turf/T in map) | ||
place(T) | ||
|
||
|
||
//Place a spawnable atom or turf on this turf | ||
/datum/mapGeneratorModule/proc/place(var/turf/T) | ||
if(!T) | ||
return 0 | ||
|
||
var/clustering = 0 | ||
|
||
//Turfs don't care whether atoms can be placed here | ||
for(var/turfPath in spawnableTurfs) | ||
if(clusterCheckFlags & CLUSTER_CHECK_TURFS) | ||
if(clusterMax && clusterMin) | ||
clustering = rand(clusterMin,clusterMax) | ||
if(locate(/atom/movable) in range(clustering, T)) | ||
continue | ||
if(prob(spawnableTurfs[turfPath])) | ||
T.ChangeTurf(turfPath) | ||
|
||
//Atoms DO care whether atoms can be placed here | ||
if(checkPlaceAtom(T)) | ||
for(var/atomPath in spawnableAtoms) | ||
if(clusterCheckFlags & CLUSTER_CHECK_ATOMS) | ||
if(clusterMax && clusterMin) | ||
clustering = rand(clusterMin,clusterMax) | ||
if(locate(/atom/movable) in range(clustering, T)) | ||
continue | ||
if(prob(spawnableAtoms[atomPath])) | ||
new atomPath (T) | ||
|
||
. = 1 | ||
|
||
|
||
//Checks and Rejects dense turfs | ||
/datum/mapGeneratorModule/proc/checkPlaceAtom(var/turf/T) | ||
. = 1 | ||
if(!T) | ||
return 0 | ||
if(T.density) | ||
. = 0 | ||
for(var/atom/A in T) | ||
if(A.density) | ||
. = 0 | ||
break | ||
|
||
|
||
/////////////////////////////////////////////////////////// | ||
// PREMADE BASE TEMPLATES // | ||
// Appropriate settings for usable types // | ||
// Not usable types themselves, use them as parent types // | ||
// Seriously, don't use these on their own, just parents // | ||
/////////////////////////////////////////////////////////// | ||
//The /atom and /turf examples are just so these compile, replace those with your typepaths in your subtypes. | ||
|
||
//Settings appropriate for a turf that covers the entire map region, eg a fill colour on a bottom layer in a graphics program. | ||
//Should only have one of these in your mapGenerator unless you want to waste CPU | ||
/datum/mapGeneratorModule/bottomLayer | ||
clusterCheckFlags = CLUSTER_CHECK_NONE | ||
spawnableAtoms = list()//Recommended: No atoms. | ||
spawnableTurfs = list(/turf = 100) | ||
|
||
//Settings appropriate for turfs/atoms that cover SOME of the map region, sometimes referred to as a splatter layer. | ||
/datum/mapGeneratorModule/splatterLayer | ||
clusterCheckFlags = CLUSTER_CHECK_ALL | ||
spawnableAtoms = list(/atom = 30) | ||
spawnableTurfs = list(/turf = 30) | ||
|
||
//Settings appropriate for turfs/atoms that cover a lot of the map region, eg a dense forest. | ||
/datum/mapGeneratorModule/denseLayer | ||
clusterCheckFlags = CLUSTER_CHECK_NONE | ||
spawnableAtoms = list(/atom = 75) | ||
spawnableTurfs = list(/turf = 75) |
37 changes: 37 additions & 0 deletions
37
code/modules/procedural mapping/mapGeneratorModules/nature.dm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
|
||
//Contents exist primarily for the nature generator test type. | ||
|
||
|
||
//Pine Trees | ||
/datum/mapGeneratorModule/pineTrees | ||
spawnableAtoms = list(/obj/structure/flora/tree/pine = 30) | ||
|
||
//Dead Trees | ||
/datum/mapGeneratorModule/deadTrees | ||
spawnableAtoms = list(/obj/structure/flora/tree/dead = 10) | ||
|
||
//Random assortment of bushes | ||
/datum/mapGeneratorModule/randBushes | ||
spawnableAtoms = list() | ||
|
||
/datum/mapGeneratorModule/randBushes/New() | ||
..() | ||
spawnableAtoms = typesof(/obj/structure/flora/ausbushes) | ||
for(var/i in spawnableAtoms) | ||
spawnableAtoms[i] = 20 | ||
|
||
|
||
//Random assortment of rocks and rockpiles | ||
/datum/mapGeneratorModule/randRocks | ||
spawnableAtoms = list(/obj/structure/flora/rock = 40, /obj/structure/flora/rock/pile = 20) | ||
|
||
|
||
//Grass turfs | ||
/datum/mapGeneratorModule/bottomLayer/grassTurfs | ||
spawnableTurfs = list(/turf/unsimulated/floor/grass = 100) | ||
|
||
|
||
//Grass tufts with a high spawn chance | ||
/datum/mapGeneratorModule/denseLayer/grassTufts | ||
spawnableTurfs = list() | ||
spawnableAtoms = list(/obj/structure/flora/ausbushes/grassybush = 75) |
Oops, something went wrong.