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)
    GTmemDLLcalls: TMemo;
    GTtshDeadUnits: TTabSheet;
    GTtshDLLcalls: TTabSheet;
    GTtshSonoBuoy: TTabSheet;
    GTtshWeatherGroups: TTabSheet;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    GTlblHMS: TLabel;
    MainMenu1: TMainMenu;
    tshUnitShowingSide: TTabSheet;
    USSckbEnabled: TCheckBox;
    USSedtLines: TSpinEdit;
    USSlblLines: TLabel;
    USSmemMsgLog: TMemo;
    VClstbxItems: TListBox;
    SGlblClassName: TLabel;
    SGButtonRefresh: TButton;
    GTcklbAutoP: TCheckListBox;
    GTckbAutoP: TCheckBox;
    GTbtnResume: TButton;
    GTckbPause: TCheckBox;
    GTpctStructs: TPageControl;
    GTtshStartGroup: TTabSheet;
    GTtshHarpEvents: TTabSheet;
    Label1: TLabel;
    GTlblGameTime: TLabel;
    GTHEEventList: TListBox;
    GEHEmemDetail: TMemo;
    GTlblGameTimeLeft: TLabel;
    SGListBoxUnitInfo: TListBox;
    tshGT: TTabSheet;
    tshVC: TTabSheet;
    VCckbEnabled: TCheckBox;
    VCedtLines: TSpinEdit;
    VClblLines: TLabel;
    SGlblUnitIDName: TLabel;
    SGpnlUnit: TPanel;
    SGlblGroups: TLabel;
    SGlblUnits: TLabel;
    SGlbxGroups: TListBox;
    SGlbxUnits: TListBox;
    SGpnl1: TPanel;
    SGlblDesc: TLabel;
    memDLLInit: TMemo;
    SLckbEnabled: TCheckBox;
    SGckbEnabled: TCheckBox;
    SLedtLines: TSpinEdit;
    SGedtLines: TSpinEdit;
    SLlblLines: TLabel;
    SGlblLines: TLabel;
    SLmemMsgLog: TMemo;
    SGmemMsgLog: TMemo;
    tshStartGroup: TTabSheet;
    tshDLLInit: TTabSheet;
    tshScenLoad: TTabSheet;
    tshTimeFactor: TTabSheet;
    tshUnitShowing: TTabSheet;
    TFckbEnabled: TCheckBox;
    TFedtLines: TSpinEdit;
    TFlblLines: TLabel;
    TFmemMsgLog: TMemo;
    MLckbEnabled: TCheckBox;
    USckbEnabled: TCheckBox;
    MLlblLines: TLabel;
    USedtLines: TSpinEdit;
    MLmemMsgLog: TMemo;
    USlblLines: TLabel;
    PageControl1: TPageControl;
    MLedtLines: TSpinEdit;
    tshMsgLog: TTabSheet;
    USmemMsgLog: TMemo;
    VCmemMsgLog: TMemo;
    SessionSze: TXMLPropStorage;
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormDestroy(Sender: TObject);
    procedure GTbtnResumeClick(Sender: TObject);
    procedure GTHEEventListSelectionChange(Sender: TObject; User: boolean);
//    procedure HHQueueEventMessageClick(Sender: TObject);
    procedure SGButtonRefreshClick(Sender: TObject);
    procedure SGlbxGroupsSelectionChange(Sender: TObject; User: boolean);
    procedure SGlbxUnitsSelectionChange(Sender: TObject; User: boolean);
    procedure EventmemDetailWrite;
    procedure UNbtnResumeClick(Sender: TObject);
    function SecsToHRMinSec(GTNowSecs: LongInt):String;

  private
    { private declarations }
  public
    { public declarations }
    // ALE 20130812 Big bad pointers that hold most of the game data
    PStartGroup, PSelectedGroup: PHCGroup;
    PHarpEventHead, PEvent: PHCHarpoonEvent;
    PSonobuoyRegionHead: PHCSonobuoyRegion;
    PAllDeadUnitsPtr: PHCDeadListItem;
    PWeatherGroups: PHCGroup;
    PVictoryConditionsList: 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;
    gGTNow: LongInt;

  end;

var
  frmMain: TfrmMain;


implementation

uses uHCDefines, uHCEventHelpers;

{$R *.lfm}

{ TfrmMain }

function TfrmMain.SecsToHRMinSec(GTNowSecs: LongInt):String;
var
  intHr, intMin, intSec, intRem: Integer;

begin
   intHr:= GTNowSecs div 3600;
   intRem:= GTNowSecs mod 3600;
   intMin:= intRem div 60;
   intSec:= intRem mod 60;
   result:=(Format('GTNow: %d: %d: %d',[intHr, intMin, intSec]));
end;

procedure TfrmMain.SGlbxGroupsSelectionChange(Sender: TObject; User: boolean);
var
  strSel: String;
  PHCGThis: PHCGroup;
  PHCUThis: PHCUnit;
