CleverRaven / CleverRaven/Cataclysm-DDA

Placing long-distance points of interest: Moving towards a vaguely defined "official" map.

Open
#85,448 6 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

(P3 - Medium) [C++] <Suggestion / Discussion> Map / Mapgen
Dominant language
C++
Stars
13.2k
Forks
4.6k
Avg merge
2d 1h
Merged PRs (30d)
205

Description

Is your feature request related to a problem? Please describe.

See #70056. For some time, we've lacked the ability to point in specific directions and say "that thing is going to be there". This leads to a lot of persistent bugs, for example, finding a mission target often fails if we're looking for a specific overmap special like Hub01 and it's too far away. Eventually as outlined in #70056, we want some sort of procedurally generated grand-scale map that lets us reliably predict the approximate relationships of different things. We have a very tiny version of that now, in that we can predict where the ocean will be, which is where the older issue stems.

Over the last few years of discussion and thought, the radial map design of #70056 is probably not the most manageable way to go about this. There are a few different options, but they're not important for today. For now, let's discuss something that should be quite straightforward to implement with all the features we have now: setting predictable random locations for a few faction bases.

Solution you would like.

First Pass: The Three Big Factions

I suggest that for our very first foray into a persistent "overovermap" as Kevin calls it and as we MUST NOT call it in the long term, we should take the three most important faction bases, and make assertions about where they live relative to each other.

Image Here's our overmap. 0,0 is roughly where the player is expected to start.

The shaded areas represent three different places where our three POIs can spawn

  • POI: Refugee Center, Red area, from X=(-4 to 4), Y=(-4 to 4), excluding X=(-2 to 2) and Y=(-2 to 2)
  • POI: Exodii Base, Blue area, from X=(0 to 10), Y=(6 to 12)
  • POI: Hub01, Green area, from X=(0 to -10), Y=(-6 to -12)

Early in world generation,we are going to randomly select a single overmap within the allowed range, and save it. That is now permanent. We get something like this: (original shaded areas preserved for comparison but not relevant anymore)
Image

  • the Refugee Center is located at -3,3
  • The exodii base si located at 7,9
  • Hub01 is located at -7,-7
    That's the overmap in which we will find those POIs.

