Skip to content

Commit

Permalink
Import citizen types from the BIC file
Browse files Browse the repository at this point in the history
This allows us to know about things like entertainers, tax collectors, etc.

While here I noticed that one of the tests wasn't actually doing anything, so I fixed the path issue and added an assertion to catch similar issues in the future.

#541
  • Loading branch information
TomWerner committed Feb 12, 2025
1 parent 3de878b commit 6452d61
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 2 deletions.
82 changes: 82 additions & 0 deletions C7/Text/c7-static-map-save.json
Original file line number Diff line number Diff line change
Expand Up @@ -64533,5 +64533,87 @@
"tech-44"
]
}
],
"citizenTypes": [
{
"id": "CitizenType-1",
"isDefaultCitizen": true,
"specialistIndex": 0,
"singularName": "Laborer",
"civilopediaEntry": "CTZN_Laborer",
"pluralName": "Laborers",
"luxuries": 0,
"research": 0,
"taxes": 0,
"corruption": 0,
"construction": 0
},
{
"id": "CitizenType-2",
"isDefaultCitizen": false,
"specialistIndex": 1,
"singularName": "Entertainer",
"civilopediaEntry": "CTZN_Entertainer",
"pluralName": "Entertainers",
"luxuries": 1,
"research": 0,
"taxes": 0,
"corruption": 0,
"construction": 0
},
{
"id": "CitizenType-3",
"isDefaultCitizen": false,
"specialistIndex": 2,
"singularName": "Tax Collector",
"civilopediaEntry": "CTZN_Tax_Collector",
"pluralName": "Tax Collectors",
"luxuries": 0,
"research": 0,
"taxes": 2,
"corruption": 0,
"construction": 0
},
{
"id": "CitizenType-4",
"isDefaultCitizen": false,
"specialistIndex": 3,
"singularName": "Scientist",
"civilopediaEntry": "CTZN_Scientist",
"pluralName": "Scientists",
"luxuries": 0,
"research": 3,
"taxes": 0,
"corruption": 0,
"construction": 0
},
{
"id": "CitizenType-5",
"isDefaultCitizen": false,
"specialistIndex": 4,
"singularName": "Policeman",
"civilopediaEntry": "CTZN_Laborer",
"pluralName": "Policemen",
"prerequisiteTech": "tech-44",
"luxuries": 0,
"research": 0,
"taxes": 0,
"corruption": 1,
"construction": 0
},
{
"id": "CitizenType-6",
"isDefaultCitizen": false,
"specialistIndex": 5,
"singularName": "Civil Engineer",
"civilopediaEntry": "CTZN_Laborer",
"pluralName": "Civil Engineers",
"prerequisiteTech": "tech-58",
"luxuries": 0,
"research": 0,
"taxes": 0,
"corruption": 0,
"construction": 2
}
]
}
45 changes: 45 additions & 0 deletions C7GameData/CitizenType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Runtime.InteropServices;

namespace C7GameData {
public class CitizenType {
public ID Id;

// Should this citizen be the default?
public bool IsDefaultCitizen;

// If !IsDefaultCitizen, the index of this specialist, for looking up in
// popHeads.pcx. 0 is the first non-laborer row.
public int SpecialistIndex;

// Like "Laborer" or "Scientist"
public string SingularName;

public string CivilopediaEntry;

// Like "Laborers" or "Scientists"
public string PluralName;

// If non-null, the tech needed to use this citizen type.
public ID PrerequisiteTech;

// The contribution, in gold per turn, that this citizen makes towards
// luxuries/happiness.
public int Luxuries;

// The contribution, in beakers, that this citizen makes towards teching
public int Research;

// The contribution, in gold per turn, that this citizen makes towards
// the treasury.
public int Taxes;

// TODO: Figure out the details of how corruption is reduced by
// policemen.
public int Corruption;

// The contribution, in shields per turn, that this citizen makes
// towards production.
public int Construction;
}
}
1 change: 1 addition & 0 deletions C7GameData/GameData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class GameData {

public List<ExperienceLevel> experienceLevels = new List<ExperienceLevel>();
public List<Tech> techs = new();
public List<CitizenType> citizenTypes = new();
public string defaultExperienceLevelKey;
public ExperienceLevel defaultExperienceLevel;

Expand Down
30 changes: 30 additions & 0 deletions C7GameData/ImportCiv3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ private void ImportSharedBiqData() {
// save.ScenarioSearchPath = biq?.Game[0].ScenarioSearchFolders;
ImportBarbarianInfo();
ImportTechs();
ImportCitizenTypes();
}

public static SaveGame ImportSav(string savePath, string defaultBicPath, Func<string, string> getPediaIconsPath) {
Expand Down Expand Up @@ -766,6 +767,35 @@ private void ImportTechs() {
}
}

private void ImportCitizenTypes() {
BiqData theBiq = biq.Ctzn is null ? defaultBiq : biq;

for (int i = 0; i < theBiq.Ctzn.Length; ++i) {
CTZN c = theBiq.Ctzn[i];

CitizenType ct = new() {
Id = ids.CreateID("CitizenType"),
IsDefaultCitizen = c.DefaultCitizen == 1,
SingularName = c.SingularName,
CivilopediaEntry = c.CivilopediaEntry,
PluralName = c.PluralName,
Luxuries = c.Luxuries,
Research = c.Research,
Taxes = c.Taxes,
Corruption = c.Corruption,
Construction = c.Construction
};
if (!ct.IsDefaultCitizen) {
ct.SpecialistIndex = i - 1;
}
if (c.Prerequisite > -1) {
ct.PrerequisiteTech = save.Techs[c.Prerequisite].id;
}

save.CitizenTypes.Add(ct);
}
}

private static void SetWorldWrap(SavData civ3Save, SaveGame save) {
if (civ3Save is not null && civ3Save.Wrld.Height > 0 && civ3Save.Wrld.Width > 0) {
save.Map.wrapHorizontally = civ3Save.Wrld.XWrapping;
Expand Down
3 changes: 3 additions & 0 deletions C7GameData/Save/SaveGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public static SaveGame FromGameData(GameData data) {
save.ScenarioSearchPath = data.scenarioSearchPath;
save.DefaultExperienceLevel = data.defaultExperienceLevelKey;
save.Techs = data.techs.ConvertAll(t => t.ToSaveTech());
save.CitizenTypes = data.citizenTypes;
return save;
}

Expand All @@ -94,6 +95,7 @@ public GameData ToGameData() {
unitPrototypes = UnitPrototypes.ToDictionary(up => up.name),
scenarioSearchPath = ScenarioSearchPath,
civilizations = Civilizations,
citizenTypes = CitizenTypes,
ids = new ID.Factory(this),
};
// units and cities are empty
Expand Down Expand Up @@ -198,6 +200,7 @@ public GameData ToGameData() {
public List<StrengthBonus> StrengthBonuses = new List<StrengthBonus>();
public Dictionary<string, int> HealRates = new Dictionary<string, int>();
public List<SaveTech> Techs = new();
public List<CitizenType> CitizenTypes = new();
public string ScenarioSearchPath; // TODO: what is this
public void Save(string path) {
byte[] json = JsonSerializer.SerializeToUtf8Bytes(this, JsonOptions);
Expand Down
13 changes: 11 additions & 2 deletions C7GameDataTests/SaveTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,22 @@ public void SimpleSave() {

[Fact]
public async void LoadSampleSaves() {
// When running the tests via github actions, civ3 isn't installed so we
// can't load the default bic.
//
// See https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables
// for a full list of env vars.
string is_on_github = System.Environment.GetEnvironmentVariable("CI");
if (is_on_github != null) { return; }

string savesPath = getDataPath("saves");
Directory.CreateDirectory(savesPath);

string sampleSavPath = Path.Combine(testDirectory, "data", "12345.SAV");
string sampleSavPath = Path.Combine(savesPath, "12345.SAV");
if (GetMd5FileHash(sampleSavPath) != "d34dd19a76eaebe26d29d73132c2fa60") {
using HttpClient client = new();
byte[] fileData = await client.GetByteArrayAsync("https://drive.usercontent.google.com/download?id=1QlIavkLtPZEIv1kHK9sO0fY2yp3o2si7&confirm=y");
File.WriteAllBytes(Path.Combine(testDirectory, "data", "12345.SAV"), fileData);
File.WriteAllBytes(Path.Combine(savesPath, "12345.SAV"), fileData);
}

IEnumerable<FileInfo> saveFiles = new DirectoryInfo(savesPath).EnumerateFiles("*.SAV");
Expand All @@ -110,6 +118,7 @@ public async void LoadSampleSaves() {
game.Save(Path.Combine(testDirectory, "data", "output", $"gotm_save_{i}.json"));
i++;
}
Assert.True(i > 0);
}

[Fact]
Expand Down

0 comments on commit 6452d61

Please sign in to comment.