begin
  // ALE 20130317 User selected a group, pull up unit list.
  strSel := SGlbxGroups.Items[SGlbxGroups.ItemIndex];
  PHCGThis := PStartGroup;
  while (PHCGThis <> nil) do
  begin
    if (strSel = PHCGThis^.id) then
       break;
    PHCGThis := PHCGThis^.toSouth;
  end;
  // ALE 20130317 in theory we have the group from which
  //  we can enumerate the units.
  SGlblUnitIDName.Caption:= '';
  SGlblClassName.Caption:=  '';
  SGListBoxUnitInfo.Items.Clear;
  SGlbxUnits.Items.Clear;
  if PHCGThis <> nil then
  begin
  PSelectedGroup:= PHCGThis;
  SGlbxUnits.Sorted := True;
  PHCUThis := PHCGThis^.Units;
  while (PHCUThis <> nil) do
  begin
    SGlbxUnits.Items.Add(Format('%2.2s%0.3d %s', [PHCGThis^.id, PHCUThis^.id, PHCUThis^.name]));
    PHCUThis := PHCUThis^.next;
  end;
  end
  else
  SGlbxUnits.Items.Add('Selected Group no longer valid'); // test for valid group
end;

procedure TfrmMain.GTbtnResumeClick(Sender: TObject);
begin
  GTHEEventList.Clear;      // want to leave so as to have last event of interest visible
  GEHEmemDetail.Clear;         //  20230406  changed mind, want cleared
  GTckbPause.Checked:=False;
  GTbtnResume.Enabled:=False;
  GTckbPause.Enabled:=True;
  Byte(PDLLBusy^) := CFALSE; // ALE 20130816
  WindowState:= wsMinimized;      // crash?
end;

procedure TfrmMain.GTHEEventListSelectionChange(Sender: TObject; User: boolean);
var
  strSel: String;
  PHCGThis: PHCGroup;
  PHCUThis: PHCUnit;
  intIndx: Integer;

begin
  // ALE 20130317 User selected a group, pull up unit list.
  intIndx:= Pos('UID:', GTHEEventList.Items[GTHEEventList.ItemIndex]);
  strSel := Copy(GTHEEventList.Items[GTHEEventList.ItemIndex], intIndx + 4, 8);
  PEvent := PHarpEventHead;
  while (PEvent <> nil) do
  begin
    if (strSel = Format('%p', [PEvent])) then
       break;
    PEvent := PEvent^.next;
  end;
  If (PEvent = nil) then
     GEHEmemDetail.Lines.Add('error, no event')
     else
     EventmemDetailWrite;
end;

procedure TfrmMain.EventmemDetailWrite;
var
  PEventMessage: PHCMessageEvent;
  PRefuelEvent: PHCAirRefuelEvent;
  PInterceptEvent: PHCInterceptEvent;
  PAirPatrolEvent: PHCAirPatrolEvent;
  PAirAttackEvent: PHCAirAttackEvent;
  PLaunchLandEvent: PHCLaunchLandEvent;
  PLaunchAirEvent: PHCLaunchAirEvent;
  PEnemyAIEvent: PHCEnemyAIEvent;
  PSpeedAltEvent: PHCSpeedAltEvent;
  PAltCourseEvent: PHCAltCourseEvent;
  PAttackEvent: PHCAttackEvent;
  PNukeRelEvent: PHCNukeFreeEvent;
  N, intEType, intTotFuel: Integer;
  strEType, strEGroupID, strSide : string;
  strUnitID: uchar;

begin
// ALE 20130816 We found the event, do something.
GEHEmemDetail.Clear;
//GEHEmemDetail.Lines.Add(Format('Pointer to Event: 0x%p', [PEvent]));
// if PEvent^.next <> nil then
//  GEHEmemDetail.Lines.Add(Format('Pointer to next Event: 0x%p', [PEvent^.next]));
if PEventUnit <> nil
  then strUnitID:= PEventUnit^.id
  else strUnitID:= 255;
if PEvent^.ourGroup <> nil
  then strEGroupID:= PHCGroup(PEvent^.ourGroup)^.id
  else strEGroupID:= '  ';
GEHEmemDetail.Lines.Add(Format('Event Type: %s',
  [HCEventType2String(PEvent^.flag AND CommandMask)]));      // vers update  / flag AND CommandMask
GEHEmemDetail.Lines.Add(Format('Group:unit the Event applies to %2.2s : %3.3d',
  [strEGroupID, strUnitID]));
//  GEHEmemDetail.Lines.Add(Format('Pointer to DataPtr: 0x%p', [PEvent^.DataPtr]));
N:= PEvent^.Time - 100000;
GEHEmemDetail.Lines.Add(Format('Event Time: %s: now + %s sec',
  [SecsToHrMinSec(N), SecsToHrMinSec(PEvent^.Time - gGTNow)]));
GEHEmemDetail.Lines.Add(Format('Event Time Type: %s',
  [HCEventTimeType2String(PEvent^.flag AND TimeMask)]));  //  vers update /.flag AND TimeMask
//  GEHEmemDetail.Lines.Add(Format('Event in_scroll_flag: %d', [PEvent^.in_scroll_flag]));
GEHEmemDetail.Lines.Add('................');
//ddt now, event specific additional information
// message event
if (PEvent^.flag AND CommandMask = MESSAGE_EVENT) then        //  vers update /flag AND CommandMask
  begin
    PEventMessage := PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('Message: %s', [PEventMessage^.Message]));

  end;
