unit MainForm;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ComCtrls, Spin, ExtCtrls,  uHCTypeDefs, uHCAnnexDefs, uHCAnnexHelpers,
  uLazGUIGlobals ,CheckLst, XMLPropStorage, Menus, uHCUtils;

type

  { TfrmMain }

  TfrmMain = class(TForm)
    SGlblUnitKts: TLabel;
    SGButtonResume: TButton;
    SGlblClassName: TLabel;
    SGButtonRefresh: TButton;
    SGListBoxUnitInfo: TListBox;
    SGlblUnitIDName: TLabel;
    SGpnlUnit: TPanel;
    SGlblGroups: TLabel;
    SGlblUnits: TLabel;
    SGlbxGroups: TListBox;
    SGlbxUnits: TListBox;
    SGpnl1: TPanel;
    SGlblDesc: TLabel;
    tshStartGroup: TTabSheet;
    PageControl1: TPageControl;
    SessionSze: TXMLPropStorage;
    procedure SessionSzeRestoreProperties(Sender: TObject);
    procedure SessionSzeSavingProperties(Sender: TObject);
    procedure SGButtonRefreshClick(Sender: TObject);
    procedure SGButtonResumeClick(Sender: TObject);
    procedure SGlbxGroupsDblClick(Sender: TObject);
    procedure SGlbxGroupsSelectionChange(Sender: TObject; User: boolean);
    procedure SGlbxUnitsDblClick(Sender: TObject);
    procedure SGlbxUnitsSelectionChange();  //  240613  (Sender: TObject; User: boolean);
    procedure UNbtnResumeClick(Sender: TObject);
    function HCMT2String(const ValHCMT: HCMT): string;
    function Side2String(const ThisSide: uchar): string;

  private
    { private declarations }
  public
    { public declarations }
    // ALE 20130812 Big bad pointers that hold most of the game data
    PStartGroup, PSelectedGroup, PHCSGThis: PHCGroup;
    PHarpEventHead, PEvent: PHCHarpoonEvent;
    PSonobuoyRegionHead: PHCSonobuoyRegion;
    PAllDeadUnitsPtr: PHCDeadListItem;
    PWeatherGroups: PHCGroup;
    PVCList: PHCVictoryConditions;
    // ALE 20130812 transient pointers
    PSelectedUnit, PEventUnit: PHCUnit;
    // ALE 20130812 misc globals
    //blnInvestigatingStructs: Boolean;
    // ALE 20130908 pointers to functions exported by the GE
    HCQueueHarpoonEvent: THCQueueHarpoonEvent;
    NewPtr: THCNewPtr;
    HCdllCheckLatLonDepth: THCdllCheckLatLonDepth;
    HCannex_id_to_disk_id: THCannex_id_to_disk_id;
    HCdisk_id_to_annex_id: THCdisk_id_to_annex_id;
    HCChangeActGroupPtr: THCChangeActGroupPtr;
    HCChangeActUnitPtr: THCChangeActUnitPtr;

//    PHCAnnexA2: PHCAnnexA2_disk;     // sub moved to public for spin box
//    PHCAnnexA1: PHCAnnexA1_disk;     // ship ditto   240411 moved back
    intPSide, intESide: uchar;
    strSide, strOSide: string;
    HCfree_Unit: THCfree_Unit;
    HCfree_Group: THCfree_Group;
    intGTNow: LongInt;
  end;

var
  frmMain: TfrmMain;


implementation

uses uHCDefines, uHCEventHelpers;

{$R *.lfm}

{ TfrmMain }

function TfrmMain.Side2String(const ThisSide: uchar): string;

  begin
    case ThisSide of
    0: result:= 'Blue';
    1: result:= 'Red';
    2: result:= 'Green';
    else result:= 'Unknown';
    end;
  end;

function TfrmMain.HCMT2String(const ValHCMT: HCMT): string;
var
  strHCMT: string;

begin
  case ValHCMT  of
       MT_AC:         result := 'Plane';
       MT_HELO:       result := 'Helo';
       MT_CARRIER:    result := 'Carrier';
       MT_SHIP:       result := 'Surface Vessel';
       MT_SUB:        result := 'Submarine';
       MT_AIRFIELD:   result := 'Airfield';
       MT_PORT:       result := 'Port';
       MT_BASE:       result := 'Port & Airfield';
       MT_CITY:       result := 'City';
       MT_MISSILE:    result := 'Missile';
       MT_TORP:       result := 'Torpedo';
       MT_SAMFIXED:   result := 'AD Fixed';
       MT_SAMMOBILE:  result := 'AD Mobile';
       MT_CONVOY:     result := 'Convoy';
       MT_ARMORED:    result := 'Armored';
      else         result := 'Unkn ' + IntToStr(ValHCMT);

  end;
end;

procedure TfrmMain.SGlbxGroupsSelectionChange(Sender: TObject; User: boolean);
var
  strSel: String;
  PHCUThis: PHCUnit;
