From 6d84f9e2bd223bd79a171153227d12987d85836d Mon Sep 17 00:00:00 2001 From: JT Traub Date: Wed, 3 Jul 2024 21:23:18 -0700 Subject: [PATCH] Generator code for the NewOrigins 7 map (#197) * Initial cut of ring map * Add Barrens, tweak map generation * map view color for barren --- aregion.cpp | 4 ++ aregion.h | 3 ++ basic/map.cpp | 7 +++ fracas/map.cpp | 7 +++ gamedata.cpp | 11 +++++ gamedata.h | 1 + havilah/map.cpp | 7 +++ map_viewer/index.ts | 1 + neworigins/map.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++ neworigins/rules.cpp | 8 ++-- neworigins/world.cpp | 12 ++--- standard/map.cpp | 7 +++ unittest/map.cpp | 3 ++ 13 files changed, 163 insertions(+), 10 deletions(-) diff --git a/aregion.cpp b/aregion.cpp index a9f61a203..694389e9a 100644 --- a/aregion.cpp +++ b/aregion.cpp @@ -3097,6 +3097,10 @@ void placeVolcanoes(ARegionArray* arr, const int w, const int h) { } } +void ARegionList::PlaceVolcanos(ARegionArray *arr) { + placeVolcanoes(arr, arr->x, arr->y); +} + int distance(graphs::Location2D a, graphs::Location2D b) { int dX = std::abs(a.x - b.x); int dY = std::abs(a.y - b.y); diff --git a/aregion.h b/aregion.h index 3ac8e154a..3c69ac8a0 100644 --- a/aregion.h +++ b/aregion.h @@ -483,6 +483,7 @@ class ARegionList : public AList void CreateNexusLevel(int level, int xSize, int ySize, char const *name); void CreateSurfaceLevel(int level, int xSize, int ySize, char const *name); void CreateNaturalSurfaceLevel(Map* map); + void CreateIslandRingLevel(int level, int xSize, int ySize, char const *name); void CreateIslandLevel(int level, int nPlayers, char const *name); void CreateUnderworldLevel(int level, int xSize, int ySize, char const *name); void CreateUnderdeepLevel(int level, int xSize, int ySize, char const *name); @@ -530,11 +531,13 @@ class ARegionList : public AList void SetRegTypes(ARegionArray *pRegs, int newType); void MakeLand(ARegionArray *pRegs, int percentOcean, int continentSize); void MakeCentralLand(ARegionArray *pRegs); + void MakeRingLand(ARegionArray *pRegs, int minDistance, int maxDistance); void SetupAnchors(ARegionArray *pArr); void GrowTerrain(ARegionArray *pArr, int growOcean); void RandomTerrain(ARegionArray *pArr); void MakeUWMaze(ARegionArray *pArr); + void PlaceVolcanos(ARegionArray *pArr); void MakeIslands(ARegionArray *pArr, int nPlayers); void MakeOneIsland(ARegionArray *pRegs, int xx, int yy); diff --git a/basic/map.cpp b/basic/map.cpp index 2ca9930ce..addf741da 100644 --- a/basic/map.cpp +++ b/basic/map.cpp @@ -195,6 +195,11 @@ void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) FinalSetup(pRegionArrays[level]); } +void ARegionList::CreateIslandRingLevel(int level, int xSize, int ySize, char const *name) +{ + throw "CreateIslandRingLevel not implemented for this game ruleset"; +} + void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, char const *name) { @@ -524,6 +529,8 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, Awrite(""); } +void ARegionList::MakeRingLand(ARegionArray *pReg, int minDistance, int maxDistance) { } + void ARegionList::MakeCentralLand(ARegionArray *pRegs) { for (int i = 0; i < pRegs->x; i++) { diff --git a/fracas/map.cpp b/fracas/map.cpp index e49fbfff0..0ad243ca9 100644 --- a/fracas/map.cpp +++ b/fracas/map.cpp @@ -195,6 +195,11 @@ void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) FinalSetup(pRegionArrays[level]); } +void ARegionList::CreateIslandRingLevel(int level, int xSize, int ySize, char const *name) +{ + throw "CreateIslandRingLevel not implemented for this game ruleset"; +} + void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, char const *name) { @@ -524,6 +529,8 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, Awrite(""); } +void ARegionList::MakeRingLand(ARegionArray *pReg, int minDistance, int maxDistance) { } + void ARegionList::MakeCentralLand(ARegionArray *pRegs) { for (int i = 0; i < pRegs->x; i++) { diff --git a/gamedata.cpp b/gamedata.cpp index e09d8cb70..62e3df5ad 100644 --- a/gamedata.cpp +++ b/gamedata.cpp @@ -4748,6 +4748,17 @@ static TerrainType td[] = { {-1,-1,-1}, 1,I_PIRATES,-1,-1, 5,{O_ISLE,-1,O_OCAVE,-1,-1,-1}}, + + // Terrain for NO7 (barren) + {"barren", "barrens", "barren", '*', R_BARREN, + TerrainType::BARREN | TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS, + 0,0,0,1, + {{-1,0,0},{-1,0,0},{-1,0,0},{-1,0,0}, + {-1,0,0},{-1,0,0},{-1,0,0}}, + {-1,-1,-1,-1}, + {-1,-1,-1}, + 0,-1,-1,-1, + 0,{-1,-1,-1,-1,-1,-1}}, }; TerrainType *TerrainDefs = td; diff --git a/gamedata.h b/gamedata.h index e7ec73fa6..4e8030c29 100644 --- a/gamedata.h +++ b/gamedata.h @@ -541,6 +541,7 @@ enum { R_CERAN_CHASM1, R_VOLCANO, R_LAKE, + R_BARREN, R_NUM }; diff --git a/havilah/map.cpp b/havilah/map.cpp index 540dcbde9..838cc388a 100644 --- a/havilah/map.cpp +++ b/havilah/map.cpp @@ -197,6 +197,11 @@ void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) FinalSetup(pRegionArrays[level]); } +void ARegionList::CreateIslandRingLevel(int level, int xSize, int ySize, char const *name) +{ + throw "CreateIslandRingLevel not implemented for this game ruleset"; +} + void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, char const *name) { @@ -532,6 +537,8 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, Awrite(""); } +void ARegionList::MakeRingLand(ARegionArray *pReg, int minDistance, int maxDistance) { } + void ARegionList::MakeCentralLand(ARegionArray *pRegs) { for (int i = 0; i < pRegs->x; i++) { diff --git a/map_viewer/index.ts b/map_viewer/index.ts index 38c800bc2..3910b64c4 100644 --- a/map_viewer/index.ts +++ b/map_viewer/index.ts @@ -27,6 +27,7 @@ const TERRAIN = { 'tundra': '#99afbc', 'volcano': '#622f22', 'lake': '#6698ff', + 'barren': '#302020', } const CELL_SZ = 5 diff --git a/neworigins/map.cpp b/neworigins/map.cpp index b5b5b55b0..493e4d7e2 100644 --- a/neworigins/map.cpp +++ b/neworigins/map.cpp @@ -1853,6 +1853,31 @@ void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) FinalSetup(pRegionArrays[level]); } +void ARegionList::CreateIslandRingLevel(int level, int xSize, int ySize, char const *name) +{ + MakeRegions(level, xSize, ySize); + pRegionArrays[level]->SetName(name); + pRegionArrays[level]->levelType = ARegionArray::LEVEL_SURFACE; + + MakeRingLand(pRegionArrays[level], 12, 20); + + CleanUpWater(pRegionArrays[level]); + + SetupAnchors(pRegionArrays[level]); + + GrowTerrain(pRegionArrays[level], 0); + + AssignTypes(pRegionArrays[level]); + + PlaceVolcanos(pRegionArrays[level]); + + SeverLandBridges(pRegionArrays[level]); + + if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); + if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); + FinalSetup(pRegionArrays[level]); +} + void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, char const *name) { @@ -2188,6 +2213,83 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, Awrite(""); } +void ARegionList::MakeRingLand(ARegionArray *pRegs, int minDistance, int maxDistance) { + ARegion *center = pRegs->GetRegion(pRegs->x / 2, pRegs->y / 2); + if (!center) { throw "Center region not found"; } + + Awrite("Making land in ring"); + for (int i = 0; i < pRegs->x; i++) { + for (int j = 0; j < pRegs->y; j++) { + ARegion *reg = pRegs->GetRegion(i, j); + if (!reg) continue; + // By default, everything is ocean + reg->type = R_OCEAN; + + // If the regions is between minDistance and maxDistance from the center, 65% chance of being land. + int distance = GetPlanarDistance(center, reg, 1000, -1); + bool awayFromEdge = i >= 4 && i <= pRegs->x - 4 && j >= 4 && j <= pRegs->y - 4; + if (distance >= minDistance && distance <= maxDistance && getrandom(100) < 60) { + reg->type = R_NUM; + } else if (distance >= maxDistance && awayFromEdge && getrandom(100) < 20) { + MakeOneIsland(pRegs, i, j); + } else if (distance < minDistance && distance > 4 && getrandom(100) < 15) { + MakeOneIsland(pRegs, i, j); + } + } + } + + Awrite("Perturbing the coastlines"); + for (int iter = 0; iter < 10; iter++) { + for (int i = 0; i < pRegs->x; i++) { + for (int j = 0; j < pRegs->y; j++) { + ARegion *reg = pRegs->GetRegion(i, j); + if (!reg) continue; + int distance = GetPlanarDistance(center, reg, 1000, -1); + int different = 0; + for (int d = 0; d < NDIRS; d++) { + ARegion *newreg = reg->neighbors[d]; + if (!newreg) continue; + if (newreg->type != reg->type) different++; + } + + if (distance <= minDistance + 2 && distance > 3) { + // inner coastline. High chance of land becoming ocean, low chance of ocean becoming land. + // Chance is proportional to neighbors that are different. + if (getrandom(100) < (different * (reg->type == R_NUM ? 2 : 1))) { + reg->wages = -2; + } + } else if (distance >= maxDistance - 1 && i >= 2 && i <= pRegs->x - 2 && j >= 2 && j <= pRegs->y - 2) { + // outer coastline. Moderate chance of ocean becoming land, lower chance of land becoming ocean. + // Chance is proportional to neighbors that are different. + if (getrandom(100) < (different * (reg->type != R_NUM ? 3 : 2))) { + reg->wages = -2; + } + } + } + } + // Apply the changes + for (int i = 0; i < pRegs->x; i++) { + for (int j = 0; j < pRegs->y; j++) { + ARegion *reg = pRegs->GetRegion(i, j); + if (!reg) continue; + // If the region changed type, swap it to the new type and clear the flag. + if (reg->wages == -2) reg->type = (reg->type == R_OCEAN ? R_NUM : R_OCEAN); + reg->wages = -1; + } + } + } + + Awrite("Adding the barrens"); + center->type = R_BARREN; + for (int d = 0; d < NDIRS; d++) { + ARegion *newreg = center->neighbors[d]; + if (!newreg) continue; + newreg->type = R_BARREN; + } + + Awrite(""); +} + void ARegionList::MakeCentralLand(ARegionArray *pRegs) { for (int i = 0; i < pRegs->x; i++) { diff --git a/neworigins/rules.cpp b/neworigins/rules.cpp index 10b76d3ec..9fff54f41 100644 --- a/neworigins/rules.cpp +++ b/neworigins/rules.cpp @@ -176,15 +176,15 @@ static GameDefs g = { 100, // TOWNS_NOT_ADJACENT 0, // LESS_ARCTIC_TOWNS 55, // OCEAN - 14, // CONTINENT_SIZE + 14, // CONTINENT_SIZE 4, // TERRAIN_GRANULARITY - 1, // LAKES + 5, // LAKES 20, // ARCHIPELAGO 30, // SEVER_LAND_BRIDGES - 6, // SEA_LIMIT + 6, // SEA_LIMIT GameDefs::NO_EFFECT, // LAKE_WAGE_EFFECT 0, // LAKESIDE_IS_COASTAL - 70, // ODD_TERRAIN + 80, // ODD_TERRAIN 1, // IMPROVED_FARSIGHT 1, // GM_REPORT 0, // DECAY diff --git a/neworigins/world.cpp b/neworigins/world.cpp index 205a47864..067f4180c 100644 --- a/neworigins/world.cpp +++ b/neworigins/world.cpp @@ -393,8 +393,8 @@ void Game::CreateWorld() } int generator = -1; - while (generator != 1 && generator != 2) { - Awrite("Selected surface land generator? [Origianl - 1, Parametrical - 2]"); + while (generator < 1 || generator > 3) { + Awrite("Selected surface land generator? [Origianl - 1, Parametrical - 2, Island Ring - 3]"); generator = Agetint(); } @@ -417,16 +417,14 @@ void Game::CreateWorld() } } - regions.CreateLevels(2 + Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + Globals->ABYSS_LEVEL); + regions.CreateLevels(2 + Globals->UNDERWORLD_LEVELS + Globals->UNDERDEEP_LEVELS + Globals->ABYSS_LEVEL); SetupNames(); regions.CreateNexusLevel( 0, nx, ny, "nexus" ); if (generator == 1) { regions.CreateSurfaceLevel( 1, xx, yy, 0 ); - } - else { + } else if (generator == 2) { Map* map = new Map(xx * 2, yy * 2); map->redistribution = 1.5; map->evoparation = 0.75; @@ -434,6 +432,8 @@ void Game::CreateWorld() map->waterPercent = 0.1; regions.CreateNaturalSurfaceLevel(map); + } else if (generator == 3) { + regions.CreateIslandRingLevel(1, xx, yy, 0); } // Create underworld levels diff --git a/standard/map.cpp b/standard/map.cpp index 9a4466cea..c203482c3 100644 --- a/standard/map.cpp +++ b/standard/map.cpp @@ -182,6 +182,11 @@ void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) FinalSetup(pRegionArrays[level]); } +void ARegionList::CreateIslandRingLevel(int level, int xSize, int ySize, char const *name) +{ + throw "CreateIslandRingLevel not implemented for this game ruleset"; +} + void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, char const *name) { @@ -511,6 +516,8 @@ void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, Awrite(""); } +void ARegionList::MakeRingLand(ARegionArray *pReg, int minDistance, int maxDistance) { } + void ARegionList::MakeCentralLand(ARegionArray *pRegs) { for (int i = 0; i < pRegs->x; i++) { diff --git a/unittest/map.cpp b/unittest/map.cpp index 56f92ea58..4b93c92d8 100644 --- a/unittest/map.cpp +++ b/unittest/map.cpp @@ -48,6 +48,7 @@ void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char const } void ARegionList::CreateIslandLevel(int level, int nPlayers, char const *name) { } +void ARegionList::CreateIslandRingLevel(int level, int xSize, int ySize, char const *name) {} void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, char const *name) { MakeRegions(level, xSize, ySize); @@ -111,6 +112,8 @@ void ARegionList::SetupIcosahedralNeighbors(ARegionArray *pRegs) { } void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, int continentSize) { } +void ARegionList::MakeRingLand(ARegionArray *pReg, int minDistance, int maxDistance) { } + void ARegionList::MakeCentralLand(ARegionArray *pRegs) { } void ARegionList::MakeIslands(ARegionArray *pArr, int nPlayers) { }