Skip to main content
GameDev.net gamedev.net
🔒 Locked

Nation States: Dominion

Started by leffeq65 Dec 10, 2025 at 12:00 PM 12 replies 2.6k views
Original Post
leffeq65
leffeq65

Hello!! I am currently developing a game that i call NationStates.
You will start the game as the Prime Minister of a poor Country, your task is to develop it in the direction you want. However remember that people can oppose you if you do not fulfill at least their basic needs, and you dont want a revolution.

Game description:
NationStates: Dominion is a nation-building simulation that lets players run a developing country using realistic economic, demographic, and infrastructure systems. All “global” commodity prices in the game are based upon real trading data stretching from 1988 until 2025, for example Oil price and Wheat price.
Instead of instant “city-builder magic,” everything takes time: power plants warm up, roads are constructed, populations react, and markets evolve.
The game simulates an entire society — companies, households, energy grids, tax systems, agriculture, and trade — all influencing each other dynamically.
Its modular, JSON-driven architecture enables massive scalability and total moddability.
This is a strategy game with the depth of an economic model and the accessibility of a political simulator.

The country is huge > 1M Square kilometers (>386000 sq.Miles) is divided into 8299 (polygon based) different Cities/Villages and Unihabited areas, by clicking a region in the map you acess the data for that City/Village. Where its possible to alter or build different things, however Cities, Villages and Counties can be set to operate with the City AI.

My questions to the Forum is the following; “Is this a Game You could consider to play?"
The Game is Currently being developed in Visual Studio C#.

Part of the Map (rendered):

Map polygons without rendered Map:

City Info:

Control Hydro Power Plants:

Choose Your Ministers:

Tom Sloper
Tom Sloper

This thread was off-topic in the Writing forum. Moved to Your Announcements. @leffeq65, please familiarize yourself with the topics of our various forums and before posting again, review our community guidelines. Good luck with your project.

-- Tom Sloper    --      sloperama.com
leffeq65
leffeq65

@Tom Sloper Ok! I tried to understand, but probably was lazy to read properly. Sorry for that 🙂

Malak
Malak

Hey! I'm Malak Noorullah Khan, a developer with Node.js/Flutter/Python experience. Your NationStates game looks amazing - it reminds me of Vic3's depth combined with Call of War's strategy. Would love to contribute if you're open to collaboration. I can help with economic systems, City AI, or multiplayer infrastructure. Let me know!

leffeq65
leffeq65

Hello Malak,

I am open for collaboration! Developing this Simulation is not a simple task for one person. My name is Leif and i am from Sweden, this game idea has been growing in my head for many years. The version i am currently working on i have been developing for approximately over two years (off and on). The base idea was to have dynamic businesses, that really works from demand. People needs milk, gives needs for Farms and Dairy production + distribution and sales in stores. I have needed to implement “Sub articles”, “Import articles” and “Farm” + “Production” articles. To limit the complexity each company produces “One” product, except farms.