begin
   // ALE 20130317 User selected a group, pull up unit list.
  strSel := SGlbxGroups.Items[SGlbxGroups.ItemIndex];
  PHCSGThis := PStartGroup;
  while (PHCSGThis <> nil) do
  begin
    if (strSel = PHCSGThis^.id) then
       break;
    PHCSGThis := PHCSGThis^.toSouth;
  end;
  // ALE 20130317 in theory we have the group from which
  //  we can enumerate the units.
  SGlblUnitIDName.Caption:= '';
  SGlblClassName.Caption:=  '';
  SGlblUnitKts.Caption:= '';
  SGListBoxUnitInfo.Items.Clear;
  SGlbxUnits.Items.Clear;
  if PHCSGThis <> nil then
  begin
  PSelectedGroup:= PHCSGThis;
  PSelectedUnit:= nil;      //  240907  reset public selected unit
  SGlbxUnits.Sorted := True;
  PHCUThis := PHCSGThis^.Units;        //  list units
  while (PHCUThis <> nil) do
  begin
  if PHCUThis^.Missile = nil           //  240907 add missile test and platNo
  then
  SGlbxUnits.Items.Add(Format('%2.2s%0.3d %s', [PHCSGThis^.id, PHCUThis^.id, PHCUThis^.name]))
  else
  SGlbxUnits.Items.Add(Format('%2.2s%0.3d %d %s',
    [PHCSGThis^.id, PHCUThis^.id, PHCUThis^.Missile^.PlatNow, PHCUThis^.name]));
    PHCUThis := PHCUThis^.next;
  end;
//  20230603 add group info to the unit detail section
  SGlblUnitIDName.Caption:= Format('%s %s',[Side2String(PHCSGThis^.side), HCMT2String(PHCSGThis^.gtype)]);
  SGlblClassName.Caption:= Format('Grp Speed: %d/%d kts, course: %d degs',
      [PHCSGThis^.kts, PHCSGThis^.maxspeed, PHCSGThis^.course]);
  SGListBoxUnitInfo.Items.Add(Format('Grp RCS: %d, VCS: %d, ECM: %d',[PHCSGThis^.RCS, PHCSGThis^.VCS,
      PHCSGThis^.ecm]));
  if PHCSGThis^.Units^.Missile <> nil
    then
    begin
      if PHCSGThis^.Units^.Missile^.targetUnit <> nil
      then strSel:= Format('%2.2s',[PHCGroup(PHCUnit(PHCSGThis^.Units^.Missile^.targetUnit)^.Group)^.id])
      else strSel:= 'Nil';
    end;

//  SGListBoxUnitInfo.Items.Add(Format('AI Risk Taking: %d',[PHCSGThis^.AIChance]));
//  SGCurntSpdSpnEd.Value:= PHCSGThis^.kts;     //  240315 set up to edit group speed
//  SGCurntSpdSpnEd.MaxValue:= PHCSGThis^.maxspeed;
  end
  else
  SGlbxUnits.Items.Add('Selected Group no longer valid'); // test for valid group
end;

procedure TfrmMain.SGlbxUnitsDblClick(Sender: TObject);
begin
  if PSelectedUnit <> nil then
  HCChangeActUnitPtr(PSelectedUnit);
end;


procedure TfrmMain.SessionSzeRestoreProperties(Sender: TObject); // set location  20230409
begin
  //Top:= StrToInt(SessionSze.StoredValue['frmMain_Top']);               //  do I need to test for file exists?
  //Width:= StrToInt(SessionSze.StoredValue['frmMain_Width']);           // if FileExists(Application.Location + LAZGExtn.xml) then ..
  //Height:= StrToInt(SessionSze.StoredValue['frmMain_Height']);
  //Left:= StrToInt(SessionSze.StoredValue['frmMain_Left']);
end;

procedure TfrmMain.SessionSzeSavingProperties(Sender: TObject);  // store location 20230409
begin
  SessionSze.StoredValue['frmMain_Top']:= IntToStr(Top);        // move to boundary changed  too
  SessionSze.StoredValue['frmMain_Width']:= IntToStr(Width);
  SessionSze.StoredValue['frmMain_Height']:= IntToStr(Height);
  SessionSze.StoredValue['frmMain_Left']:= IntToStr(Left);
end;

procedure TfrmMain.UNbtnResumeClick(Sender: TObject);
begin
  Byte(PDLLBusy^) := CFALSE;
end;


procedure TfrmMain.SGButtonRefreshClick(Sender: TObject);
var
  PTGroup: PHCGroup;
begin
  SGlbxGroups.Items.Clear;
  SGlbxUnits.Items.Clear;
  SGListBoxUnitInfo.Clear;
  SGlblUnitIDName.Caption:= '';           //  clear all boxs until a unit is selected  20230503
  SGlblClassName.Caption:= '';
  SGlblUnitKts.Caption:= '';
  PTGroup := PStartGroup;
  while (PTGroup <> nil) do
    begin
    SGlbxGroups.Items.Add(PTGroup^.id);           //  HCMT would be usful
    PTGroup := PTGroup^.toSouth;
    end;