//  Refuel event
if (PEvent^.flag AND CommandMask = AIR_REFUEL_EVENT) then    //  vers update / flag and CommandMask
begin
  PRefuelEvent:= PEvent^.DataPtr;
  intTotFuel:= (PEventUnit^.Air^.FuelToOffload) * strToInt(Format('%2.2d',[PRefuelEvent^.num_tankers]));
  GEHEmemDetail.Lines.Add(Format('Fueling Unit: %3.3d', [PRefuelEvent^.fuelingUnit]));
  GEHEmemDetail.Lines.Add(Format('Tanker Type: %3.3d',[PRefuelEvent^.which_plane_type]));
  GEHEmemDetail.Lines.Add(Format('Number of Tankers: %2.2d', [PRefuelEvent^.num_tankers]));
  GEHEmemDetail.Lines.Add(Format('Fueling: %3.3d', [PRefuelEvent^.now_refueling]));   // 0=No, 1= yes
  GEHEmemDetail.Lines.Add(Format('Original Refuel Range: %4.4d', [PRefuelEvent^.fuel_range]));
  GEHEmemDetail.Lines.Add(Format('Remaining Refuel Range %4.4d',[intTotFuel]));
  GEHEmemDetail.Lines.Add('. . . . . . . .');
  // now do each unit refuel info
  N := 0;
  repeat
  begin
  GEHEmemDetail.Lines.Add(Format('# %d: unit %3.3d', [N, PRefuelEvent^.planestofuel[N]]));
  If PRefuelEvent^.planestofuel[N] = 255 then
    GEHEmemDetail.Lines.Add('Refuel cycle finished')
    else
    if
      PRefuelEvent^.planestofuel[N] = 205 then
      GEHEmemDetail.Lines.Add('Awaiting start of refuel?')
      else
      GEHEmemDetail.Lines.Add(Format('Per Plane Fuel: %4.4d', [PRefuelEvent^.fuel_per_plane[N]]));
  N := N+1;
  end;
  until  PRefuelEvent^.planestofuel[N-1] > 200;
end;
//  intercept event
if (PEvent^.flag AND CommandMask = INTERCEPT_EVENT) then    //  flag and CommandMask
  begin
    PInterceptEvent:= PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('Target: %2.2s-%3.3d',
        [PInterceptEvent^.targetGroup, PInterceptEvent^.targetUnit]));
    GEHEmemDetail.Lines.Add(Format('Irange: %d',[PInterceptEvent^.Irange]));
    GEHEmemDetail.Lines.Add(Format('action: %d',[PInterceptEvent^.action]));
    GEHEmemDetail.Lines.Add(Format('flag: %d, data: %d',[PInterceptEvent^.flag, PInterceptEvent^.data]));
    GEHEmemDetail.Lines.Add(Format('dummies: %d, %d',[PInterceptEvent^.Dummy1, PInterceptEvent^.Dummy2]));
  end;
// air patrol event
if (PEvent^.flag AND CommandMask = AIR_PATROL_EVENT) then     // flag and CommandMask
  begin
    PAirPatrolEvent:= PEvent^.DataPtr;
    intEType:= PAirPatrolEvent^.PatrolType;
    case intEType of
    1: strEType:= 'ASUW';
    2: strEType:= 'ASW';
    3: strEType:= 'AAW';
    4: strEType:= 'AEW/radar/ESM';
    5: strEType:= 'EW';
    else strEType:= 'unknown';
    end;
    GEHEmemDetail.Lines.Add('Type: ' + strEType);
    GEHEmemDetail.Lines.Add(Format('Plane Annex: %d, Mission: %d',[PAirPatrolEvent^.PlaneID, PAirPatrolEvent^.LoadoutIDX]));
    GEHEmemDetail.Lines.Add(Format('Number Patrolling: %2.2d, Status: %1.1d',[PAirPatrolEvent^.Numer, PAirPatrolEvent^.Status]));
    GEHEmemDetail.Lines.Add(Format('Rings: %d',[PAirPatrolEvent^.Rings]));
    // from centre outwards = 1,2,4,8 if occupy multi rings then add values
    GEHEmemDetail.Lines.Add(Format('Sectors: %d',[PAirPatrolEvent^.Sectors]));
    // from 1 o'clock clockwise = 1,2,4,8,16,32,64,128 add for multi sectors
  end;
// AIR ATTACK EVENT
if (PEvent^.flag AND CommandMask = AIR_ATTACK_EVENT) then  // flag and CommandMask
  begin
    PAirAttackEvent:= PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('Target: %3.3s',[PAirAttackEvent^.targetGroup]));
    GEHEmemDetail.Lines.Add(Format('eventType:%3.3d',[PAirAttackEvent^.eventType]));
    GEHEmemDetail.Lines.Add(Format('attackRange: %4d, attackType: %2.2d',[PAirAttackEvent^.attackRange, PAirAttackEvent^.attackType]));
    GEHEmemDetail.Lines.Add(Format('Flag %2.2d, data:%2.2d, dipping: %1.1d',[PAirAttackEvent^.flag, PAirAttackEvent^.data, PAirAttackEvent^.dipping]));
  end;
