diff --git a/Contest.pas b/Contest.pas index dc1eeb7..d77be04 100644 --- a/Contest.pas +++ b/Contest.pas @@ -44,12 +44,14 @@ TContest = class procedure DropStation(id : integer); virtual; abstract; function GetCall(id : integer) : string; virtual; abstract; procedure GetExchange(id : integer; out station : TDxStation); virtual; abstract; + function GetRandomSerialNR: Integer; virtual; function GetStationInfo(const ACallsign : string) : string; virtual; function PickCallOnly : string; function OnSetMyCall(const AUserCallsign : string; out err : string) : boolean; virtual; function OnContestPrepareToStart(const AUserCallsign: string; const ASentExchange : string) : Boolean; virtual; + procedure SerialNrModeChanged; virtual; function IsFarnsworthAllowed : Boolean; function GetSentExchTypes( const AStationKind : TStationKind; @@ -169,6 +171,15 @@ function TContest.IsFarnsworthAllowed : Boolean; end; +{ + Return a random serial number for the currently selected Serial NR mode + (a menu pick). +} +function TContest.GetRandomSerialNR: Integer; +begin + Result := Ini.SerialNRSettings[Ini.SerialNR].GetNR; +end; + { GetStationInfo() returns station's DXCC information. @@ -243,6 +254,20 @@ function TContest.OnContestPrepareToStart(const AUserCallsign: string; end; +{ + Called after + - 'Setup | Serial NR' menu pick + - 'Setup | Serial NR | Custom Range...' menu pick/modification + + The base class implementation does nothing. Other derived classes can + update cached information based on the serial NR menu pick (e.g. CQ WPX). +} +procedure TContest.SerialNrModeChanged; +begin + assert(RunMode <> rmStop); +end; + + { Return sent dynamic exchange types for the given kind-of-station and callsign. AStationKind represents either the user's station (representing current diff --git a/CqWpx.pas b/CqWpx.pas index c69c2d8..8cf3ee8 100644 --- a/CqWpx.pas +++ b/CqWpx.pas @@ -20,7 +20,6 @@ TCqWpx = class(TContest) PrevSerialNRType : TSerialNRTypes; PrevRangeStr : String; - procedure InitSerialNRGen; function GetNR(const station : TDxStation) : integer; public @@ -30,17 +29,17 @@ TCqWpx = class(TContest) function OnContestPrepareToStart(const AUserCallsign: string; const ASentExchange : string) : Boolean; override; function LoadCallHistory(const AUserCallsign : string) : boolean; override; + procedure SerialNrModeChanged; override; + procedure InitSerialNRGen; function PickStation(): integer; override; procedure DropStation(id : integer); override; function GetCall(id:integer): string; override; // returns station callsign procedure GetExchange(id : integer; out station : TDxStation); override; + function GetRandomSerialNR: Integer; override; function getExch1(id:integer): string; // returns RST (e.g. 5NN) function getExch2(id:integer): string; // returns section info (e.g. 3) - {function getZone(id:integer): string; // returns CQZone (e.g. 3) - function FindCallRec(out fdrec: TCqWpxCallRec; const ACall: string): Boolean; - } function GetStationInfo(const ACallsign: string) : string; override; function ExtractMultiplier(Qso: PQso) : string; override; end; @@ -48,14 +47,40 @@ TCqWpx = class(TContest) implementation uses - SysUtils, Generics.Defaults, System.Math, {Ini,} Classes, ARRL; + SysUtils, Generics.Defaults, System.Math, + Main, // for SetMySerialNR + Classes, ARRL; function TCqWpx.OnContestPrepareToStart(const AUserCallsign: string; const ASentExchange : string) : Boolean; begin + // Refresh Serial NR Generator before calling OnContestPrepareToStart InitSerialNRGen; Result := inherited OnContestPrepareToStart(AUserCallsign, ASentExchange); + + // reload My Serial Number at start of contest. This allows Mid-Contest and + // End of Contest modes to set Tst.Me.NR with a realistic random number. + if Result then + MainForm.SetMySerialNR; +end; + + +{ + Overriden for the CQ WPX Contest to allow regeneration of the SerialNRGen + tables (based on new Ini.SerialNR setting). + + Called after + - 'Setup | Serial NR' menu pick + - 'Setup | Serial NR | Custom Range...' menu pick/modification + + This can be called during a Run if the user selects a different + Serial NR distribution (e.g. Mid-Contest, End of Contest, etc.). +} +procedure TCqWpx.SerialNrModeChanged; +begin + assert(RunMode <> rmStop); + InitSerialNRGen; end; @@ -77,6 +102,8 @@ constructor TCqWpx.Create; inherited Create; CallLst := TCallList.Create; SerialNRGen := TSerialNRGen.Create; + + InitSerialNRGen; end; @@ -228,6 +255,12 @@ procedure TCqWpx.DropStation(id : integer); end; +function TCqWpx.GetRandomSerialNR: Integer; +begin + Result := Self.SerialNRGen.GetNR; +end; + + // return status bar information string from DXCC data file. // the callsign, Entity and Continent are returned. // this string is used in MainForm.sbar.Caption (status bar). @@ -271,12 +304,19 @@ procedure TCqWpx.GetExchange(id : integer; out station : TDxStation); end; +{ + Returns the serial number for a DX Station being worked. + For HST or Start-of-Contest serial NR modes, the serial number is based + on elapsed time and operator skill. For Mid-Contest and End-of-Contest + modes, the serial number returned will follow a distribution similar to + the a WPX Contest. See SerNRGen for more information. +} function TCqWpx.GetNR(const station : TDxStation) : integer; begin if (RunMode = rmHST) or (Ini.SerialNR = snStartContest) then Result := station.Oper.GetNR // Result = f(elapsed time, operator skill) else - Result := SerialNRGen.GetNR; + Result := GetRandomSerialNR; // follows WPX distribution of serial NRs end; @@ -291,6 +331,7 @@ function TCqWpx.getExch2(id:integer): string; // returns serial number (e.g. Result := '1'; end; + end. diff --git a/Ini.pas b/Ini.pas index 84ae7c1..cb12430 100644 --- a/Ini.pas +++ b/Ini.pas @@ -57,6 +57,7 @@ TSerialNRSettings = record procedure Init(const Range: string; AMin, AMax: integer); function IsValid : boolean; function ParseSerialNR(const ValueStr : string; var Err : string) : Boolean; + function GetNR : integer; end; PSerialNRSettings = ^TSerialNRSettings; @@ -514,6 +515,16 @@ function TSerialNRSettings.IsValid: Boolean; end; +function TSerialNRSettings.GetNR : integer; +begin + assert(IsValid); + if IsValid then + Result := MinVal + Random(MaxVal - MinVal) + else + Result := 1; +end; + + function TSerialNRSettings.ParseSerialNR( const ValueStr : string; var Err : string) : Boolean; diff --git a/Main.pas b/Main.pas index 8026222..0001765 100644 --- a/Main.pas +++ b/Main.pas @@ -398,6 +398,7 @@ TMainForm = class(TForm) procedure Advance; procedure SetContest(AContestNum: TSimContest); procedure SetMyExchange(const AExchange: string); + procedure SetMySerialNR; procedure SetQsk(Value: boolean); procedure SetWpm(AWpm : integer); procedure SetMyCall(ACall: string); @@ -1181,6 +1182,13 @@ procedure TMainForm.UpdateTitleBar; end; +procedure TMainForm.SetMySerialNR; +begin + assert(Tst.Me.SentExchTypes.Exch2 = etSerialNr); + SetMyExch2(Tst.Me.SentExchTypes.Exch2, Ini.UserExchange2[SimContest]); +end; + + procedure TMainForm.SetMyCall(ACall: string); var err : string; @@ -1310,16 +1318,23 @@ procedure TMainForm.SetMyExch1(const AExchType: TExchange1Type; procedure TMainForm.SetMyExch2(const AExchType: TExchange2Type; const Avalue: string); begin + assert(RunMode = rmStop); // Adding a contest: setup contest-specific exchange field 2 case AExchType of etSerialNr: begin + var S : String := Avalue.Replace('T', '0', [rfReplaceAll]) + .Replace('O', '0', [rfReplaceAll]) + .Replace('N', '9', [rfReplaceAll]); Ini.UserExchange2[SimContest] := Avalue; - if not IsNum(Avalue) or (RunMode = rmHst) then - Tst.Me.Nr := 1 + if SimContest = scHST then + Tst.Me.NR := 1 + else if S.Contains('#') and (SerialNR in [snMidContest, snEndContest]) then + Tst.Me.NR := 1 + (Tst.GetRandomSerialNR div 10) * 10 + else if IsNum(S) then + Tst.Me.Nr := S.ToInteger else - Tst.Me.Nr := StrToInt(Avalue); - + Tst.Me.Nr := 1; if BDebugExchSettings then Edit3.Text := IntToStr(Tst.Me.Nr); // testing only end; etGenericField, etNaQpExch2, etNaQpNonNaExch2: @@ -2344,12 +2359,15 @@ procedure TMainForm.UpdSerialNR(V: integer); if not Ini.SerialNRSettings[snt].IsValid then snt := snStartContest; - //Ini.NRDigits := nrd; Ini.SerialNR := snt; SerialNRSet1.Checked := snt = snStartContest; SerialNRSet2.Checked := snt = snMidContest; SerialNRSet3.Checked := snt = snEndContest; SerialNRCustomRange.Checked := snt = snCustomRange; + + // update contest-specific settings/caches (e.g. SerialNR Generator for CQ Wpx) + if not (RunMode in [rmStop, rmHST]) then + Tst.SerialNrModeChanged; end;