end;

procedure TfrmMain.SGButtonResumeClick(Sender: TObject);
begin
  if (SGButtonResume.Caption = 'RESUME')
  then
  begin
  Byte(PDLLBusy^) := CFALSE;
  SGButtonResume.Caption:= 'PAUSE';
  end
  else
  begin
  Byte(PDLLBusy^) := CTRUE;
  SGButtonResume.Caption:= 'RESUME';
  end;

end;

procedure TfrmMain.SGlbxGroupsDblClick(Sender: TObject);
begin
  if PHCSGThis <> nil then

    HCChangeActGroupPtr(PHCSGThis);
end;

procedure TfrmMain.SGlbxUnitsSelectionChange();  //  240613 - (Sender: TObject; User: boolean);
var
  strSel, strDepthAlt, strShow, strWepName, strPlaneLoadout, strName,
    strMGPhase, strStatus, strUType, strDescript: String;      // strSide, strOSide, moved to updateshowing
  PHCUThis: PHCUnit;
  PThisMnt: PHCMntRec;
  PThisMag: PHCMagRec;
  PmyPlanes: PHCPlaneRec;
  RLat, RLon: Double;
  intDepthAlt, intShow, intC: integer;
  isTanker, isSub, isAir: Boolean;    // , isShip, isBase     240319 not using now
  strID: uchar;
  ThisWepID:  ID;
  PThisLoadout: PHCAnnexY1_disk;
  PThisMount: PHCAnnexZ1_disk;
  PThisMulti: PHCAnnexZ2_disk;
  PHCAnnexA1: PHCAnnexA1_disk;      // surface ship
  PHCAnnexA2: PHCAnnexA2_disk;      // subs
  PHCAnnexB1: PHCAnnexB1_disk;      // aircraft
  PHCAnnexP1: PHCAnnexP1_disk;      // installations/bases
  PHCAnnexC1: PHCAnnexC1_disk;      // guns
  PHCAnnexD1: PHCAnnexD1_disk;      // missiles
  PHCAnnexE1: PHCAnnexE1_disk;      // asw dc mortar etc
  PHCAnnexF1: PHCAnnexF1_disk;      // torpedos
  PHCAnnexG1: PHCAnnexG1_disk;      // ATOG
  PHCAnnexG2: PHCAnnexG2_disk;      // ECM
  PHCAnnexM1: PHCAnnexM1_disk;      // Sonar

begin
  // ALE 20130317 User selected a unit, pull up unit info.
  isTanker:= False;  //until proven True
  strSel := SGlbxUnits.Items[SGlbxUnits.ItemIndex];    // need a check for selected unit/group? no longer valid
                                                       //  check group still valid
  if HCIsValidGroup(PSelectedGroup, PStartGroup) = CTRUE then
  begin
  PHCUThis := PSelectedGroup^.Units;
  while (PHCUThis <> nil) do
  begin
    if (Pos(Format('%2.2s%0.3d', [PSelectedGroup^.id, PHCUThis^.id]), strSel) = 1) then
      break;
    PHCUThis := PHCUThis^.next;
  end;                            // ddt add unit information
  if (PHCUThis <> nil) then      // test for valid unit
  begin
    isSub:= False;
    isAir:= False;
//    isShip:= False;
//    isBase:= False;
    PSelectedUnit := PHCUThis;         //  set PSelectedUnit to unit selected in list
    SGListBoxUnitInfo.Items.Clear;
    strUType:= '';
    strDescript:= '';

    // now add class name using annex

      case (HCAnnexHelper.HCAnnexShift(PSelectedUnit^.Annex)) of
          SHIP_FLAG:
          begin