Algorithm:

  1. Look at the allowed OMs where we can place POI, use RNG to select which overmap in which to place it. (NOTE: it is better if the random number generator here is deterministic, so that we can predict outcomes based on a random seed, but not really important for a first implementation, I'll leave that up to the coder)
  2. Check the lake/ocean threshold numbers for the selected OM, and the lake/ocean noise map for the OM. Make sure this overmap is no more than 50% lake or ocean. if this is not true, reroll the POI location. if we reroll 5+ times and cannot find a not-wet POI location, throw an error and abort mapgen. (eventually, the allowable amount of lake/ocean could be set in the POI json definition, and a coder could implement this immediately if they want, but it could also be hard coded on a first pass).

We need to make a few changes.

  1. we need a JSON definition for an overmap POI which tells us the allowable coordinates for the POI as above, and the name of the POI so that we can call it later. This POI definition should also allow us to specify a region_map_settings entry for the POI overmap.
    • (Note: Eventually, we'll want more detail stored in this JSON object).
    • I will try to mock up this JSON object later.
  2. for these POIs, the chance of their map special spawning anywhere besides the overmap specified is now zero, and they have a 100% chance to spawn in the specified overmap. If they do not spawn in the specified overmap we should throw a major error and cancel worldgen.
    • Practically speaking, I think the easiest way to do this is to blacklist the POI specials in regional_map_settings, and remove that blacklist in the POI's specific regional_map_settings.
    • We will probably also need to add a new flag for POI specials in their overmap_special definition, which causes them to be placed very very early in mapgen, so that other specials don't take their place.
  3. we need to save those locations and make them accessible to EOC JSON and mission JSON - specifically, when we want to assign a mission target, we should be able to tell it to look at the cached overmap location of a specific POI, by name, as defined in the json from 1.
    • This should save us a ton of waiting when we want to find the refugee center or hub01 or whatever for a mission, and also basically guarantees that we can find it.
  4. Change our CI tests that check for all specials spawning within a specific overmap radius to now exclude POI_specials from that check, but instead, it loads the expected OM for the POI_specials and makes sure the specials spawn there. If an OM special has the POI_special flag and doesn't have an associated POI to spawn in, that should be logged as a failure I would think.

For our first pass, that's it. We can test this out, and see if it works.

Error trapping for existing worlds

Over time this is probably going to be a nightmare but I think, for now, we might be OK?

  1. For each existing POI_special, check to see if it has already been placed. If so, identify its OM and record that as the location of the POI.
  2. If a given POI_special has not been placed, check to see if there is a valid OM within its desired area that has not been generated in which we can place it. if so, proceed with the process outlineda bove.
  3. If there is no valid OM within the desired area to place the POI, start scanning the adjacent OMs outside that radius, and continue scanning for either 100 OM or until we find a valid placement.
  4. If we STILL cannot find a possible OM, choose an OM in the default location (make sure that location isn't the same as another POI though!) and throw an error prompt something like "Could not find a place to spawn mandatory POI 'Hub01'. Force placement and overwrite previous contents of that overmap?" If player selects "n", follow up with "Note: 'Hub01' will not spawn in this world. You may manually force spawn in debug settings."
    • Forcing the overmap in this case will cause it to completely regenerate with the appropriate POI settings.
  5. Add a debug menu option to designate an overmap coordinate for a POI location. We'll need that anyway.
Second Pass: Special regional map settings

Once we have the ability to define regional map settings for a POI, we need someone to go through and define the region map settings for our three POIs.

  • This step could be mostly JSON, but if I'm not mistaken in how regional_map_settings work, we might need to expose the cities attribute to have additional options. I don't want to get too deep here, because I think we're going to be rewriting city generation pretty soon. What we might want today is just to add the option "tiny" to the settings: if "cities" are "tiny" then when we determine city size, we override any other map settings and place only size 1 cities - little tiny gas station stops. This setting does not change local city spacing or anything.
  • I would suggest that for all three of these, or at least the ref center and hub, the OM they spawn in should have city size set to Tiny. The Refugee Center and hub01 should also have pretty limited whitelists of what specials we allow to spawn, mostly things like cabins and gas stations, to ensure that they're built far away from major commercial developments, but also far away from farmland (in the case of the refugee center, at least), and definitely away from dangerous hostile centers like mi-go and fungaloids.
  • The exodii might be kept more random, because it's more appropriate for them to plop down in the middle of a city. However, we still might want to blacklist the worst stuff.
Third pass: POIs that are contingent on other POIs

When we're satisfied with how the above is working and we've shaken out the problems I didn't foresee, I think the next step is to add POIs whose location is contingent on where we decided to place another POI. For this, I want to place Tacoma ranch (and maybe some others, I'm trying to think what)

  • Tacoma Ranch needs to spawn close to the Free Merchants, but not so close that it's silly for you to act as a go-between.
  • other?
  1. Add a new attribute to our POI definition JSON: proximity. Example usage:
"proximity": [ { "POI_merchants": { "x": [ 0,4 ], "y": [-3, 3], "min_distance": 2 } } ]
  1. Don't attempt to place this POI until the POI(s) listed in Proximity have been placed.
  2. Produce an error if we have circular proximity, eg. if POI_tacoma lists POI_merchants and POI_merchants lists POI_tacoma.
  3. When placing the location of this POI, we choose an OM offset from POI_merchants by a random number from 0,4 in the X axis, and a random number from -3 to 3 on the Y axis, with a minimum straight-line distance from the OM containing the free merchants of 2. Note that all three of these fields are optional, although we need at least one of them. For example, we could add another line:
"proximity": [
  { "POI_merchants": { "x": [ 0,4 ], "y": [-3, 3], "min_distance": 2 } },
  { "POI_hub01": { "min_distance": 2 } },
  { "POI_exodiibase": { "min_distance": 2 } }
]
  • This just ensures our new POI is at least 2 OM away from hub01 and the exodii, these particular criteria don't care anything else about where it is placed.
  1. If we cannot place a POI according to these criteria, eg. we used more than one POI as a requirement and made our restrictions too stringent, produce an error and exit worldgen.
Image

Illustration: This is how we place Tacoma (purple box) in our previous map example. That purple square will migrate wherever the red dot (the free merchants) migrate to. Since the blue and green dots (exodii and hub01) can also be in very different places, in this example Tacoma could easily wind up very close to them, hence the example above where we ensure it doesn't end up right beside them.

Describe alternatives you have considered.

This is an ongoing issue post and will get more steps added in.

In my original issue post, which remains mostly the 'big picture' this is pointed towards, I described regions as a radial map reaching out from 0,0. We could still do that, and there are some ways it makes things easier, like having smooth biome transitions, but I think overall what we're building to here will be easier to understand for content addition.

Additional context

This is going to be so cool, and I think it's now not that hard to do with the code for dimensions and highways.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing overmap generation, overmap_special, regional_map_settings, EOC JSON, mission JSON, and CI special-radius checks mentioned in the issue. First define and implement a scoped first pass for persistent faction POI locations; done means valid placement, saved locations accessible to missions, and CI coverage for expected POI overmaps.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, json
Domain
game-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
18/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.