// Launch Land Event
if (PEvent^.flag AND CommandMask = LAUNCHLAND_EVENT) then  // flag and CommandMask
  begin
    PLaunchLandEvent:= PEvent^.DataPtr;
    intEType:= PLaunchLandEvent^.launch;
    case intEType of
    0: strEType:= 'landing';
    1: strEtype:= 'launching';
    end;
    GEHEmemDetail.Lines.Add(Format('base: %2.2s-%3.3d',[PLaunchLandEvent^.baseGroup,
    PLaunchLandEvent^.baseUnit]));
    GEHEmemDetail.Lines.Add('aircraft is ' + strEType);
    GEHEmemDetail.Lines.Add(Format('%3d-%s',[PLaunchLandEvent^.planes^.PlatNow,
    PLaunchLandEvent^.planes^.name]));
  end;
//  Launch Air Event
If (PEvent^.flag AND CommandMask = LAUNCH_EVENT) then     // flag and CommandMask
  begin
    PLaunchAirEvent:= PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('number: %3.3d, unit: %3.3d, Target: %3.3s ', [PLaunchAirEvent^.numberAircraft, PLaunchAirEvent^.UnitID, PLaunchAirEvent^.targetGroup]));
  end;
// Enemy AI event
if (PEvent^.flag AND CommandMask = ENEMY_AI_EVENT) then
  begin
    PEnemyAIEvent:= PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('Target: %3.3s; order: %3.3d',[PEnemyAIEvent^.targetGroup, PEnemyAIEvent^.order]));
    GEHEmemDetail.Lines.Add(Format('Effect subtype/ range/ data: %2.2d/ %4.4d/ %3.3d',[PEnemyAIEvent^.etype, PEnemyAIEvent^.range, PEnemyAIEvent^.data]));
  end;
//  Speed Altitude change
if  (PEvent^.flag AND CommandMask = ALT_SPEED_EVENT) then
  begin
    PSpeedAltEvent:= PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('New speed: %4.4d, Altitude: %1.1d, Throttle %1.1d',[PSpeedAltEvent^.newSpeed,
    PSpeedAltEvent^.newAltBand, PSpeedAltEvent^.newThrottle]));
  end;
//  Alter Course
if  (PEvent^.flag AND CommandMask = ALT_COURSE_EVENT) then
  begin
    PAltCourseEvent:= PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('course - new: %3.3d, old: %3.3d',[PAltCourseEvent^.newcourse, PAltCourseEvent^.oldcourse]));
  end;
// Attack Event
if (PEvent^.flag AND CommandMask = ATTACK_EVENT) then
  begin
    PAttackEvent:= PEvent^.DataPtr;
    GEHEmemDetail.Lines.Add(Format('Target: %s-%3.3d',[PAttackEvent^.TargetGroup, PAttackEvent^.TargetID]));
    GEHEmemDetail.Lines.Add(Format('Attaking unit: %3.3d, %2.2d Rounds, %3.3d secs to fire',[PAttackEvent^.UnitID, PAttackEvent^.numberRounds, PAttackEvent^.deltaTime]));
  end;
// nuke release
if (PEvent^.flag AND CommandMask = NUKE_FREE_EVENT)  then
  begin
    PNukeRelEvent:= PEvent^.DataPtr;
    case  PNukeRelEvent^.Side  of
    0: strSide:= 'Blue';
    1: strSide:= 'Red';
    2: strSide:= 'Neutral';
    end;
    GEHEmemDetail.Lines.Add(Format('Nuke Release for %s',
        [strSide]));
  end;
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;
  PTGroup := PStartGroup;
  while (PTGroup <> nil) do
    begin
    SGlbxGroups.Items.Add(PTGroup^.id);
    PTGroup := PTGroup^.toSouth;
    end;
end;

procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin

end;