//            isShip:= True;
            PHCAnnexA1 := HCAnnexHelper.HCGetAnnexA1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := Format('Ship Class Name: %s, Country: %s, ID %d',
              [PHCAnnexA1^.ClassName, AnnexData^.PBSStrings^.CountryName[PHCAnnexA1^.Country], PHCAnnexA1^.Country]);    //  250811 and below add country
            strUType:= AnnexData^.PBSStrings^.ShipType[PHCAnnexA1^.Subtype];
  strDescript:= 'TxtID: ' + IntToStr(PHCAnnexA1^.TextIndex) + ': ' + AnnexData^.PPLAT_DESC_LIST[PHCAnnexA1^.TextIndex].description;    //  250810
          end;
          SUB_FLAG:
          begin
            PHCAnnexA2 := HCAnnexHelper.HCGetAnnexA2(PSelectedUnit^.Annex);
            SGlblClassName.Caption := Format('Submarine Class Name: %s, Country: %s, ID %d',
                [PHCAnnexA2^.ClassName, AnnexData^.PBSStrings^.CountryName[PHCAnnexA2^.Country], PHCAnnexA2^.Country]);
            strUType:= AnnexData^.PBSStrings^.ShipType[PHCAnnexA2^.Subtype];
   strDescript:=  'TxtID: ' + IntToStr(PHCAnnexA2^.TextIndex) + ': ' + AnnexData^.PPLAT_DESC_LIST[PHCAnnexA2^.TextIndex].description;    //  250810
            isSub:= True;
            intDepthAlt:= PSelectedUnit^.AltBand;
            case intDepthAlt of
  0: strDepthAlt := 'TooDeep';
  1: strDepthAlt := 'Vdeep';
  2: strDepthAlt := 'Deep';
  3: strDepthAlt := 'Intermed';
  4: strDepthAlt := 'Shallow';
  5: strDepthAlt := 'Snorkel';
  6: strDepthAlt := 'SeaLevel';
  7: strDepthAlt := 'ScopeAlt';
          end;
          end;
          PLANE_FLAG:
          begin
            isAir:= True;
            PHCAnnexB1 := HCAnnexHelper.HCGetAnnexB1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := Format('Aircraft Class Name: %s, Country: %s, ID %d',
               [PHCAnnexB1^.ClassName, AnnexData^.PBSStrings^.CountryName[PHCAnnexB1^.Country], PHCAnnexB1^.Country]);
            strUType:= AnnexData^.PBSStrings^.ACType[PHCAnnexB1^.Subtype];
   strDescript:=  'TxtID: ' + IntToStr(PHCAnnexB1^.TextIndex) + ': ' + AnnexData^.PPLAT_DESC_LIST[PHCAnnexB1^.TextIndex].description;    //  250810
          end;
          BASE_FLAG:
          begin
//            isBase:= True;            //  240319
            PHCAnnexP1 := HCAnnexHelper.HCGetAnnexP1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := Format('Base Name: %s, Country: %s, ID %d',
               [PHCAnnexP1^.Name, AnnexData^.PBSStrings^.CountryName[PHCAnnexP1^.Country], PHCAnnexP1^.Country]);
          end;
          MISSILE_FLAG:
          begin
            isAir:= True;
            PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := 'Missile Class: ' + PHCAnnexD1^.ClassName;  //  240606   back edit
          end;
          TORP_FLAG:
          begin
            PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := 'Torpedo Class: ' + PHCAnnexF1^.ClassName;   //  240607 back edit
          end;
          ASW_FLAG:
          begin
            PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(PSelectedUnit^.Annex);
            SGlblClassName.Caption:= 'Class: ' + PHCAnnexE1^.ClassName;           //  240607 added ASW
          end;
          else
            SGlblClassName.Caption := 'No Class Name';  // (HCAnnexHelper.HCAnnexShift(PSelectedUnit^.Annex))
        end;
    SGlblUnitKts.Caption:= 'Unit''s class AnnexID ' + IntToStr(PSelectedUnit^.Annex);
//
 SGListBoxUnitInfo.Items.Insert(0, strDescript);   //250810

    // finished getting class name from annex
    SGlblUnitIDName.Caption := Format('%2.2s%0.3d %s %s',
      [PSelectedGroup^.id, PSelectedUnit^.id, strUType, PSelectedUnit^.name]);  //  240412 add strUType
    SGListBoxUnitInfo.Items.Add(format('MaxKts: %d',[PSelectedUnit^.maxspeed]));
    SGListBoxUnitInfo.Items.Add(format('best weapon range: AAW- %0.1n, ASUW- %0.1n, ASW- %0.1n',
      [PSelectedUnit^.BestAAWRange / 10, PSelectedUnit^.BestASuWRange / 10 ,
       PSelectedUnit^.BestASWRange / 10]));                                //  240617 >>
  if (PSelectedUnit^.utype = MT_SHIP) or (PSelectedUnit^.utype = MT_SUB) then
    SGListBoxUnitInfo.Items.Add(format('BaseHydroNoise(at Creep): %d',[PSelectedUnit^.BaseSourceLevel]));
    SGListBoxUnitInfo.Items.Add(Format('RCS: %d, VCS: %d',[PSelectedUnit^.RCS, PSelectedUnit^.VCS]));
  if isSub then
    SGListBoxUnitInfo.Items.Add('MaxDepth: ' + HCAltBand2String(PHCAnnexA2^.MaxDepth));
  if isAir = False
    then SGListBoxUnitInfo.Items.Add(format('Damage Points: %d',[PSelectedUnit^.OrigDp]));