Its funny you propose to work with City AI, since I am currently working exactly with the AI for the cities, its responsibilites are decided by the player. But from start the responsibilites are limited to basic functions, like water management and garbage. Please take a look at the City Class and the CityResponsibility Class (which is partly written).

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
public class CityResponsibility
{
   public int CityID { get; set; }   // Link back to the City
   public bool CityAutonomy { get; set; }
   public List<Responsibility> Duties { get; set; }
   public string DevelopmentFocus { get; set; }
   public int BudgetPriority { get; set; }
   public double CorruptionLevel { get; set; }
   public List<FeesAndCharges> FeesCharges { get; set; } = new List<FeesAndCharges>();
   public int EmployedTotal { get; set; }
   public int UnemployedInCity { get; set; }
   public int PensionersInCity { get; set; }
   public void City_AI(int CityID, Responsibility Duty)
   {
       var r = Form1.AllCityResponsibility(CityID);
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Taxes))
           AI_Taxes(CityID);
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Preschool))
           AI_Preschool(CityID);
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Watersupply))
           AI_Water();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Garbage))
           AI_Garbage();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Rescue))
           AI_Rescue();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Sports))
           AI_Sports();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Elementary))
           AI_Elementary();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.HighSchool))
           AI_HighSchool();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Libraries))
           AI_Library();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.ElderlyCare))
           AI_ElderlyCare(CityID);
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Fees))
           AI_Fees();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.BuildingPermits))
           AI_Permits();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.Culture))
           AI_Culture();
       if (r.CityAutonomy && r.Duties.Contains(Responsibility.SocialService))
           AI_Social();
   }
   private void AI_Preschool(int cityID)
   {
       var cit = Form1.allCities.FirstOrDefault(x => x.CityID == cityID);
       if (cit == null)
           return;
       int children = 0;
       int employees = 0;
       // Ages 1–6 (index range depends on your population model)
       for (var age = 1; age <= 6; age++)
       {
           var boys = cit.Population.Males(age);
           var girls = cit.Population.Females(age);
           var total = boys + girls;
           children += total;
           if (age <= 3)
               employees += total / (double)10;    // infants require more staff
           else
               employees += total / (double)20;// older kids require fewer
       }
       // Calculate required preschools (30 kids per school)
       cit.PreSchools = Math.Ceiling(children / (double)30);
       // Energy Need
       // This is calcucated under EnergyUsageALL once per Game minute
       // Calculate salary & taxes
       EmployeeCostCalculations(cityID, employees);
   }
   private void AI_Taxes(int CityID)
   {
       // This AI part is only used twice a Year
       // First weekend day in April & First weekend day in October
       // Checks Expenses vs Tax income and subsideries
       int check = GetHolidays(Form1.day, Form1.MonthCounter);
       var Cit = Form1.allCities.FirstOrDefault(x => x.CityID == CityID);
       int CheckDay = Form1.weekDayCounter;
       CheckDay = Form1.day;
       CheckDay = Form1.MonthCounter;
       if (Form1.MonthCounter == 4 && Form1.day == 1)
       {
           double Subsideries, TaxIncome, Cash, TotalIncome;
           int Population;
           Cash = Cit.Cash;
           Population = Cit.Population.CityPopulation;
           Subsideries = Population * Form1.StateSubsideriesCities;
           PopulationCalcs(CityID);
           TaxIncome = (PensionersInCity * Form1.Pensions + EmployedTotal * Form1.AverageStateSalary + UnemployedInCity * Form1.UnemploymentMoney) * 12 * Cit.CommunityTax;
           TotalIncome = TaxIncome + Subsideries;
           // Weigh against salaries
           double SalaryCost = Cit.CityAdmin * Form1.AverageStateSalary * (1 + Form1.SocialTax);
           double Result = TotalIncome - SalaryCost;
           // Change Taxes Up or Down
           switch (Result)
           {
               case object _ when Result < 0:
                   {
                       Cit.CommunityTax += 0.005; // +0.5%
                       break;
                   }
               case object _ when Result > 0 < 1000000:
                   {
                       break;
                   }
               case object _ when Result > 1000000:
                   {
                       Cit.CommunityTax -= 0.0025; // -0.25%
                       break;
                   }
           }
       }
       if (Form1.MonthCounter == 10 && Form1.day == 1)
       {
                      case object _ when Result < 0:
                   {
                       Cit.CommunityTax += 0.005; // +0.5%
                       break;
                   }
               case object _ when Result > 0 < 1000000:
                   {
                       break;
                   }
               case object _ when Result > 1000000:
                   {
                       Cit.CommunityTax -= 0.0025; // -0.25%
                       break;
                   }
       }
   }
   private void PopulationCalcs(int CityID)
   {
       var c = Form1.allCities.FirstOrDefault(x => x.CityID == CityID);
       int Pop; // = Form1.CityNames(p, 2)
       int Children;
       int SchoolChild, HighShool, Old, University, NewBorn, WorkForce;
       int ir;
       for (ir = 0; ir <= 110; ir++)
       {
           if (ir <= 6)
               Children += c.Population.Males(ir) + c.Population.Females(ir);
           if (ir >= 7 & ir <= 15)
               SchoolChild += c.Population.Males(ir) + c.Population.Females(ir);
           if (ir >= 16 & ir <= 18)
               HighShool += c.Population.Males(ir) + c.Population.Females(ir);
           if (ir >= 19 & ir <= 22)
               University += c.Population.Males(ir) + c.Population.Females(ir);
           if (ir >= 65)
               Old += c.Population.Males(ir) + c.Population.Females(ir);
           if (ir == 0)
               NewBorn += c.Population.Males(ir) + c.Population.Females(ir);
           Pop += c.Population.Males(ir) + c.Population.Females(ir);
       }
       Community_info.TextBox1.Text = Children;
       Community_info.TextBox3.Text = SchoolChild;
       Community_info.TextBox2.Text = Old;
       Community_info.TextBox4.Text = HighShool;
       Community_info.TextBox5.Text = University;
       WorkForce = Pop - Children - SchoolChild - Old - HighShool - University - NewBorn;
       Community_info.TextBox26.Text = WorkForce.ToString("N0");
       int Employed;
       foreach (var comp in Form1.OurCompanies)
       {
           if (comp.Location == c.CityID)
           {
               // Real quantity of employees
               int realQtyEMP, QtyWorkHours, QtyEmployees;
               if (comp.IsOperational == 2)
               {
                   QtyEmployees = comp.QtyEmployees;
                   if (comp.WorkWeek == "MF")
                   {
                       QtyWorkHours = comp.EndHour - comp.StartHour;
                       realQtyEMP = Conversion.Int(QtyWorkHours * QtyEmployees / (double)8) + Conversion.Int(QtyEmployees * 0.1);
                   }
                   if (comp.WorkWeek == "ML")
                   {
                       QtyWorkHours = comp.EndHour - comp.StartHour;
                       realQtyEMP = Conversion.Int(QtyWorkHours * QtyEmployees * 1.167 / 8) + Conversion.Int(QtyEmployees * 0.1);
                   }
                   if (comp.WorkWeek == "MS" | comp.WorkWeek == "CF")
                   {
                       QtyWorkHours = comp.EndHour - comp.StartHour;
                       realQtyEMP = Conversion.Int(QtyWorkHours * QtyEmployees * 1.4 / 8) + Conversion.Int(QtyEmployees * 0.1);
                   }
                   Employed += realQtyEMP;
               }
           }
       }
       Employed += c.QtyHomeFarms * Form1.LocalFarm.WorkersPerFarm;
       Employed += c.CityAdmin;
       Employed += c.Schools * 50;				//Fixed numbers will be dynamic
       Employed += c.Police * 40;
       Employed += c.DayCare * 10;
       Employed += c.Firebrigade * 15;
       Employed += c.Highschool * 110;
       Employed += c.University * 350;
       Employed += c.Hospitals * 750;
       Employed += c.HealthCareCenter * 20;
       Employed += c.StateDepsEmployees;
       Employed += c.Others;
       Employed += c.Military;

       int Unemployed = WorkForce - Employed;
       EmployedTotal = Employed;
       UnemployedInCity = Unemployed;
       PensionersInCity = Old;
   }
   private void AI_Water()
   {
   }
   private void AI_Garbage()
   {
   }
   private void AI_Culture()
   {
   }
   private void AI_Library()
   {
   }
   private void AI_Rescue()
   {
   }
   private void AI_Fees()
   {
   }
   private void AI_ElderlyCare(int CityID)
   {
       var cit = Form1.allCities.FirstOrDefault(x => x.CityID == CityID);
       int QtyElderly;
       int p;
       for (p = 65; p <= 110; p++)
       {
           QtyElderly += cit.Population.Males(p);
           QtyElderly += cit.Population.Females(p);
       }
       int QtyOccupants = QtyElderly * 0.075;
       // How many % may need help?
       // How do they need help? At home? Or living in a home for elderly average EU is (8.4% Men, 11.7 % Women)
       // Fees for staying?
       // Food Cost?
       // Personnel {3 per 12?}
       int Personnel = QtyOccupants * 0.075 * 3 / 12;
       EmployeeCostCalculations(CityID, Personnel);
       // Fees
       double FeeAmount;
       foreach (var FeeItem in FeesCharges)
       {
           if (FeeItem.Type == FeeNames.NursingHome)
               FeeAmount = FeeItem.Fee;
       }
       cit.Cash += QtyOccupants * FeeAmount;
   }
   private void AI_Social()
   {
   }
   private void AI_Elementary()
   {
   }
   private void AI_Permits()
   {
   }
   private void AI_Sports()
   {
   }
   private void AI_HighSchool()
   {
   }
   private void EmployeeCostCalculations(int cityID, int qtyEmployees)
   {
       Form1.City cit = null/* TODO Change to default(_) if this is not a reference type */;
       if (!Form1.CityDict.TryGetValue(cityID, cit))
           return;
       Counties cnt = null/* TODO Change to default(_) if this is not a reference type */;
       if (!Form1.CountyDict.TryGetValue(cit.County, cnt))
           return;
       var salaries = qtyEmployees * Form1.AverageStateSalary;
       var salaryCost = salaries * (1 + Form1.SocialTax);
       var socialTaxes = salaries * Form1.SocialTax;
       var incomeTax = salaries * Form1.IncomeTax;
       var localTax = salaries * cit.CommunityTax;
       var countyTax = salaries * cnt.CountyTax;
       var netPaid = salaries - incomeTax - localTax - countyTax;
       // --- State taxes ---
       Form1.SocialTaxCollected += socialTaxes;
       Form1.IncomeTaxCollected += incomeTax;
       // --- City taxes ---
       cit.TaxIncome += localTax;
       cit.Cash += localTax;
       cit.Cash -= salaryCost;
       // --- County taxes ---
       cnt.Cash += countyTax;
       // --- Worker net salary ---
       Form1.WorkingPeopleMoney += netPaid;
   }
}
public enum FeeNames
{
   Water,
   Garbage,
   ChildCare,
   NursingHome
}
public enum OccuranceType
{
   Hourly,
   Daily,
   Weekly,
   Monthly,
   Yearly
}
public class FeesAndCharges
{
   public string Name { get; set; }
   public FeeNames Type { get; set; }
   public double Fee { get; set; }
   public OccuranceType Occurance { get; set; }
}
public enum Responsibility
{
   Preschool,
   Taxes,
   Fees,
   Elementary,
   HighSchool,
   Watersupply,
   Garbage,
   Rescue,
   Culture,
   ElderlyCare,
   SocialService,
   Libraries,
   Sports,
   BuildingPermits
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;

public class City
{
    public string Name;
    public int CityID;
    public float CityArea = 0.0F;
    public List<string> Resources = new List<string>();
    public CityPopulation Population = new CityPopulation();
    public List<PointF> PolygonPoints = new List<PointF>();
    public List<int> Roads = new List<int>();
    public bool Inhabited;
    public bool HasRiver;
    public bool HasHub;
    public bool HasPowerplant;
    public int Others;
    public int StateDepsEmployees;
    public int Military;
    public string Terrain;
    public List<int> Neighbours = new List<int>();
    public bool Electricity;
    public int CityAdmin;
    public float TaxIncome;
    public float CommunityTax;
    public float Cash;
    public float Invested;
    public float AdminCost;
    public float OtherCosts;
    public float EnergyCost;
    public bool ConnectedToGrid;
    public int GrowingZone;
    public float LocalPowerNeed;
    public float LocalProductionMW;
    public float NetPower;