//procedure TfrmMain.DUbtnUpdateClick(Sender: TObject);
//var
//  PThisDeadUnit: PHCDeadListItem;
//  strClass, strUname: String;
//  intCarrierKill, intShipKill, intSubKill,
//  intPlaneKill, intHeloKill,
//  intBaseKill,
//  intFixKill, intMobKill,
//  intArmKill, intUnarmKill,
//  intS: integer;
//  ThisA1_disk: PHCAnnexA1_disk;
//begin
//  DUmemDetail.Lines.Clear;
//  for intS := 0 to 2 do
//  begin
//  case intS of
//  0: DUmemDetail.Lines.Add('Blue Side');
//  1: DUmemDetail.Lines.Add('Red Side');
//  2: DUmemDetail.Lines.Add('Neutral Side');
//  end;
//  PThisDeadUnit:= PAllDeadUnitsPtr;
//  intCarrierKill:= 0;
//  intShipKill:= 0;
//  intSubKill:= 0;
//  intPlaneKill:= 0;
//  intHeloKill:=0;
//  intBaseKill:= 0;
//  intFixKill:= 0;
//  intMobKill:= 0;
//  intArmKill:= 0;
//  intUnarmKill:= 0;
//  while PThisDeadUnit <> nil do
//  begin
//  if PThisDeadUnit^.side = intS then
//    begin
//    case PThisDeadUnit^.typeindex of
//    0: begin
//        strClass:= 'Carrier';
//        intCarrierKill:= intCarrierKill + PThisDeadUnit^.count;
//       end;
//    1: begin
//        strClass:= 'Ship';
//        intShipKill:= intShipKill + PThisDeadUnit^.count;
//        end;
//    2: begin
//        strClass:= 'Submarine';
//        intSubKill:= intSubKill + PThisDeadUnit^.count;
//       end;
//    3: begin
//        strClass:= 'Plane';
//        intPlaneKill:= intPlaneKill + PThisDeadUnit^.count;
//       end;
//    4: begin
//        strClass:= 'Helicopter';
//        intHeloKill:= intHeloKill + PThisDeadUnit^.count;
//       end;
//    5: begin
//        strClass:= 'Base';
//        intBaseKill:= intBaseKill + PThisDeadUnit^.count;
//       end;
//    6: begin
//        strClass:= 'AD Fixed';
//        intFixKill:= intFixKill + PThisDeadUnit^.count;
//       end;
//    7: begin
//        strClass:= 'AD Mobile';
//        intMobKill:= intMobKill + PThisDeadUnit^.count;
//       end;
//    8: begin
//        strClass:= 'Armoured';
//        intArmKill:= intArmKill + PThisDeadUnit^.count;
//       end;
//    9: begin
//        strClass:= 'Unarmoured';
//        intUnarmKill:= intUnarmKill + PThisDeadUnit^.count;
//       end;
//    end;
//  // insert look for class details
//  case HCAnnexShift(PThisDeadUnit^.Annex) of
//  SHIP_FLAG:
//    begin
//    ThisA1_disk:= HCAnnexHelper.HCGetAnnexA1(PThisDeadUnit^.Annex);
//    strUname:= ThisA1_disk^.ClassName;
//    end;
//  PLANE_FLAG:
//    begin
//    strUname:= PHCAnnexB1_disk(HCAnnexHelper.HCGetAnnexB1(PThisDeadUnit^.Annex))^.ClassName;
//    end;
//  BASE_FLAG:
//    strUname:= PHCAnnexP1_disk(HCAnnexHelper.HCGetAnnexP1(PThisDeadUnit^.Annex))^.Name;
//  SUB_FLAG:
//    strUname:= PHCAnnexA2_disk(HCAnnexHelper.HCGetAnnexA2(PThisDeadUnit^.Annex))^.ClassName;
//  else strUname:= 'unknown';
//  end;
//  // end look for class detail
//  DUmemDetail.Lines.Add(format('%s (%s): %d destroyed',[strUname, strClass, PThisDeadUnit^.count]));
//  end;
//  PThisDeadUnit:= PThisDeadUnit^.next;
//  end;   // end loop deadunitptr
//  DUmemDetail.Lines.Add('Summary');
//if intCarrierKill > 0 then  DUmemDetail.Lines.Add('Carriers: ' + intTostr(intCarrierKill));
//if intShipKill > 0 then  DUmemDetail.Lines.Add('Ships: ' + intTostr(intShipKill));
//if intSubKill > 0 then  DUmemDetail.Lines.Add('Submarines: ' + intTostr(intSubKill));
//if intPlaneKill > 0 then  DUmemDetail.Lines.Add('Planes: ' + intTostr(intPlaneKill));
//if intHeloKill > 0 then  DUmemDetail.Lines.Add('Helicopters: ' + intTostr(intHeloKill));
//if intMobKill > 0 then  DUmemDetail.Lines.Add('AD mobile: ' + intTostr(intMobKill));
//if intFixKill > 0 then  DUmemDetail.Lines.Add('AD fixed: ' + intTostr(intFixKill));
//if intArmKill > 0 then  DUmemDetail.Lines.Add('Armoured: ' + intTostr(intArmKill));
//if intUnarmKill > 0 then  DUmemDetail.Lines.Add('Unarmoured: ' + intTostr(intUnarmKill));
//  end;  // finished all sides
//end;
          //  want to put this back?

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
end;