// test for air or missile units        PROB need to do loadouts and mounts here and delete unit^.air from general mounts and mags
  if (PSelectedUnit^.Air <> nil) then
  begin
    SGListBoxUnitInfo.Items.Insert(0, 'Aircraft Unit');
    SGListBoxUnitInfo.Items.Insert(1,'MaxAlt: ' + HCAltBand2String(PHCAnnexB1^.MaxAlt));  //240607
     if ((PHCAnnexB1^.UnitFlags AND UF_B1_NOE) > 0) then
       SGListBoxUnitInfo.Items.Add('NapeOfEarth - YES')  else
       SGListBoxUnitInfo.Items.Add('NapOfEarth - NO');
    if ((PHCAnnexB1^.UnitFlags AND UF_B1_refuelcapable) > 0) then
       SGListBoxUnitInfo.Items.Add('InFlightRefuel - YES')  else
       SGListBoxUnitInfo.Items.Add('InFlightRefuel - NO');
  //have annex, get more info
    SGListBoxUnitInfo.Items.Add('Det.Size: ' + IntToStr(PHCAnnexB1^.Size) + '; RCS: '
      + IntToStr(PHCAnnexB1^.RCS));   //  240607
    SGListBoxUnitInfo.Items.Add('Max alt band: ' + HCAltBand2String(PHCAnnexB1^.MaxAlt));  //  240607
    if PSelectedUnit^.Air^.FuelToOffload > 0 then
    SGListBoxUnitInfo.Items.Add(format('tanker fuel remaining: %d per tanker',[PSelectedUnit^.Air^.FuelToOffload]));
 //  now add loadout info   then add mount info separate
  If PSelectedUnit^.Mnts <> nil      //  this is in airunit so is loadout
    then
    begin
    PThisMnt:= PselectedUnit^.Mnts;
    if (HCAnnexShift(PThisMnt^.MntId) = LOADOUT_FLAG)  then
    SGListBoxUnitInfo.Items.Add('WEAPONS:');   //  240617  is this correct place?
  while (PThisMnt <> nil) do
    begin
    if (HCAnnexShift(PThisMnt^.MntId) = LOADOUT_FLAG)  then   //find mission type
    begin
    SGListBoxUnitInfo.Items.Add('Loadout Annex ' + IntToStr(PThisMnt^.MntId));

    PThisLoadout:= HCAnnexHelper.HCGetAnnexY1(PThisMnt^.MntId);            //  240616 deletd loadout from print
    strPlaneLoadout:= format('Air Unit, Mission #%d: ',[PThisLoadout^.MissionID]);   // 240616 added loadout #
    case HCMissionMap[PThisLoadout^.MissionID] of
        Ord(THCMissionType.MISSION_TANKER): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Tanker';
        Ord(THCMissionType.MISSION_FERRY): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Ferry';
        Ord(THCMissionType.MISSION_ASSAULT): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Assault';
        Ord(THCMissionType.MISSION_PATROL): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Patrol';
        Ord(THCMissionType.MISSION_NUCLEAR): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Nuclear';
        Ord(THCMissionType.MISSION_STANDOFF): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Standoff';
        Ord(THCMissionType.MISSION_SEAD): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Sead';
        Ord(THCMissionType.MISSION_GUIDED): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Guided';
        Ord(THCMissionType.MISSION_UNGUIDED): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Unguided';
        Ord(THCMissionType.MISSION_ANTIRUN): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Anti Runway';
        Ord(THCMissionType.MISSION_ATA): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Intercept';
        Ord(THCMissionType.MISSION_ASW): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'ASW';
        Ord(THCMissionType.MISSION_AARMR): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Anti Armour';
        Ord(THCMissionType.MISSION_DECOY): SGListBoxUnitInfo.Items.Strings[0]:= strPlaneLoadout + 'Decoy';
      end;    //end case of mission type   COULD add loadout weapon count data to print as per landed planes
     end;   // end getting ID mission type
 //  LOADOUT WEAPONS
    if PThisMnt^.WepId <> INVALID_ID      //    PThisMnt: PHCMntRec
    then
    begin
    ThisWepID:= PThisMnt^.WepId;
    begin
    case (HCAnnexShift(ThisWepId)) of
    GUN_FLAG:
      begin
      PHCAnnexC1:= HCAnnexHelper.HCGetAnnexC1(ThisWepId);
      strWepName:=  Format('%s; ARange: %d NM, SRange: %d NM',
              [PHCAnnexC1^.ClassName, (PHCAnnexC1^.AirRange div 10), (PHCAnnexC1^.SurfRange div 10)]);
      end;
    MISSILE_FLAG:
      begin
      PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(ThisWepId);
      strWepName:= Format('%s; ARange: %d NM, SRange: %d NM, MinRange: %d NM',
      [PHCAnnexD1^.ClassName, (PHCAnnexD1^.AirRange div 10), (PHCAnnexD1^.SurfRange div 10),
      (PHCAnnexD1^.MinRange div 10)]);
      end;
    ASW_FLAG:
    begin
    PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(ThisWepId);
    strWepName:= Format('%s: MaxRange: %d MinRange: %d',
              [PHCAnnexE1^.ClassName, (PHCAnnexE1^.MaxRange div 10), (PHCAnnexE1^.MinRange div 10)]);
    end;
    TORP_FLAG:
    begin
    PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(ThisWepId);
    strWepName:= Format('%s; MaxRange: %d/%d MaxDepth %s',
            [PHCAnnexF1^.ClassName, (PHCAnnexF1^.MaxRange[0] div 10), (PHCAnnexF1^.MaxRange[1] div 10),
            HCAltBand2String(PHCAnnexF1^.MaxDepth)]);
    end;
    ATOG_FLAG:
    begin
    PHCAnnexG1:= HCAnnexHelper.HCGetAnnexG1(ThisWepId);
    strWepName:= 'weptype ' + intToStr(PHCAnnexG1^.WType) + '/' + PHCAnnexG1^.ClassName;
    end;
    ECM_FLAG:
    begin
    PHCAnnexG2:= HCAnnexHelper.HCGetAnnexG2(ThisWepId);
    strWepName:= PHCAnnexG2^.ClassName;
    end;
    SONAR_FLAG:
      begin
      PHCAnnexM1:= HCAnnexHelper.HCGetAnnexM1(ThisWepId);
      strWepName:= PHCAnnexM1^.ClassName;
      end;
    else
      strWepName:= format('misc - WepID %d',[ThisWepId]);
    end;  //  end look at  mount
      SGListBoxUnitInfo.Items.Add('  ' + IntToStr(PThisMnt^.Ammo_c[0]) + ' - ' + strWepName +
          ', WepAnnex ' + IntToStr(ThisWepID)); // 240307
      strWepName:= '';
    end;   // end this weapon of loadout
    end  //; // valid weaponID else its an INVALID_ID dummy entry
    else  SGListBoxUnitInfo.Items.Add('  DummyWep');
                             //  finished looking this multimount
    PThisMnt:= PThisMnt^.next;
    end;  // end this loadout    - should only be one
  end; // look at air unit loadouts
  // listing altband - speed table            240617 moved from before wep list  WHY did I do it like this??
  SGListBoxUnitInfo.Items.Add('AltBand/Throttle/Speed Table:');
  SGListBoxUnitInfo.Items.Add(format('speed level 0=%d',[PHCAnnexB1^.SpeedLevels[0]]));
      for intC := 1 to  (PLANE_SPEED_LEVELS - 1) do
      SGListBoxUnitInfo.Items.Append(format('speed level %d=%d',[intC, PHCAnnexB1^.SpeedLevels[intC]]));
  //  finished altband  - speed table
  end             // end look at air units
  else