    public int QtyHouses;             // Actual quantity houses
    public int HouseNeed;             // If there is need for housing
    public decimal HousePart;         // Need increasement part
    public decimal PartHouse;         // Destroyed houses part
    public decimal PartConn;		  //
 Part of house

    public float CityCash;
    public int ConnectedHouses;
    public int ApartmentBuildings;
    public int Hospitals;
    public int HealthCareCenter;
    public int Police;
    public int QtyStreetLights;
    public int Firebrigade;
    public int PreSchools;
    public int Schools;
    public string SoilType; 			// SoilQuality for agriculture
    public int Highschool;
    public int DayCare;
    public int StreetLamps;
    public float SupplierPower;
    public int ElderlyCare;
    public int QtyHomeFarms;
    public int Sewage;
    public int Water;
    public int Garbage;
    public int University;
    public string County;
    public PointF CityCenter;
    public CityMonthlyStats MonthlyStats = new CityMonthlyStats();
    public bool Prospected { get; set; } = false;
    public int WorkOpportunity = 0;
}
leffeq65
leffeq65

@Malak Hello there,

I think i posted everything in the Offical Post about the game, please check about the City Class there, and yes i am interested in co-operation.

You can also check out the Homepage (not ready yet) for the game development.
www.nationstates.se

Regards/Leif

Malak
Malak

@leffeq65 ok man I have sent you message please check it out on your site

Malak
Malak

ok

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.