public Allegiance GetAllegianceFromCode(string code) { // TODO: Consider hashtable Allegiance alleg = Allegiances.Where(a => a.T5Code == code).FirstOrDefault(); return(alleg ?? SecondSurvey.GetStockAllegianceFromCode(code)); }
internal void Validate(ErrorLogger errors, int lineNumber, string line) { if (UWP == "???????-?") { return; } Action <string> Error = (string message) => { errors.Error(message, lineNumber, line); }; Action <bool, string> ErrorIf = (bool test, string message) => { if (test) { Error(message); } }; Action <bool, string> ErrorUnless = (bool test, string message) => { if (!test) { Error(message); } }; Func <int, string, bool> Check = (int value, string hex) => { for (int i = 0; i < hex.Length; ++i) { if (value == SecondSurvey.FromHex(hex[i])) { return(true); } } return(false); }; Func <string, bool, bool> CC = (string code, bool calc) => { if (calc) { ErrorUnless(HasCode(code), $"Missing code: {code}"); } else { ErrorUnless(!HasCode(code), $"Extraneous code: {code}"); } return(calc); }; #if VALIDATE_UWP // UWP ErrorIf(Atmosphere > 15, $"UWP: Atm>F: {Atmosphere}"); ErrorIf(Hydrographics > 10, $"UWP: Hyd>A: {Hydrographics}"); ErrorIf(PopulationExponent > 15, $"UWP: Pop>F: {PopulationExponent}"); ErrorUnless(Util.InRange(Government, PopulationExponent - 5, Math.Max(15, PopulationExponent + 5)), $"UWP: Gov={Government} out of range (Pop={PopulationExponent} + Flux)"); ErrorUnless(Util.InRange(Law, Government - 5, Math.Max(18, Government + 5)), $"UWP: Law={Law} out of range (Gov={Government} + Flux)"); int tlmod = (Starport == 'A' ? 6 : 0) + (Starport == 'B' ? 4 : 0) + (Starport == 'C' ? 2 : 0) + (Starport == 'X' ? -4 : 0) + (Size == 0 || Size == 1 ? 2 : 0) + (Size == 2 || Size == 3 || Size == 4 ? 1 : 0) + (Atmosphere <= 3 ? 1 : 0) + (Atmosphere >= 10 ? 1 : 0) + (Hydrographics == 9 ? 1 : 0) + (Hydrographics == 10 ? 2 : 0) + (Util.InRange(PopulationExponent, 1, 5) ? 1 : 0) + (PopulationExponent == 9 ? 2 : 0) + (PopulationExponent >= 10 ? 4 : 0) + (Government == 0 || Government == 5 ? 1 : 0) + (Government == 13 ? -2 : 0); ErrorUnless(Util.InRange(TechLevel, tlmod + 1, tlmod + 6), $"UWP: TL={TechLevel} out of range (mods={tlmod} + 1D)"); #endif // Planetary bool As = CC("As", Check(Size, "0") /*&& Check(Atmosphere, "0") && Check(Hydrographics, "0")*/); bool De = CC("De", Check(Atmosphere, "23456789") && Check(Hydrographics, "0")); bool Fl = CC("Fl", Check(Atmosphere, "ABC") && Check(Hydrographics, "123456789A")); bool Ga = CC("Ga", Check(Size, "678") && Check(Atmosphere, "568") && Check(Hydrographics, "567")); bool He = CC("He", Check(Size, "3456789A" /* + "BC" */) && Check(Atmosphere, "2479ABC") && Check(Hydrographics, "012")); // TODO: Add BC to T5SS spreadsheet calcs bool Ic = CC("Ic", Check(Atmosphere, "01") && Check(Hydrographics, "123456789A")); bool Oc = CC("Oc", Check(Size, "ABC") && Check(Atmosphere, "3456789") && Check(Hydrographics, "A")); bool Va = CC("Va", Check(Atmosphere, "0")); bool Wa = CC("Wa", Check(Size, "3456789") && Check(Atmosphere, "3456789") && Check(Hydrographics, "A")); // Population bool Di = CC("Di", PopulationExponent == 0 /*&& Government == 0 && Law == 0*/ && TechLevel > 0); bool Ba = CC("Ba", PopulationExponent == 0 /*&& Government == 0 && Law == 0*/ && TechLevel == 0); bool Lo = CC("Lo", Check(PopulationExponent, "123")); bool Ni = CC("Ni", Check(PopulationExponent, "456")); bool Ph = CC("Ph", Check(PopulationExponent, "8")); bool Hi = CC("Hi", Check(PopulationExponent, "9ABCDEF")); // Economic bool Pa = CC("Pa", Check(Atmosphere, "456789") && Check(Hydrographics, "45678") && Check(PopulationExponent, "48")); bool Ag = CC("Ag", Check(Atmosphere, "456789") && Check(Hydrographics, "45678") && Check(PopulationExponent, "567")); bool Na = CC("Na", Check(Atmosphere, "0123") && Check(Hydrographics, "0123") && Check(PopulationExponent, "6789ABCDEF")); bool Pi = CC("Pi", Check(Atmosphere, "012479") && Check(PopulationExponent, "78")); bool In = CC("In", Check(Atmosphere, "012479ABC") && Check(PopulationExponent, "9ABCDEF")); bool Po = CC("Po", Check(Atmosphere, "2345") && Check(Hydrographics, "0123")); bool Pr = CC("Pr", Check(Atmosphere, "68") && Check(PopulationExponent, "59")); bool Ri = CC("Ri", Check(Atmosphere, "68") && Check(PopulationExponent, "678")); // {Ix} int imp = 0; { string ix = Importance.Replace('{', ' ').Replace('}', ' ').Trim(); if ("AB".Contains(Starport)) { ++imp; } if ("DEX".Contains(Starport)) { --imp; } if (TechLevel >= 10) { ++imp; } //if (TechLevel >= 16) ++imp; // TODO: Add to T5SS spreadsheet calcs if (TechLevel <= 8) { --imp; } if (PopulationExponent <= 6) { --imp; } if (PopulationExponent >= 9) { ++imp; } if (Ag) { ++imp; } if (Ri) { ++imp; } if (In) { ++imp; } if (Bases == "NS" || Bases == "NW" || Bases == "W" || Bases == "X" || Bases == "D" || Bases == "RT" || Bases == "CK" || Bases == "KM") { ++imp; } ErrorUnless(Int32.Parse(ix) == imp, $"{{Ix}}={Importance} does not match calculated Importance={imp}"); } // (Ex) { string ex = Economic.Replace('(', ' ').Replace(')', ' ').Trim(); int resources = SecondSurvey.FromHex(ex[0]); int labor = SecondSurvey.FromHex(ex[1]); int infrastructure = SecondSurvey.FromHex(ex[2]); int efficiency = Int32.Parse(ex.Substring(3)); if (TechLevel < 8) { ErrorUnless(Util.InRange(resources, 2, 12), $"(Ex) Resources={resources} out of range for TL<8={TechLevel} (2D)"); } else { ErrorUnless(Util.InRange(resources, 2 + GasGiants + Belts, 12 + GasGiants + Belts), $"(Ex) Resources={resources} out of range for TL8+={TechLevel} (2D + GG={GasGiants} + Belts={Belts})"); } ErrorUnless(labor == Math.Max(0, PopulationExponent - 1), $"(Ex) Labor={labor} does not match Pop={PopulationExponent} - 1"); if (Ba) { ErrorUnless(infrastructure == 0, $"(Ex) Infrastructure={infrastructure} should be 0 if Ba"); } else if (Lo) { ErrorUnless(infrastructure == 1, $"(Ex) Infrastructure={infrastructure} should be 1 if Lo"); } else if (Ni) { ErrorUnless(Util.InRange(infrastructure, Math.Max(0, imp + 1), Math.Max(0, imp + 6)), $"(Ex) Infrastructure={infrastructure} out of range for Ni (Imp={imp} + 1D)"); } else { ErrorUnless(Util.InRange(infrastructure, Math.Max(0, imp + 2), Math.Max(0, imp + 12)), $"(Ex) Infrastructure={infrastructure} out of range (Imp={imp} + 2D)"); } ErrorUnless(Util.InRange(efficiency, -5, 5), $"(Ex) Efficiency={efficiency} out of range (Flux)"); } // [Cx] { string cx = Cultural.Replace('[', ' ').Replace(']', ' ').Trim(); int homogeneity = SecondSurvey.FromHex(cx[0]); int acceptance = SecondSurvey.FromHex(cx[1]); int strangeness = SecondSurvey.FromHex(cx[2]); int symbols = SecondSurvey.FromHex(cx[3]); if (PopulationExponent == 0) { if (homogeneity != 0) { Error($"[Cx] Homogeneity={homogeneity} - expected 0 for Pop 0"); } if (acceptance != 0) { Error($"[Cx] Acceptance={acceptance} - expected 0 for Pop 0"); } if (strangeness != 0) { Error($"[Cx] Strangeness={strangeness} - expected 0 for Pop 0"); } if (symbols != 0) { Error($"[Cx] Symbols={symbols} - expected 0 for Pop 0"); } } else { ErrorUnless(Util.InRange(homogeneity, Math.Max(1, PopulationExponent - 5), Math.Max(1, PopulationExponent + 5)), $"[Cx] Homogeneity={homogeneity} out of range (Pop={PopulationExponent} + Flux)"); ErrorUnless(acceptance == Math.Max(1, PopulationExponent + imp), $"[Cx] Acceptance={acceptance} not equal Pop={PopulationExponent} + Imp={imp}"); ErrorUnless(Util.InRange(strangeness, Math.Max(1, 5 - 5), Math.Max(1, 5 + 5)), $"[Cx] Strangeness={strangeness} out of range (Flux + 5)"); ErrorUnless(Util.InRange(symbols, Math.Max(1, TechLevel - 5), Math.Max(1, TechLevel + 5)), $"[Cx] Symbols={symbols} out of range (TL={TechLevel} + Flux)"); } } // Ownership if (Government == 6 && !(HasCodePrefix("O:") || HasCodePrefix("Mr") || HasCode("Re") || HasCode("Px"))) { errors.Warning("Gov 6 missing O:/Mr/Re/Px", lineNumber, line); } }
internal void Serialize(ResourceManager resourceManager, TextWriter writer, string mediaType, bool includeMetadata = true, bool includeHeader = true, bool sscoords = false, WorldFilter filter = null) { WorldCollection worlds = GetWorlds(resourceManager); // TODO: less hacky T5 support bool isT5 = (mediaType == "TabDelimited" || mediaType == "SecondSurvey"); if (mediaType == "TabDelimited") { if (worlds != null) { worlds.Serialize(writer, mediaType, includeHeader: includeHeader, filter: filter); } return; } if (includeMetadata) { // Header // writer.WriteLine("# Generated by http://travellermap.com"); writer.WriteLine("# " + DateTime.Now.ToString("yyyy-MM-ddTHH:mm:sszzz", DateTimeFormatInfo.InvariantInfo)); writer.WriteLine(); writer.WriteLine("# {0}", Names[0]); writer.WriteLine("# {0},{1}", X, Y); writer.WriteLine(); foreach (var name in Names) { if (name.Lang != null) { writer.WriteLine("# Name: {0} ({1})", name.Text, name.Lang); } else { writer.WriteLine("# Name: {0}", name); } } if (Credits != null) { string stripped = Regex.Replace(Credits, "<.*?>", ""); stripped = Regex.Replace(stripped, @"\s+", " "); stripped = stripped.Trim(); writer.WriteLine(); writer.WriteLine("# Credits: {0}", stripped); } if (DataFile != null) { writer.WriteLine(); if (DataFile.Milieu != null) { writer.WriteLine("# Milieu: {0}", DataFile.Milieu); } writer.WriteLine(); if (DataFile.Author != null) { writer.WriteLine("# Author: {0}", DataFile.Author); } if (DataFile.Publisher != null) { writer.WriteLine("# Publisher: {0}", DataFile.Publisher); } if (DataFile.Copyright != null) { writer.WriteLine("# Copyright: {0}", DataFile.Copyright); } if (DataFile.Source != null) { writer.WriteLine("# Source: {0}", DataFile.Source); } if (DataFile.Ref != null) { writer.WriteLine("# Ref: {0}", DataFile.Ref); } } writer.WriteLine(); for (int i = 0; i < 16; ++i) { char c = (char)('A' + i); Subsector ss = Subsector(c); writer.WriteLine("# Subsector {0}: {1}", c, ss?.Name ?? ""); } writer.WriteLine(); } if (worlds == null) { if (includeMetadata) { writer.WriteLine("# No world data available"); } return; } // Allegiances if (includeMetadata) { // Use codes as present in the data, to match the worlds foreach (string code in worlds.AllegianceCodes().OrderBy(s => s)) { var alleg = GetAllegianceFromCode(code); if (alleg != null) { writer.WriteLine("# Alleg: {0}: \"{1}\"", isT5 ? code : SecondSurvey.T5AllegianceCodeToLegacyCode(code), alleg.Name); } } writer.WriteLine(); } // Worlds worlds.Serialize(writer, mediaType, includeHeader: includeHeader, sscoords: sscoords, filter: filter); }
internal void Serialize(ResourceManager resourceManager, TextWriter writer, string mediaType, SectorSerializeOptions options) { WorldCollection worlds = GetWorlds(resourceManager); // TODO: less hacky T5 support bool isT5 = (mediaType == "TabDelimited" || mediaType == "SecondSurvey"); if (mediaType == "TabDelimited") { worlds?.Serialize(writer, mediaType, options); return; } if (options.includeMetadata) { // Header // writer.WriteLine("# Generated by https://travellermap.com"); writer.WriteLine("# " + DateTime.Now.ToString("yyyy-MM-ddTHH:mm:sszzz", DateTimeFormatInfo.InvariantInfo)); writer.WriteLine(); writer.WriteLine($"# {Names[0]}"); writer.WriteLine($"# {X},{Y}"); writer.WriteLine(); foreach (var name in Names) { if (name.Lang != null) { writer.WriteLine($"# Name: {name.Text} ({name.Lang})"); } else { writer.WriteLine($"# Name: {name}"); } } writer.WriteLine(); writer.WriteLine($"# Milieu: {CanonicalMilieu}"); if (Credits != null) { string stripped = Regex.Replace(Credits, "<.*?>", ""); stripped = Regex.Replace(stripped, @"\s+", " "); stripped = stripped.Trim(); writer.WriteLine(); writer.WriteLine($"# Credits: {stripped}"); } if (DataFile != null) { writer.WriteLine(); if (DataFile.Author != null) { writer.WriteLine($"# Author: {DataFile.Author}"); } if (DataFile.Publisher != null) { writer.WriteLine($"# Publisher: {DataFile.Publisher}"); } if (DataFile.Copyright != null) { writer.WriteLine($"# Copyright: {DataFile.Copyright}"); } if (DataFile.Source != null) { writer.WriteLine($"# Source: {DataFile.Source}"); } if (DataFile.Ref != null) { writer.WriteLine($"# Ref: {DataFile.Ref}"); } } writer.WriteLine(); for (int i = 0; i < 16; ++i) { char c = (char)('A' + i); Subsector ss = Subsector(c); writer.WriteLine($"# Subsector {c}: {ss?.Name ?? ""}"); } writer.WriteLine(); } if (worlds == null) { if (options.includeMetadata) { writer.WriteLine("# No world data available"); } return; } // Allegiances if (options.includeMetadata) { // Use codes as present in the data, to match the worlds foreach (string code in worlds.AllegianceCodes().OrderBy(s => s)) { var alleg = GetAllegianceFromCode(code); if (alleg != null) { var a = isT5 ? code : SecondSurvey.T5AllegianceCodeToLegacyCode(code); writer.WriteLine($"# Alleg: {a}: \"{alleg.Name}\""); } } writer.WriteLine(); } // Worlds worlds.Serialize(writer, mediaType, options); }