//  MISSILE UNITS   !!! INcludes torpedo and asroc but separate annex
  if (PSelectedUnit^.Missile <> nil) then
  begin
    SGListBoxUnitInfo.Items.Insert(0, 'Missile Unit');

    SGListBoxUnitInfo.Items.Add('AnnexID: ' + IntToStr(PSelectedUnit^.Annex));
    case (HCAnnexHelper.HCAnnexShift(PSelectedUnit^.Annex)) of
    MISSILE_FLAG:
                 begin
                   SGListBoxUnitInfo.Items.Add(format('AirPh/SurfPh: %d/ %d; DP: %d',
                     [PHCAnnexD1^.AirPh, PHCAnnexD1^.SurfPh, PHCAnnexD1^.Dp]));   //  240607
                   SGListBoxUnitInfo.Items.Add(format('Operational: %S - %s',
                     [HCAltBand2String(PHCAnnexD1^.MinAlt), HCAltBand2String(PHCAnnexD1^.MaxAlt)]));
                 end;
    ASW_FLAG:
                 begin
                   if PHCAnnexE1^.Dp < 101
                   then
                     SGListBoxUnitInfo.Items.Add(format('Ph: %d; DP: %d',
                       [PHCAnnexE1^.Ph, PHCAnnexE1^.Dp]))
                   else SGListBoxUnitInfo.Items.Add('ASROC');
                   SGListBoxUnitInfo.Items.Add(format('Operational: %d - %d',
                     [((PHCAnnexE1^.MinRange) div 10), ((PHCAnnexE1^.MaxRange) div 10)]));      //  240607
                 end;
    TORP_FLAG:
                 begin
                   SGListBoxUnitInfo.Items.Add(format('Ph: %d; DP Surf/Sub: %d/ %d',
                     [PHCAnnexF1^.Ph, PHCAnnexF1^.SurfDp, PHCAnnexF1^.SubDp]));
                   SGListBoxUnitInfo.Items.Add(format('MaxDepth: %s',
                     [HCAltBand2String(PHCAnnexF1^.MaxDepth)]));    //  240607
                 end;
    end;


  end;
// end air missile unit test

// SURFACE UNIT MOUNTS
  if (PselectedUnit^.Mnts <> nil) and (PSelectedUnit^.Air = nil) then       //  240307 re introduce NOT AIR
  begin
  SGListBoxUnitInfo.Items.Add('* Mounts *');
  PThisMnt:= PselectedUnit^.Mnts;
  while (PThisMnt <> nil) do
    begin                             // PThisMnt = ships mount,  PThisMount = Mount annex
    SGListBoxUnitInfo.Items.Add('MountID: ' + IntToStr(PThisMnt^.MntId));
    if (HCAnnexShift(PThisMnt^.MntId) = MOUNT_FLAG)  then
  begin    //  Name Mount
    PThisMount:= HCAnnexHelper.HCGetAnnexZ1(PThisMnt^.MntId);
    SGListBoxUnitInfo.Items.Add(format('Type: %s: %d mounts; %d tubes, %d targets',
           [PThisMount^.ClassName, PThisMount^.NumMounts, PThisMount^.NumTubes,
           PThisMount^.NumTargets]));
  end;
    if PThisMnt^.WepId <> INVALID_ID
    then
    begin
    ThisWepID:= PThisMnt^.WepId;
    if (HCAnnexShift(ThisWepId)) =  MULTI_FLAG
    then
//  Multi Mounts
    begin
        PThisMulti:= HCAnnexHelper.HCGetAnnexZ2(ThisWepId);
        intC:= 0;
        while (PThisMulti^.WepQty[intC] > 0) do
        begin
         //
        SGListBoxUnitInfo.Items.Add(IntToStr(intC + 1) + '/ WepID: ' + IntToStr(PThisMulti^.WepId[intC]));

          case (HCAnnexShift(PThisMulti^.WepId[intC])) of
          GUN_FLAG:
            begin
            PHCAnnexC1:= HCAnnexHelper.HCGetAnnexC1(PThisMulti^.WepId[intC]);
            strWepName:= Format('%s; ARange: %d NM, SRange: %d NM',
              [ PHCAnnexC1^.ClassName, (PHCAnnexC1^.AirRange div 10), (PHCAnnexC1^.SurfRange div 10)]);
            end;  //   240405 more detail
          MISSILE_FLAG:
            begin
            PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(PThisMulti^.WepId[intC]);
            strWepName:= Format('%s; ARange: %d NM, SRange: %d NM, MinRange: %d NM',[PHCAnnexD1^.ClassName,
      (PHCAnnexD1^.AirRange div 10), (PHCAnnexD1^.SurfRange div 10), (PHCAnnexD1^.MinRange div 10)]);
            //  insertnmin range   220230513   22021117
            end;
          ASW_FLAG:
          begin
          PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(PThisMulti^.WepId[intC]);
          strWepName:= Format('%s: MaxRange: %d MinRange: %d',
              [PHCAnnexE1^.ClassName, (PHCAnnexE1^.MaxRange div 10), (PHCAnnexE1^.MinRange div 10)]);
          end;
          TORP_FLAG:
          begin
          PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(PThisMulti^.WepId[intC]);
          strWepName:= Format('%s; MaxRange: %d/%d MaxDepth %s',
            [PHCAnnexF1^.ClassName, (PHCAnnexF1^.MaxRange[0] div 10), (PHCAnnexF1^.MaxRange[1] div 10),
            HCAltBand2String(PHCAnnexF1^.MaxDepth)]);
          end;
          ATOG_FLAG:
          begin
          PHCAnnexG1:= HCAnnexHelper.HCGetAnnexG1(PThisMulti^.WepId[intC]);
          strWepName:= PHCAnnexG1^.ClassName;
          end;
          ECM_FLAG:
          begin
          PHCAnnexG2:= HCAnnexHelper.HCGetAnnexG2(PThisMulti^.WepId[intC]);
          strWepName:= PHCAnnexG2^.ClassName;
          end;
          else
            strWepName:= format('misc - WepID %d',[ThisWepId]);
           end;
           //    now print out data for multi mount this weapon

           SGListBoxUnitInfo.Items.Add(format('  - %d of %s',
            [PThisMulti^.WepQty[intC], strWepName]));   //  20230503 include current load and range could add thiswepid number here
            intC:= intC + 1;

        end;     //  end one weapon of multi mount
        strWepName:= '';  //  needs to be reset to nil so as not to list at end of multi mount

    end   //;      // end case of multi mount


    else  //     must be a single mount   PThisMount = annex PThisMnt = ship mount
          //  need to separate air units and not look up annex-NumRoundsMnt
    begin
    case (HCAnnexShift(ThisWepId)) of
    GUN_FLAG:
      begin
      PHCAnnexC1:= HCAnnexHelper.HCGetAnnexC1(ThisWepId);
      strWepName:=  Format('%d of %s: ARange: %d NM, SRange %d NM',
      [(PThisMount^.NumRoundsMnt * PThisMount^.NumMounts), PHCAnnexC1^.ClassName,
      (PHCAnnexC1^.AirRange div 10), (PHCAnnexC1^.SurfRange div 10)]);    // PThisMnt^.Ammo_c[0]    240303
      end;
    MISSILE_FLAG:
      begin
      PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(ThisWepId);
      strWepName:= Format('%d of %s; ARange: %d NM, SRange: %d NM, MinRange: %d NM',[PThisMount^.NumRoundsMnt * PThisMount^.NumMounts,
      PHCAnnexD1^.ClassName, (PHCAnnexD1^.AirRange div 10), (PHCAnnexD1^.SurfRange div 10),
      (PHCAnnexD1^.MinRange div 10)]);
            //  insertnmin range   220230513 insert ARange n SRange 20231117   240306 add intitial mount rounds (and below)
      end;
    ASW_FLAG:
    begin
    PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(ThisWepId);
    strWepName:= Format('%d of %s: MaxRange: %d',[(PThisMount^.NumRoundsMnt * PThisMount^.NumMounts * PThisMount^.NumTubes),
    PHCAnnexE1^.ClassName, (PHCAnnexE1^.MaxRange div 10)]);
    end;
    TORP_FLAG:
    begin
    PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(ThisWepId);
    strWepName:= Format('%d of %s: MaxRange: %d/%d, maxDepth: %s',
        [(PThisMount^.NumRoundsMnt * PThisMount^.NumMounts), PHCAnnexF1^.ClassName,
        (PHCAnnexF1^.MaxRange[0] div 10), (PHCAnnexF1^.MaxRange[1] div 10),
            HCAltBand2String(PHCAnnexF1^.MaxDepth)]); //  240405 more detail
    end;
    ATOG_FLAG:
    begin
    PHCAnnexG1:= HCAnnexHelper.HCGetAnnexG1(ThisWepId);
    strWepName:= 'weptype ' + intToStr(PHCAnnexG1^.WType) + '/' + PHCAnnexG1^.ClassName;
    end;
    ECM_FLAG:
    begin
    PHCAnnexG2:= HCAnnexHelper.HCGetAnnexG2(ThisWepId);
    strWepName:= PHCAnnexG2^.ClassName;
    end;
    else
      strWepName:= format('misc - WepID %d',[ThisWepId]);
    end;  //  end look at non multi mount 20231117
    //  now print out non multi mount data   (already printed multi wep data?)
      SGListBoxUnitInfo.Items.Add('  ' + 'WepID: ' + IntToStr(ThisWepID) + ',  '
        + strWepName);
      strWepName:= '';
    end;   // end single mount  with valid wepID
       end  //; // valid weaponID     240404 moved valid weap id test
       else
       SGListBoxUnitInfo.Items.Add('    DummyWep');    //  was INVALID_ID
                            //  ends that mount
    PThisMnt:= PThisMnt^.next;
    end;       // end  each mount
  end;       // end if mounts
//

  if (PSelectedUnit^.Mags <> nil) then
  begin
  SGListBoxUnitInfo.Items.Add('* Magazines *');
  //if (isShip = True)                       //  240319 listing mag info
SGListBoxUnitInfo.Items.Add(format('1stmag @ %d, NoOfMags # %d',[PHCAnnexA1^.MagStart, PHCAnnexA1^.MagCount]));
  PThisMag:= PSelectedUnit^.Mags;
  while (PThisMag <> nil) do
    begin
    //  get annex info
    case (HCAnnexShift(PThisMag^.WepId)) of
    GUN_FLAG:
      begin
      PHCAnnexC1:= HCAnnexHelper.HCGetAnnexC1(PThismag^.WepId);
      strWepName:= PHCAnnexC1^.ClassName;
      end;
    MISSILE_FLAG:
      begin
      PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(PThismag^.WepId);
      strWepName:= PHCAnnexD1^.ClassName;
      end;
    ASW_FLAG:
    begin
    PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(PThismag^.WepId);
    strWepName:= PHCAnnexE1^.ClassName;
    end;
    TORP_FLAG:
    begin
    PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(PThismag^.WepId);
    strWepName:= PHCAnnexF1^.ClassName;
    end;
     // moreweapons?
    else
      strWepName:= 'unknown weapon ID: ' + IntToStr(PThisMag^.WepId)
    end;
    SGListBoxUnitInfo.Items.Add(format('   WepID: %d, %s: Count: %d, ReloadTime: %d',[PThisMag^.WepId, strWepName, PThisMag^.Count, PThisMag^.ReloadTime]));
//  we could amend magazine data here
    PThisMag:= PThisMag^.next;
    end;
  end;   //end mags

  end
  else
  begin
    SGListBoxUnitInfo.Items.Clear;
    SGListBoxUnitInfo.Items.Add('bad unit selection?'); // something strange went on
  end;
  end    // end that the group was valid
else begin
         SGlbxGroups.Items.Clear;
         SGlbxGroups.Items.Add('Selected Unit from Invalid Group');
         SGlbxUnits.Items.Clear;
         SGListBoxUnitInfo.Clear;
         SGlblUnitIDName.Caption:= '';           //  clear all boxs until a unit is selected  20230503
         SGlblClassName.Caption:= '';
     end;        //  was invalid group


end;

end.