procedure TfrmMain.SGlbxUnitsSelectionChange(Sender: TObject; User: boolean);
var
  strSel, strDepthAlt, strShow, strWepName, strPlaneLoadout: String;
  PHCUThis: PHCUnit;
  PThisMnt: PHCMntRec;
  PThisMag: PHCMagRec;
  PmyPlanes: PHCPlaneRec;
  RLat, RLon: Double;
  intDepthAlt, intShow, intC: integer;
  isTanker, isSub: Boolean;

  ThisWepID:  ID;
  PThisLoadout: PHCAnnexY1_disk;
  PThisMount: PHCAnnexZ1_disk;
  PThisMulti: PHCAnnexZ2_disk;

  PHCAnnexA1: PHCAnnexA1_disk;
  PHCAnnexA2: PHCAnnexA2_disk;
  PHCAnnexB1: PHCAnnexB1_disk;
  PHCAnnexP1: PHCAnnexP1_disk;
  PHCAnnexC1: PHCAnnexC1_disk;
  PHCAnnexD1: PHCAnnexD1_disk;
  PHCAnnexE1: PHCAnnexE1_disk;
  PHCAnnexF1: PHCAnnexF1_disk;
  PHCAnnexG1: PHCAnnexG1_disk;
  PHCAnnexG2: PHCAnnexG2_disk;

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
  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;
    PSelectedUnit := PHCUThis;
    SGListBoxUnitInfo.Items.Clear;
    // now add class name using annex
      case (HCAnnexHelper.HCAnnexShift(PSelectedUnit^.Annex)) of
          SHIP_FLAG:
          begin
            PHCAnnexA1 := HCAnnexHelper.HCGetAnnexA1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := 'Ship Class Name: ' + PHCAnnexA1^.ClassName;
          end;
          SUB_FLAG:
          begin
            PHCAnnexA2 := HCAnnexHelper.HCGetAnnexA2(PSelectedUnit^.Annex);
            SGlblClassName.Caption := 'Submarine Class Name: ' + PHCAnnexA2^.ClassName;
            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
            PHCAnnexB1 := HCAnnexHelper.HCGetAnnexB1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := 'Aircraft Class Name: ' + PHCAnnexB1^.ClassName;
          end;
          BASE_FLAG:
          begin
            PHCAnnexP1 := HCAnnexHelper.HCGetAnnexP1(PSelectedUnit^.Annex);
            SGlblClassName.Caption := 'Base Name: ' + PHCAnnexP1^.Name;
          end;
          else
            SGlblClassName.Caption := '';
        end;
    // finished getting class name form annex
    SGlblUnitIDName.Caption := Format('%2.2s%0.3d %s',[PSelectedGroup^.id, PSelectedUnit^.id, PSelectedUnit^.name]);
    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]));
    SGListBoxUnitInfo.Items.Add(format('course: %3.3d, kts: %d, MaxKts: %d',[PSelectedUnit^.course, PSelectedUnit^.kts, PSelectedUnit^.maxspeed]));
    if isSub then
    SGListBoxUnitInfo.Items.Add('Depth: ' + strDepthAlt);
    SGListBoxUnitInfo.Items.Add(format('Damage Points Now/Orig: %d/ %d',[PSelectedUnit^.CurrDp, PSelectedUnit^.OrigDp]));

// test for air or missile units
  if (PSelectedUnit^.Air <> nil) then
  begin
  intDepthAlt:=  PSelectedUnit^.AltBand ;
  case intDepthAlt of
       11: strDepthAlt:= 'VLow';
       12: strDepthAlt:= 'Low';
       13: strDepthAlt:= 'Med';
       14: strDepthAlt:= 'High';
       15: strDepthAlt:= 'Vhigh';
  end;
    SGListBoxUnitInfo.Items.Insert(0, 'Aircraft Unit');
    SGListBoxUnitInfo.Items.Insert(1,'Altitude: ' + strDepthAlt);
    SGListBoxUnitInfo.Items.Add(format('Aircraft number orig/now: %2.2d/ %2.2d',[PSelectedUnit^.Air^.PlatStart, PSelectedUnit^.Air^.PlatNow]));
    SGListBoxUnitInfo.Items.Add(format('base: %2.2s-%3.3d, %s',[PHCGroup(PHCUnit(PSelectedUnit^.Air^.HomeUnit)^.Group)^.id, PHCUnit(PSelectedUnit^.Air^.HomeUnit)^.id, PHCUnit(PSelectedUnit^.Air^.HomeUnit)^.name]));
    SGListBoxUnitInfo.Items.Add(format('Combat Flag: %2.2d', [PSelectedUnit^.CombatFlag]));
    //  test
    if ((PHCAnnexB1^.UnitFlags AND UF_B1_NOE) > 0) then
       SGListBoxUnitInfo.Items.Add('NOE capable');
  //have annex, get more info
    SGListBoxUnitInfo.Items.Add(format('Max alt band: %d',[PHCAnnexB1^.MaxAlt]));
    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]]));
  //

    if PSelectedUnit^.Air^.FuelToOffload > 0 then
    SGListBoxUnitInfo.Items.Add(format('tanker fuel remaining: %d per tanker',[PSelectedUnit^.Air^.FuelToOffload]));
  end
  else
  if (PSelectedUnit^.Missile <> nil) then
  begin
    intDepthAlt:=  PSelectedUnit^.AltBand ;
  case intDepthAlt of
       11: strDepthAlt:= 'VLow';
       12: strDepthAlt:= 'Low';
       13: strDepthAlt:= 'Med';
       14: strDepthAlt:= 'High';
       15: strDepthAlt:= 'Vhigh';
       end;
    SGListBoxUnitInfo.Items.Insert(0, 'Missile Unit - Altitude: ' + strDepthAlt);
    SGListBoxUnitInfo.Items.Add(format('Number Now/Original: %d/ %d, target: %2.2s-%3.3d - %s',
    [PSelectedUnit^.Missile^.PlatNow, PSelectedUnit^.Missile^.PlatStart, PHCGroup(PHCUnit(PSelectedUnit^.Missile^.targetUnit)^.Group)^.id, PHCUnit(PSelectedUnit^.Missile^.targetUnit)^.id, PHCUnit(PSelectedUnit^.Missile^.targetUnit)^.name]));
  end;
