using Nonemm.Core; using Nonemm.Core.Country; namespace Nonemm.Contests.Rules; /// OK/OM DX. An OK or OM station sends a county code and everyone else a /// serial number, and which side the operator is on decides what a contact /// scores. /// /// The received exchange lands in the section column for an OK or OM station /// and in the exchange column for everyone else, which is where N1MM keeps /// each of them. public sealed class OkOmDx : Contest { private readonly ModeCategory mode; public OkOmDx(ModeCategory mode) => this.mode = mode; public string Name => "OKOMDX"; public string DisplayName => "Czech and Slovak Republics DX"; public string CabrilloName => "OK-OM-DX"; public IReadOnlyList ExchangeFieldsFor(StationInfo me) => [ new ExchangeField("RST", ExchangeSlot.ReceivedReport, ExchangeFieldKind.Report), new ExchangeField("County", ExchangeSlot.Section, ExchangeFieldKind.Text) { Width = 4 }, new ExchangeField("Nr", ExchangeSlot.Exchange1, ExchangeFieldKind.Number), ]; /// An OK or OM station sends a county and no serial; everyone else the /// other way round, so one of the two boxes is stepped over. public bool SkipsField(ExchangeField field, CountryLookup? their) => field.Slot switch { ExchangeSlot.Section => their is not null && !IsOkOm(their.Entity.PrimaryPrefix), ExchangeSlot.Exchange1 => their is not null && IsOkOm(their.Entity.PrimaryPrefix), _ => false, }; public IReadOnlyList MultiplierNames => ["Countries", "Counties"]; public DupeScope DupeScope => DupeScope.PerBand; public bool HasSerialNumbers => true; public IReadOnlyList Modes => [mode]; public string SentExchangeFor(StationInfo me) => IsOkOm(me.CountryPrefix) ? me.County : "001"; /// A maritime mobile is 5 points to either side. An OK or OM operator gets /// 2 points at home, 3 elsewhere on the continent and 5 from another — /// Czechia and Slovakia are two countries, so they are 3 points to each /// other. Everyone else gets 10 points for an OK or OM station, 1 at home, /// 3 on their own continent and 5 from another. public int PointsFor(QsoContext qso) { if (qso.Qso.Call.IsMaritimeMobile) { return 5; } if (!IsOkOm(qso.Me.CountryPrefix) && IsOkOm(qso.CountryPrefix)) { return 10; } int home = IsOkOm(qso.Me.CountryPrefix) ? 2 : 1; return qso.IsSameCountry ? home : qso.IsSameContinent ? 3 : 5; } /// Both sides count the same two, once per band each: every country, and /// every OK or OM county. N1MM's own class counts prefixes for an OK or OM /// operator, which was the rule before the counties came in. public IReadOnlyList MultipliersFor(QsoContext qso) { string band = qso.Band?.Name ?? ""; List found = []; if (qso.CountryPrefix.Length > 0) { found.Add(new Multiplier(1, qso.CountryPrefix, band)); } string county = County(qso.Qso); if (IsOkOm(qso.CountryPrefix) && county.Length > 0) { found.Add(new Multiplier(2, county, band)); } return found; } public int TotalScore(ScoreTally tally, ContestEntry entry) => tally.Points * tally.TotalMultipliers; public CabrilloExchange CabrilloExchange(Qso qso, StationInfo me, ContestEntry entry) => new( [ new CabrilloField(me.Callsign, 13), new CabrilloField(qso.SentReport, 3), new CabrilloField(IsOkOm(me.CountryPrefix) ? me.County : $"{qso.SentNumber:000}", 6), ], [ new CabrilloField(qso.Call.Text, 13), new CabrilloField(qso.ReceivedReport, 3), new CabrilloField(County(qso).Length > 0 ? County(qso) : qso.Exchange1, 6), ]); private static string County(Qso qso) => qso.Section.Trim().ToUpperInvariant(); private static bool IsOkOm(string countryPrefix) => countryPrefix is "OK" or "OM"; }