Skip to content

Conversation

@Emandac
Copy link
Contributor

@Emandac Emandac commented Aug 1, 2025

Updated <in [tileFilter] tiles> so that the player/ai can settle on water/mountain tiles.

One where city couldn't spawn naval unit.
The other when naval unit spawned they could get pushed to a costal tile.
@Emandac Emandac changed the title Fix 2 bugs with <in [tileFilter] tiles> for Water tiles Fix 3 bugs with <in [tileFilter] tiles> for Water tiles Aug 3, 2025
@yairm210
Copy link
Owner

Did you find out what was causing the crashes?

@Emandac
Copy link
Contributor Author

Emandac commented Aug 10, 2025

Yes. The crash was cause by not checking if the settler had an unique conditional before adding addedDistanceBeweenContinents to minimalCityDistanceOnDifferentContinents.

@yairm210
Copy link
Owner

I see
So we need to unify both automation and this function to use the same calculation
That's a prerequisite for any changes

@Emandac
Copy link
Contributor Author

Emandac commented Aug 14, 2025

I see So we need to unify both automation and this function to use the same calculation That's a prerequisite for any changes

How should I go about doing this ?

@yairm210
Copy link
Owner

Find the code in settler automation that determines locations we can settle
find the code in unit action that determines locations we can settle
Ensure that they both use the same function

@Emandac Emandac marked this pull request as draft August 17, 2025 00:25
@Emandac Emandac marked this pull request as ready for review August 26, 2025 00:01
@Emandac Emandac marked this pull request as draft August 29, 2025 13:30
@Emandac Emandac marked this pull request as ready for review September 1, 2025 16:43
@Emandac Emandac marked this pull request as draft September 2, 2025 20:05
@Emandac Emandac marked this pull request as ready for review September 7, 2025 14:34
@Emandac
Copy link
Contributor Author

Emandac commented Oct 23, 2025

Do I need to change anything else to get this PR merged ?

val uniqueModifier = unique.getModifiers(UniqueType.ConditionalInTiles).firstOrNull()
val modConstants = civ.gameInfo.ruleset.modOptions.constants
if (!tile.isLand || tile.isImpassible()) return false
if (!unique.hasModifier(UniqueType.ConditionalInTiles) && (!tile.isLand || tile.isImpassible())) return false
Copy link
Collaborator

@RobLoach RobLoach Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be checking the param of ConditionalInTiles here, there than down below with canSettleInTileWithUnique?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (unique.hasModifier(UniqueType.ConditionalInTiles)) {
  // TODO: Check the condition of params[0]
}
else if (!tile.isLand || tile.isImpassible())) {
  return false
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition, since the boolean getOwner() checks following are less-expensive, may be best to put that above this one.

if (tile.getOwner() != null && tile.getOwner() != civ) return false

if (unique.hasModifier(UniqueType.ConditionalInTiles)) {
canSettleInTileWithUnique = !unique.getModifiers(UniqueType.ConditionalInTiles).none{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

none { - interestingly, https://kotlinlang.org/docs/coding-conventions.html#horizontal-whitespace shows the rule for lambdas, but not other blocks or fun/if/for... bodies...

@SomeTroglodyte
Copy link
Collaborator

Just came across...

if (tile.isCityCenter() && terrain.type != TerrainType.Land) return null

(OneTimeChangeTerrain) ... might conflict.

Sounds like some

    @delegate:Transient
    val isRulesetAllowsSettlingWater by lazy {
        ruleset.units.values.asSequence()
            .flatMap { unit ->
                unit.uniqueObjects.asSequence()
                    .filter { it.type == UniqueType.FoundCity || it.type == UniqueType.FoundPuppetCity  }
                    .flatMap { unique -> unique.modifiers }
            }
            .filter { it.type == UniqueType.ConditionalInTiles }
            .map { it.params[0] }
            .any {
                it == "Water" ||
                ruleset.terrains[it]?.type == TerrainType.Water
            }
    }

might be needed in GameInfo for use in such "land-locked" code. Though interestingly, I can't find more with global searches - except edge cases such as - retreat from land to neighboring sea-city will be forbidden, or StartNormalizer.

@Emandac
Copy link
Contributor Author

Emandac commented Oct 29, 2025

Just came across...

if (tile.isCityCenter() && terrain.type != TerrainType.Land) return null

(OneTimeChangeTerrain) ... might conflict.

Sounds like some

    @delegate:Transient
    val isRulesetAllowsSettlingWater by lazy {
        ruleset.units.values.asSequence()
            .flatMap { unit ->
                unit.uniqueObjects.asSequence()
                    .filter { it.type == UniqueType.FoundCity || it.type == UniqueType.FoundPuppetCity  }
                    .flatMap { unique -> unique.modifiers }
            }
            .filter { it.type == UniqueType.ConditionalInTiles }
            .map { it.params[0] }
            .any {
                it == "Water" ||
                ruleset.terrains[it]?.type == TerrainType.Water
            }
    }

might be needed in GameInfo for use in such "land-locked" code. Though interestingly, I can't find more with global searches - except edge cases such as - retreat from land to neighboring sea-city will be forbidden, or StartNormalizer.

Should I put this into it's own PR or in this one ?

@Emandac
Copy link
Contributor Author

Emandac commented Oct 29, 2025

So like this if (tile.isCityCenter() && !tile.tileMap.gameInfo.isRulesetAllowsSettlingWater) return null ?

@Emandac
Copy link
Contributor Author

Emandac commented Oct 29, 2025

Done

val unique = foundUniques.firstOrNull()!!
var canSettleInTileWithUnique = false

val uniqueModifier = unique.getModifiers(UniqueType.ConditionalInTiles).firstOrNull()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I haven't been following this closely, it looks like it checks the first conditional in tiles. I guess this assumes you wouldn't be adding multiple of these on one line.

Copy link
Contributor Author

@Emandac Emandac Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested something like this: Founds a new city <in [Coast] tiles> <in [Atoll] tiles> and it did work.

You can still add more conditional in tiles, but the first one must be the one the player/ai must settle on.

private fun canSettleTile(tile: Tile, unit: MapUnit, nearbyCities: Sequence<City>): Boolean {
val civ = unit.civ
val foundUniques = unit.getMatchingUniques(UniqueType.FoundCity) + unit.getMatchingUniques(UniqueType.FoundPuppetCity)
val unique = foundUniques.firstOrNull()!!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also just grabs the first one it finds. What if you have multiple of them, and a subsequent one applies, while the first doesn't?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I when I added puppet city unique, I made so you can't have both at the same time.

@Emandac
Copy link
Contributor Author

Emandac commented Nov 2, 2025

Hmm, I never thought about that 😅

@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions
Copy link

Conflicts have been resolved.

@Emandac Emandac closed this Nov 18, 2025
@Emandac
Copy link
Contributor Author

Emandac commented Nov 18, 2025

I will be unable to continue working on the PR

@Emandac Emandac reopened this Dec 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants