World Project - Niilo007/RimWorld-NQoL GitHub Wiki

World Project

Related:



🤝 Faction Relations System

---
title: Capture Relation Effects
---
stateDiagram-v2
  [*] --> SettlementCaptured
  SettlementCaptured --> [*] : Is Our Settlement
  SettlementCaptured --> DecreaseRelationWithAttacker_1 : Settlement Of Ally
  SettlementCaptured --> DecreaseRelationWithAttacker_1 : Settlement Of Neutral
  SettlementCaptured --> IncreaseRelationWithAttacker_1 : Settlement Of Enemy
  DecreaseRelationWithAttacker_1 --> SettlementIdeo 
  SettlementIdeo --> DecreaseRelationWithAttacker_2 : Same As Our Ideo
  SettlementIdeo --> DecreaseRelationWithAttacker_2 : Our Ideo Is Minor Ideo
  DecreaseRelationWithAttacker_2 --> SettlementCulture 
  IncreaseRelationWithAttacker_1 --> SettlementIdeo 
  SettlementIdeo --> IncreaseRelationWithAttacker_2 : Incompatible With Ours
  IncreaseRelationWithAttacker_2 --> SettlementCulture 
  SettlementIdeo --> SettlementCulture : null
  SettlementIdeo --> AttackerIdeo : Different From Ours
  AttackerIdeo --> IncreaseRelationWithAttacker_3 : Same As Ours
  IncreaseRelationWithAttacker_3 --> SettlementCulture 
  SettlementCulture --> AttackerCulture_1 : Same As Ours
  SettlementCulture --> AttackerCulture_2 : Different From Ours
  AttackerCulture_1 --> DecreaseRelationWithAttacker_4  : Different From Ours
  AttackerCulture_1 --> [*] : Same As Ours
  AttackerCulture_2 --> IncreaseRelationWithAttacker_4 : Same As Ours
  AttackerCulture_2 --> [*] : Different From Ours
  IncreaseRelationWithAttacker_4  --> [*]
  DecreaseRelationWithAttacker_4 --> [*]
  SettlementCulture --> [*] : null
Loading
<li Class="NQualityOfLife.World.FactionExtensions" Inherit="False" MayRequireAnyOf="Niilo007.NiilosQoL,Niilo007.NiilosQoL.Dev">
    <allowDiplomacy>true</allowDiplomacy>
</li>
flowchart TB
  LocalExpansionDesire --Increases--> AttackDesire
  ExpansionDesire --Increases--> AttackDesire
  LocalPopDensity --Increases--> AttackDesire
  SettlementCount --Decreases--> TruceDesire
  SettlementCount --Decreases--> ExpansionDesire
  LocalPopDensity --Increases--> LocalExpansionDesire
Loading
 private void UpdateLocalExpansionDesire()
 {
     if (localTilePopulationCapCached <= 0f)
     {
         Utils.Log.Error($"'{nameof(localTilePopulationCapCached)}' was: '{localTilePopulationCapCached.OrNull()}'! - Should have been set by now! Setting it now... - '{this.parent.OrNull()}'");
         localTilePopulationCapCached = GetPopulationCapForTile(myTileId, populationSoftCap, populationHardCap, myTile);
     }
     if (population <= 0f || localTilePopulationCapCached <= 0f) { localExpansionDesireCached = 0f; populationDensityRatio = 0f; return; }
     if (population > localTilePopulationCapCached)
     {
         populationDensityRatio = 1;
     }
     else
     {
         populationDensityRatio = population / localTilePopulationCapCached;
     }
     localExpansionDesireCached = populationDensityRatio;
 }
 /// <summary>Calculate a faction's desire to expand it's settlement count</summary>
 /// <param name="faction">The faction who's expansion desire we are calculating</param>
 /// <param name="strongest">Strongest faction on the map</param>
 /// <param name="weakest">weakest faction on the map</param>
 /// <returns>float in a range of 0f-1f</returns>
 public static Ratio CalculateFactionExpansionDesire(this Faction faction, Faction strongest, Faction weakest)
 {
     if (faction == null || strongest == null || weakest == null)
     {
         Utils.Log.Error_Null(nameof(faction), nameof(strongest), nameof(weakest), $"({faction.AsParam(nameof(faction))}, {strongest.AsParam(nameof(strongest))}, {weakest.AsParam(nameof(weakest))})");
         return 0;
     }

     (int bases, int population, int popCap) = faction.GetSettlementCountAndTotalPopulation();
     float desire = (float)((float)population / popCap);

     if (faction == strongest) { desire *= 0.5f; }
     else if (faction == weakest) { desire *= 1.5f; }

     desire -= bases * 0.01f;

     return desire.ClampRatio();
 }
/// <summary>Calculate a faction's general desire to make peace with other factions</summary>
/// <param name="faction">The faction who's truce desire we are calculating</param>
/// <param name="strongest">Strongest faction on the map</param>
/// <param name="weakest">weakest faction on the map</param>
/// <returns>float in a range of 0f-1f</returns>
public static Ratio CalculateTruceDesire(this Faction faction, Faction strongest, Faction weakest)
{
    if (faction == null || strongest == null || weakest == null)
    {
        Utils.Log.Error_Null(nameof(faction), nameof(strongest), nameof(weakest), $"({faction.AsParam(nameof(faction))}, {strongest.AsParam(nameof(strongest))}, {weakest.AsParam(nameof(weakest))})");
        return 0;
    }

    if (faction.def.GetModExtension<FactionExtensions>()?.allowDiplomacy != true)
    {
        Utils.Log.ErrorOnce($"'{faction.OrNull()}' does not allow diplomacy but: '{nameof(CalculateTruceDesire)}' was called -> will always return '{Ratio.Zero}'!");
        return Ratio.Zero;
    }

    ushort ourSettlementCount = faction.SettlementCount();
    float desire = World.NQoL_WorldComp.AllSettlementsCount / (float)(ourSettlementCount * ourSettlementCount);

    if (faction == weakest) { desire *= 2f; }
    else if (faction == strongest) { desire *= 0.25f; }
    if (faction != strongest && faction.RelationWith(strongest).kind == FactionRelationKind.Hostile) { desire *= 2f; }
    desire *= 0.01f;

    return desire.ClampRatio();
}

☮ Peace Deals

🤝 Truce

Truce can happen if both factions have a desire for a truce and are hostile to each other. A successful truce makes the 2 factions unconditionally neutral to each other.

flowchart TB
  SharedCulture --Increases--> TruceWillingness
  SharedIdeo --Increases--> TruceWillingness
Loading

🏳 Surrender

If a faction is desperate enough for peace, they may surrender to a hostile faction.

---
title: Peace Deal
---
stateDiagram-v2
    [*] --> TryToMakePeaceWithNextFaction
    TryToMakePeaceWithNextFaction --> [*] : Iterated All
    TryToMakePeaceWithNextFaction --> SurrenderOutcomePartialChange
    SurrenderOutcomePartialChange --> PeaceWithFaction  : Accepted
    SurrenderOutcomePartialChange--> SurrenderOutcomePartialConversion : Rejected
    SurrenderOutcomePartialConversion --> PeaceWithFaction  : Accepted
    SurrenderOutcomePartialConversion  --> SurrenderOutcomeMajorChange : Rejected
    SurrenderOutcomeMajorChange --> PeaceWithFaction  : Accepted
    SurrenderOutcomeMajorChange  --> SurrenderOutcomeTotalConversion : Rejected
    SurrenderOutcomeTotalConversion --> TryToMakePeaceWithNextFaction : Rejected
    SurrenderOutcomeTotalConversion --> PeaceWithFaction : Accepted
    PeaceWithFaction --> TryToMakePeaceWithNextFaction
Loading

🧑‍🌾 Population System

📈 Population Growth Logic

public static float GetCurrentPopulationGrowthRatePerDay(float localStaticGrowthRate, float biomePopulationCap, float currentPopulation, Factor localFertility, Ratio populationDensityRatio)
{
    float logisticGrowth = biomePopulationCap * currentPopulation * (1f - populationDensityRatio);
    return localStaticGrowthRate * logisticGrowth * localFertility;
}

🌾 Food Resource System

Plan:

  • Food is produced by Farm files and consumed by the Population. Lack of food causes population stagnation or loss.
  • Foo resources can be transferred with roads.

🌱 Fertility

private Factor UpdateCachedFertility()
{
    localFertilityCached = myTileId.LocalFertility(Session.Instance.World!.grid) * 0.14285f;
    return localFertilityCached;
}
public static Factor LocalFertility(this int tile, WorldGrid? worldGrid = null, int radius = 6)
{
    if (tile < 0) { Utils.Log.Error_InvalidInput_WithReason(nameof(tile), $"({tile.AsParam(nameof(tile))}, {worldGrid.AsParam()})", "has an invalid tile id!"); return Factor.Invalid; }
    else { if (Session.Instance?.World == null || TileCount <= -1 || (worldGrid != null && Session.Instance!.World!.grid != worldGrid)) { Session.NewSession.World = Find.World; } }
    List<int> relevantTiles = Tile_.GetTilesInRadius(tile, radius, out int count, Session.Instance!.World!.grid); //RelevantTiles(tile, radius, out int count); // new List<int>(); //tile.NeighbouringTiles(WorldGrid);
    //int nC = n.Count;
    Factor totalFertility = 0f; // tile.TileFertilityFactor(WorldGrid);
    for (int i = 0; i < count; i++)
    {
        totalFertility += relevantTiles[i].TileFertilityFactor(Session.Instance!.World!.grid);
    }
    return Utils.Math.Clamp(totalFertility, 1f, 999f);
}
public static Factor TileFertilityFactor(this int tile, WorldGrid? worldGrid = null)
{
    if (tile < 0) { Utils.Log.Error_InvalidInput_WithReason(tile.AsParam(nameof(tile)), $"({tile.AsParam(nameof(tile))}, {worldGrid.AsParam(nameof(worldGrid))})", "has an invalid tile id!"); return Factor.Invalid; }
    else { if (Session.Instance?.World == null || TileCount <= -1) { Session.NewSession.World = Find.World; } }
    return Session.Instance!.World!.grid.tiles[tile].TileFertilityFactor(tile);
}

💥 War


🏹 Battle Simulation

bool attackerVictory = DoBattleSim
(
    attackers: population * 0.5f,
    attackerTechLevel: myFaction!.def.techLevel,
    attackerCasualties: out float attackerCasualties,
    battleGoal: out battleGoal,
    defenders: theirComp!.population,
    defenderTechLevel: theirFaction.def.techLevel,
    defenderCasualties: out float defenderCasualties,
    hilliness: battleFieldTile.hilliness,
    attackSuccessChance: out _,
    attackerFaction: myFaction,
    defenderFaction: theirFaction,
    biome: battleFieldTile.biome,
    defenderComp: theirComp
);

🏭🦺 Development System


⛺🌃 Tiles

Tiles can become war torn when the settlement is attacked.

public static bool MakeWarTornAround(this Tile tile, int tileId, WorldGrid? worldGrid = null)
{
}
  • Implemented Tiles:
    • Urban
    • Farm land
  • Planned:
    • Mining tile / site

🌃 Urban Tile

  • Urban tiles increase the population capacity of the settlement.
    • See: NQualityOfLife.World.NQoL_World_Object_Comp.GetPopulationCapForTile()
  • Urban tiles provide defense buffs in battle.
    • See: NQualityOfLife.World.NQoL_World_Object_Comp.DoBattleSim()
  • Urban tiles are less fertile than natural terrain or farm land
    • See: NQualityOfLife.World.Utils_.Tile_.TileFertilityFactor()
<li Class="NQualityOfLife.World.FactionExtensions" Inherit="False" MayRequireAnyOf="Niilo007.NiilosQoL,Niilo007.NiilosQoL.Dev">
    <canDevelop>true</canDevelop>
    <canUrbanize>true</canUrbanize>
</li>

⛺ Farm Land Tile

<li Class="NQualityOfLife.World.FactionExtensions" Inherit="False" MayRequireAnyOf="Niilo007.NiilosQoL,Niilo007.NiilosQoL.Dev">
    <canDevelop>true</canDevelop>
    <canFarm>true</canFarm>
</li>

🚧 Roads

  • Settlements can transfer resources and population to connected settlements.
  • Settlements can build new roads to connect to nearby settlements, and upgrade existing roads.
  • Planned:
    • The tier of the road affects transfer efficiency.
<li Class="NQualityOfLife.World.FactionExtensions" Inherit="False" MayRequireAnyOf="Niilo007.NiilosQoL,Niilo007.NiilosQoL.Dev">
    <canDevelop>true</canDevelop>
    <canBuildRoads>true</canBuildRoads>
</li>

🧭⛺ New Settlements

  • Existing settlements can establish new settlements if they have the resources and population to do so.
<li Class="NQualityOfLife.World.FactionExtensions" Inherit="False" MayRequireAnyOf="Niilo007.NiilosQoL,Niilo007.NiilosQoL.Dev">
    <canDevelop>true</canDevelop>
    <specialFactionModifiers>CanBuildNewSettlements</specialFactionModifiers>
</li>

mindmap
  root((World Project))
    Resource System
      Trade
        Road Building
    Population System
      Population
    War Stuff
      Battle Sim
Loading

flowchart TB
  FoodResource --Consumed By--> Population
  Population --Produces--> RawMaterials 
  RawMaterials --Produced By--> Population 
  RawMaterials --Used To Build--> Roads
  RawMaterials --Used To Build--> UrbanTiles 
  UrbanTiles --Increases--> PopCap
  PopCap --Used To Calculate--> PopDensity
  Population --Used To Calculate--> PopDensity
  PopGrowth --Increased By--> Population 
  PopGrowth --Increased By--> PopCap
  PopGrowth --Decreased By--> PopDensity
  PopDensity --Calculated From--> PopCap
  PopDensity --Calculated From--> Population
  FarmTiles --Produces--> FoodResource
  Population --Consumes--> FoodResource
Loading

⚠️ **GitHub.com Fallback** ⚠️