// end air missile unit test
//  test for landed air units
  if (PSelectedUnit^.myPlanes <> nil) then
  begin
    PmyPlanes:= PSelectedUnit^.myPlanes;
    SGListBoxUnitInfo.Items.Add('* Aircraft Landed *');
    while (PmyPlanes <> nil) do
    begin
      PThisLoadout:= HCAnnexHelper.HCGetAnnexY1(PmyPlanes^.LoadID);
      SGListBoxUnitInfo.Items.Add(format('%d-%s; range %d',[PmyPlanes^.PlatNow, PmyPlanes^.name, PThisLoadout^.Range]));
      intC := 0 ;
      while PThisLoadout^.WepQty[intC] > 0 do
    begin
        //find weapon type then name
     case (HCAnnexShift(PThisLoadout^.WepId[intC])) of
    GUN_FLAG:
      begin
      PHCAnnexC1:= HCAnnexHelper.HCGetAnnexC1(PThisLoadout^.WepId[intC]);
      strWepName:= PHCAnnexC1^.ClassName;
      end;
    MISSILE_FLAG:
      begin
      PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(PThisLoadout^.WepId[intC]);
      strWepName:= PHCAnnexD1^.ClassName;
      end;
    ASW_FLAG:
      begin
      PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(PThisLoadout^.WepId[intC]);
      strWepName:= PHCAnnexE1^.ClassName;
      end;
    TORP_FLAG:
      begin
      PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(PThisLoadout^.WepId[intC]);
      strWepName:= PHCAnnexF1^.ClassName;
      end;
    ATOG_FLAG:
      begin
      PHCAnnexG1:= HCAnnexHelper.HCGetAnnexG1(PThisLoadout^.WepId[intC]);
      strWepName:= PHCAnnexG1^.ClassName;
      end;
    ECM_FLAG:
      begin
      PHCAnnexG2:= HCAnnexHelper.HCGetAnnexG2(PThisLoadout^.WepId[intC]);
      strWepName:= PHCAnnexG2^.ClassName;
      end;
    else strWepName:= 'misc';
    end; //case   now have weapon name
        SGListBoxUnitInfo.Items.Add(format('   %d  %s',[PThisLoadout^.WepQty[intC], strWepName]));
        intC:= intC +1;
    end;    // now have weapon No/names listed  for this plane
      PmyPlanes:= PmyPlanes^.next;
    end;
  end;
// end test for landed air units
//
  if (PselectedUnit^.Mnts <> nil)  then                      // and (PSelectedUnit^.Air = nil)
  begin
  SGListBoxUnitInfo.Items.Add('* Mounts *');
  PThisMnt:= PselectedUnit^.Mnts;
  while (PThisMnt <> nil) do
    begin
// problem starts here, for aircraft units
    if (HCAnnexShift(PThisMnt^.MntId) = MOUNT_FLAG)  then
  begin
    PThisMount:= HCAnnexHelper.HCGetAnnexZ1(PThisMnt^.MntId);
    SGListBoxUnitInfo.Items.Add(format('%s: %d mounts; %d tubes, %d targets',
      [PThisMount^.ClassName, PThisMount^.NumMounts, PThisMount^.NumTubes,
       PThisMount^.NumTargets]));
    if PThisMount^.WepId <> Invalid_ID then  ThisWepID:= PThisMount^.WepId;
  end
    else // assume its an aircraft loadout
    begin
    if (HCAnnexShift(PThisMnt^.MntId) = LOADOUT_FLAG)  then   //find mission type
    begin
    PThisLoadout:= HCAnnexHelper.HCGetAnnexY1(PThisMnt^.MntId);
      case HCMissionMap[PThisLoadout^.MissionID] of
        Ord(THCMissionType.MISSION_TANKER): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Tanker';
        Ord(THCMissionType.MISSION_FERRY): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Ferry';
        Ord(THCMissionType.MISSION_ASSAULT): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Assault';
        Ord(THCMissionType.MISSION_PATROL): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Patrol';
        Ord(THCMissionType.MISSION_NUCLEAR): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Nuclear';
        Ord(THCMissionType.MISSION_STANDOFF): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Standoff';
        Ord(THCMissionType.MISSION_SEAD): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Sead';
        Ord(THCMissionType.MISSION_GUIDED): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Guided';
        Ord(THCMissionType.MISSION_UNGUIDED): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Unguided';
        Ord(THCMissionType.MISSION_ANTIRUN): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Anti Runway';
        Ord(THCMissionType.MISSION_ATA): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Intercept';
        Ord(THCMissionType.MISSION_ASW): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: ASW';
        Ord(THCMissionType.MISSION_AARMR): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Anti Armour';
        Ord(THCMissionType.MISSION_DECOY): SGListBoxUnitInfo.Items.Strings[0]:= 'Air Unit, Mission: Decoy';
      end;
    //end case of mission type
    end;   // end ID mission type
    if PThisMnt^.WepId <> Invalid_ID then  ThisWepID:= PThisMnt^.WepId;
    end;

    case (HCAnnexShift(ThisWepId)) of
      MULTI_FLAG:
    begin
          PThisMulti:= HCAnnexHelper.HCGetAnnexZ2(ThisWepId);
          intC:= 0;
          while (PThisMulti^.WepQty[intC] > 0) do
          begin
           //
           case (HCAnnexShift(PThisMulti^.WepId[intC])) of
    GUN_FLAG:
      begin
      PHCAnnexC1:= HCAnnexHelper.HCGetAnnexC1(PThisMulti^.WepId[intC]);
      strWepName:= PHCAnnexC1^.ClassName;
      end;
    MISSILE_FLAG:
      begin
      PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(PThisMulti^.WepId[intC]);
      strWepName:= PHCAnnexD1^.ClassName;
      end;
    ASW_FLAG:
    begin
    PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(PThisMulti^.WepId[intC]);
    strWepName:= PHCAnnexE1^.ClassName;
    end;
    TORP_FLAG:
    begin
    PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(PThisMulti^.WepId[intC]);
    strWepName:= PHCAnnexF1^.ClassName;
    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;
           //
            SGListBoxUnitInfo.Items.Add(format('   %d of %s',
               [PThisMulti^.WepQty[intC], strWepName]));
            intC:= intC + 1;
          end;     //  end one weapon of multi mount
    end;      // end case of multi mount
               //  start case of single mount (not ac loadout)
    GUN_FLAG:
      begin
      PHCAnnexC1:= HCAnnexHelper.HCGetAnnexC1(ThisWepId);
      strWepName:= PHCAnnexC1^.ClassName;
      end;
    MISSILE_FLAG:
      begin
      PHCAnnexD1:= HCAnnexHelper.HCGetAnnexD1(ThisWepId);
      strWepName:= PHCAnnexD1^.ClassName;
      end;
    ASW_FLAG:
    begin
    PHCAnnexE1:= HCAnnexHelper.HCGetAnnexE1(ThisWepId);
    strWepName:= PHCAnnexE1^.ClassName;
    end;
    TORP_FLAG:
    begin
    PHCAnnexF1:= HCAnnexHelper.HCGetAnnexF1(ThisWepId);
    strWepName:= PHCAnnexF1^.ClassName;
    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 case weapon type
    SGListBoxUnitInfo.Items.Add(Format('   %d of %s',[PThisMnt^.Ammo_c[0], strWepName]));

    strWepName:= '';
    PThisMnt:= PThisMnt^.next;
    end;       // end  each mount
  end;       // end if mounts
//
  if (PSelectedUnit^.Mags <> nil) then
  begin
  SGListBoxUnitInfo.Items.Add('* Magazines *');
  PThisMag:= PSelectedUnit^.Mags;
  while (PThisMag <> nil) do
    begin
    //try to 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'
    end;
    //
    SGListBoxUnitInfo.Items.Add(format('%s: Count: %d, ReloadTime: %d',[strWepName, PThisMag^.Count, PThisMag^.ReloadTime]));
    PThisMag:= PThisMag^.next;
    end;
  end;   //end mags
  if (PHCGroup(PSelectedUnit^.Group)^.side = 2) then
  SGListBoxUnitInfo.Items.Add('side = neutral')
  else
  begin
    SGListBoxUnitInfo.Items.Add('* General *');
    intShow:=  PSelectedUnit^.showing[0];
    case intShow of
    0: strShow:= 'showing for AI only';
    1: strShow:= 'showing for player only';
    3: strShow:= 'enemy exact fix';
    4: strShow:= 'enemy has approx position';
    else strShow:= 'showing = value ' + intTostr(intShow);
    end;
    SGListBoxUnitInfo.Items.Add(strShow);
  end;
  RLat:= 90-(PSelectedUnit^.sLat/sliver1);       // have to convert game slat/slon to real lat/lon
  RLon:= PSelectedUnit^.sLon/sliver1;
  SGListBoxUnitInfo.Items.Add(format('lat: %3.2f; lon: %3.2f',[RLat, RLon]));
  intDepthAlt:= HCdllCheckLatLonDepth(RLat, RLon);     // water depth/land altitude at geographic point of unit
  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';
  8: strDepthAlt := 'SmallShip';
  9: strDepthAlt := 'MedShip';
  10: strDepthAlt := 'LrgShip';
  11: strDepthAlt := 'Land';             // normally vlow
  12: strDepthAlt := 'Low';
  13: strDepthAlt := 'Medium';
  14: strDepthAlt := 'High';
  15: strDepthAlt := 'Vhigh';
  16: strDepthAlt := 'SubOrbit';
  end;
  //
  SGListBoxUnitInfo.Items.Add('water depth/land alt: ' + strDepthAlt);
  end
  else
  begin
    SGListBoxUnitInfo.Items.Clear;
    SGListBoxUnitInfo.Items.Add('bad unit selection?'); // something strange went on
  end;
end;

end.

