library Drone; {$mode delphi}{$H+} {$R *.res} uses Classes { you can add units after this } , Mainform, uHCDefines , uHCGCI, uHCGlobals, uHCTypeDefs, uHCEventHelpers, uHCDateTime , uHCAnnexDefs, uHCAnnexHelpers, uLazGUIGlobals, uHCUtils , Windows, Forms, ShellAPI, SysUtils ,Types ,Dialogs, Interfaces, Controls, FileInfo; const DLLVERN = 3; DLLVERINTN = 39; // 37 var frmMain: TfrmMain; intGameTime: Long; FileVersionInfo: TFileVersionInfo; strFileVers, strGEVers: String; {*** Return DLL internal version, i.e. revision 5 of my DLL ***} function DLLVer():word;export;cdecl; begin result := DLLVERN; end; {*** Return DLL interface version, i.e. revision 1 of my HCE interface spec ***} function DLLVerInt():word;export;cdecl; begin result := DLLVERINTN; end; {*** Return DLL description, 255 characters max ***} function DLLDesc():PAnsiChar;export;cdecl; begin result := 'use with HC to ammend loaded database by Don Thomas'; end; {*** Free DLL ***} procedure DLLFree();export;cdecl; begin // Do any cleanup here, this is the end frmMain.WindowState:= wsMinimized; // 240906 frmMain.Free; end; {*** Init DLL ***} procedure DLLInit(hwndHC: HWND; pathHC: PAnsiChar; verHC: PAnsiChar; verSaveGame: LongWord; funcRefs: PHCDLL_FUNC_REF; PGEClosing: Pointer; PDLLBusy: Pointer; verInterface: LongWord; srandSeed: longword; harpoon_uuid_session: PAnsiChar; hclicense_dt_expire: Int64; hclicense_licensee: PAnsiChar; usblicense_desc: PAnsiChar; RESRSRStructureVersion: ulong; AnnexVersion: ushort );export;cdecl; var funcTmp: PHCDLL_FUNC_REF; begin // here we initialize globals and such for the life of the DLL Application.Initialize; // ALE 20120410 Freezes HC Application.Run; uLazGUIGlobals.PGEClosing:=PGEClosing; uLazGUIGlobals.PDLLBusy:=PDLLBusy; uLazGUIGlobals.hwndHC:=hwndHC; // 20230405 version update uLazGUIGlobals.intVerInterface:=verInterface; uLazGUIGlobals.intVerSaveGame:=verSaveGame; FileVersionInfo:= TFileVersionInfo.Create(nil); FileVersionInfo.ReadFileInfo; frmMain := TfrmMain.Create(nil); frmMain.ParentWindow := hwndHC; // 230407 reside in harpwindow strFileVers:= FileVersionInfo.VersionStrings.Values['FileVersion']; FileVersionInfo.Free; if Length(strFileVers) = 0 then strFileVers := '1.0.1'; frmMain.Caption := 'Annex OVerwrite V ' + strFileVers //IntToStr(DLLVERN) + ', ExportDLL Interface v ' + IntToStr(DLLVERINTN) + 'for GE v 2023.003+'; if (verInterface < DLLVERINTN) then ShowMessage('Drone.DLL requires at least HC2025.006, platform amends will not occur and game might crash'); // 250228 // ALE 20130908 List the function pointers sent over by the GE // then capture one of them for example usage funcTmp := funcRefs; while (funcTmp <> nil) do begin if (funcTmp^.funcName = 'NewPtr') then frmMain.NewPtr := funcTmp^.funcPtr else if (funcTmp^.funcName = 'QueueHarpoonEvent') then frmMain.HCQueueHarpoonEvent := THCQueueHarpoonEvent(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'dllCheckLatLonDepth') then frmMain.HCdllCheckLatLonDepth := THCdllCheckLatLonDepth(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'annex_id_to_disk_id') then frmMain.HCannex_id_to_disk_id := THCannex_id_to_disk_id(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'disk_id_to_annex_id') then frmMain.HCdisk_id_to_annex_id := THCdisk_id_to_annex_id(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'free_Unit') then frmMain.HCfree_Unit := THCfree_Unit(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'free_Group') then frmMain.HCfree_Group := THCfree_Group(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'ChangeActGroupPtr') then frmMain.HCChangeActGroupPtr := THCChangeActGroupPtr(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'ChangeActUnitPtr') then frmMain.HCChangeActUnitPtr := THCChangeActUnitPtr(funcTmp^.funcPtr) ; funcTmp := funcTmp^.next; end; frmMain.Show; frmMain.WindowState:= wsNormal; // 230407 240503 250301 frmMain.BringToFront; strGEVers:= verHC; end; procedure ProcessAnnexAmends(); // this is guts of library edit for individual - also processUnit var pSub: PHCAnnexA2_disk; pSurf: PHCAnnexA1_disk; pMissile: PHCAnnexD1_disk; pMnt: PHCAnnexZ1_disk; pASW: PHCAnnexE1_disk; // :PHCPlatformDescription; begin // 250205 edit sub annex for drone semi submerged using Intrepido 15 columbia HCDB2 pSub:= HCAnnexHelper.HCGetAnnexA2(4107); pSub^.RCS:= 1; pSub^.BaseSourceLevel:= 42; pSub^.DetectSize:= 1; pSub^.SensId[0]:= 47154; // 250206 pSub^.SensId[1]:= 43103; pSub^.OrigDp:= 1; pSub^.CreepSpeed:= 15; pSub^.MaxSurfSpeed:= 40; pSub^.MaxSubSpeed:= 50; pSub^.MaxDepth:= Snorkel; pSub^.MntId[0]:= 60722; // suicide charge pSub^.MntId[1]:= 60722; // 250316 pSub^.ClassName:= 'SemiSubDroneSwarm'; pSurf:= HCAnnexHelper.HCGetAnnexA1(3901); // 250206 Algeria type 20GC PG pSurf^.RCS:= 5; pSurf^.DetectSize:= 1; pSurf^.OrigDp:= 3; pSurf^.SearchHeight:= ScopeAlt; pSurf^.BaseSourceLevel:= 50; pSurf^.SensId[0]:= 43103; pSurf^.ClassName:= 'SurfDroneSwarm'; pSurf^.MntId[0]:= 60722; pSurf^.MaxSpeed:= 50; pSurf:= HCAnnexHelper.HCGetAnnexA1(2656); // drugrunner has MG pSurf^.ClassName:= 'CB-90'; // 250220 pSurf^.MntId[1]:= 59642; // 80mm mortar pSurf^.MaxSpeed:= 40; pMnt:= HCAnnexHelper.HCGetAnnexZ1(60722); // suicide mnt pMnt^.NumRoundsMnt:=5; pMnt^.NumTargets:= 1; pMissile:= HCAnnexHelper.HCGetAnnexD1(19011); pMissile^.Dp:= 120; pMissile^.SurfPh:= 65; pMissile^.SurfRange:= 10; pMissile^.Speed:= 50; pASW:= HCAnnexHelper.HCGetAnnexE1(22535); // amend RBU 1200(RBU-12) pASW^.ClassName:= 'AntiSnortDrone Gun'; pASW^.MaxRange:= 30; pASW^.MinRange:= 1; pASW^.Ph:= 25; // iterate thru units and update speeds and mounts elsewhere. no longer needed end; procedure ScenLoad(strHarpPath: PAnsiChar; intScenNum: SmallInt; strScenFPath: PAnsiChar; intBSNum: ShortInt; strBSFName: PAnsiChar; intSide: byte; intGameTimeIn: Long; intGameTimeLeftIn: Long; // 20230405 dt_scen_start_in: PHCDateTimeRec; AnnexDataIn: PHCAnnexes_disk; DatabaseVersionDBIn: PHCDATABASE_VERSION; ScenDataIn: PHCSCENARIO_DATA; ScenSaveDataIn: PHCSCENARIO_SAVE_DATA; GlobalsIn: PHCGlobals);export;cdecl; var intIdx: NativeUInt; pLoadout: PHCAnnexY1_disk; pShip: PHCAnnexA1_disk; pSub: PHCAnnexA2_disk; pAir: PHCAnnexB1_disk; pBase: PHCAnnexP1_disk; pGun: PHCAnnexC1_disk; pMissile: PHCAnnexD1_disk; pBomb: PHCAnnexG1_disk; pECM: PHCAnnexG2_disk; pNuke: PHCAnnexI1_disk; pRadar: PHCAnnexJ1_disk; pSonar: PHCAnnexM1_disk; pMount: PHCAnnexZ1_disk; pMulti: PHCAnnexZ2_disk; strScenNum, strBatSetName: string; TimeNowTimeRec: THCDateTimeRec; begin frmMain.intPSide:= intSide; intGameTime := intGameTimeIn; // ALE 20150712 Now that we receive the game time here, store it intGameTimeLeft := intGameTimeLeftIn; // ALE 20150712 Now that we receive the game time left here, store it end; procedure DBLoaded(AnnexDataIn: PHCAnnexes_disk; AnnexDataMemIn: PHCAnnexes_mem) export; cdecl; begin if (AnnexDataMemIn = nil) then begin AnnexData := AnnexDataIn; HCAnnexHelper := THCAnnexHelper.Create(AnnexDataIn, frmMain.HCannex_id_to_disk_id, uLazGUIGlobals.intVerInterface, uLazGUIGlobals.intVerSaveGame); ProcessAnnexAmends(); // 250223 end else begin AnnexData_mem := AnnexDataMemIn; HCAnnexMemHelper := THCAnnexMemHelper.Create(AnnexDataMemIn, frmMain.HCannex_id_to_disk_id); end; end; procedure ProcessVCList(PThisVicCondn: PHCVictoryConditions); var strVT, strUC, strOS, strDam, strDT: string; begin frmMain.VClstbxItems.Clear; frmMain.VClstbxItems.Items.Add('Import at Session Start'); while PThisVicCondn <> nil do begin if PThisVicCondn^.VicType = 0 then strVT:= 'Minimum' else strVT:= 'Total'; if PThisVicCondn^.AndOrFlag = 1 then strVT:= strVT + '(and)' else strVT:= strVT + '(or)'; // set victory type case PThisVicCondn^.unitType of 0: strUC:= 'Carrier'; 1: strUC:= 'Ship'; 2: strUC:= 'Sub'; 3: strUC:= 'Plane'; 4: strUC:= 'Helo'; 5: strUC:= 'Base'; 6: strUC:= 'Fixed AD'; 7: strUC:= 'Mobile AD'; 8: strUC:= 'Armoured'; 9: strUC:= 'UnArmred'; else strUC:= 'Unknown'; end; case PThisVicCondn^.itemType of 0: strDT:= '' ; 1: strDT:= Format('BroadType %s',[AnnexData^.PBSStrings^.BroadVicType[PThisVicCondn^.DetailType]]); 2: if PThisVicCondn^.unitType = (3 or 4) then strDT:= Format('DetailType %s',[AnnexData^.PBSStrings^.ACType[PThisVicCondn^.DetailType]]) else strDT:= Format('DetailType %s',[AnnexData^.PBSStrings^.ShipType[PThisVicCondn^.DetailType]]); else strDT := ''; end; if PThisVicCondn^.TimeOnStation = 0 then strOS:= 'Destroyed' else strOS:= format('OnStation for %d Mins',[(PThisVicCondn^.TimeOnStation) div 60]); if PThisVicCondn^.numDamaged = 0 then strDam:= '' else strDam:= Format('%d units %d %s damaged', [PThisVicCondn^.numDamaged, PThisVicCondn^.percentDamage, '%']); frmMain.VClstbxItems.Items.Add (Format('GT achieved: %8.8d, vc#%.1d %s; %s; Pertains to: %s; %s; Require: %d %s, %s', [PThisVicCondn^.gameTimeAchieved, PThisVicCondn^.id, AnnexData^.PBSStrings^.SideName[PThisVicCondn^.WhichSide], strVT, strUC, strDT, PThisVicCondn^.numKilled, strOS, strDam])); // 20230420 added ID // // chase crash PThisVicCondn:= PThisVicCondn^.next; end; frmMain.VClstbxItems.Items.Add('Session Play Starts'); end; Procedure AmendUnitData(); // 250205 var lPThisUnit: PHCUnit; lPThisGroup: PHCGroup; lPThisMnt: PHCMntRec; begin lPThisGroup := frmMain.PStartGroup; while (lPThisGroup <> nil) do begin lPThisUnit:= lPThisGroup^.Units; while (lPThisUnit <> nil) do begin //if lPThisUnit^.Annex = 4107 then // sub // begin // lPThisUnit^.maxspeed:= 50; // lPThisUnit^.AltBand:= Snorkel; // lPThisUnit^.BestAAWRange:= 0; // lPThisUnit^.BestASuWRange:= 10; // lPThisUnit^.BestASWRange:= 0; // lPThisUnit^.OrigDp:= 1; // lPThisUnit^.CurrDp:= 0; // lPThisMnt:= lPThisUnit^.Mnts; // lPThisMnt^.MntId:= 60722; // lPThisMnt^.WepId:= 19011; // lPThisMnt^.Ammo_c[0]:= 1; // lPThisMnt^.next:= nil; // lPThisUnit^.SensId[0]:= 47154; // lPThisUnit^.SensId[1]:= 43103; // end //else if (lPThisUnit^.Annex = 3901) then // surf drone // begin // lPThisUnit^.maxspeed:= 55; // lPThisMnt:= lPThisUnit^.Mnts; // lPThisMnt^.MntId:= 60722; // lPThisMnt^.WepId:= 19011; // lPThisMnt^.Ammo_c[0]:= 1; // lPThisUnit^.BestAAWRange:= 0; // lPThisUnit^.BestASuWRange:= 10; // lPThisUnit^.BestASWRange:= 0; // lPThisMnt^.next:= nil; // lPThisUnit^.Mags:= nil; // lPThisUnit^.SensId[0]:= 43103; // lPThisUnit^.OrigDp:= 3; // lPThisUnit^.CurrDp:= 0; // lPThisUnit^.RCS:= 5; // lPThisUnit^.VCS:= 1; // end; //if (lPThisUnit^.Annex = 2656) then // CB-90 was drugrunner // begin // lPThisUnit^.maxspeed:= 40; // end; if (lPThisUnit^.Annex = 2496) then // 250209 type 053 CPLAN DDG begin lPThisMnt:= lPThisUnit^.Mnts; while (lPThisMnt <> nil) do begin if (lPThisMnt^.MntId = 60288) or (lPThisMnt^.MntId = 60289) then lPThisMnt^.Damage:= 2; lPThisMnt:= lPThisMnt^.next; end; end; lPThisUnit:= lPThisUnit^.next; end; lPThisGroup := lPThisGroup^.toSouth; end; end; procedure StartGroup(StartGroup: PHCGroup);export;cdecl; var PHCGThis: PHCGroup; begin frmMain.PStartGroup:=StartGroup; ProcessVCList(frmMain.PVCList); if (intGameTime = 100000) then AmendUnitData(); //250223 250206 one off for eg damage mounts end; procedure VictoryConditionsList(PVCList: PHCVictoryConditions);export;cdecl; begin frmMain.PVCList := PVCList; end; procedure VictoryConditionLevels(whichSide: uchar; enemySide: uchar; vicLevel: uchar);export; cdecl; begin frmMain.VClstbxItems.Items.Add(Format('GT%8.8d: %s Victory Level %s achieved', [intGameTime, AnnexData^.PBSStrings^.SideName[whichSide], HCVictoryConditionLevel(vicLevel)])); // 20230417 end; procedure VictoryConditionAchieved(VictoryCondition: PHCVictoryConditions); export; cdecl; var strVT, strUC, strOS, strDam, strDT: string; begin if VictoryCondition^.VicType = 0 then strVT:= 'Minimum' else strVT:= 'Total'; if VictoryCondition^.AndOrFlag = 1 then strVT:= strVT + '(and)' else strVT:= strVT + '(or)'; // set victory type case VictoryCondition^.unitType of 0: strUC:= 'Carrier'; 1: strUC:= 'Ship'; 2: strUC:= 'Sub'; 3: strUC:= 'Plane'; 4: strUC:= 'Helo'; 5: strUC:= 'Base'; 6: strUC:= 'Fixed AD'; 7: strUC:= 'Mobile AD'; 8: strUC:= 'Armoured'; 9: strUC:= 'UnArmred'; else strUC:= 'Unknown'; end; case VictoryCondition^.itemType of 0: strDT:= '' ; 1: strDT:= Format('BroadType %s',[AnnexData^.PBSStrings^.BroadVicType[VictoryCondition^.DetailType]]); 2: if VictoryCondition^.unitType = (3 or 4) then strDT:= Format('DetailType %s',[AnnexData^.PBSStrings^.ACType[VictoryCondition^.DetailType]]) else strDT:= Format('DetailType %s',[AnnexData^.PBSStrings^.ShipType[VictoryCondition^.DetailType]]); else strDT := ''; end; if VictoryCondition^.TimeOnStation = 0 then strOS:= 'Destroyed' else strOS:= format('OnStation for %d Mins',[(VictoryCondition^.TimeOnStation) div 60]); if VictoryCondition^.numDamaged = 0 then strDam:= '' else strDam:= Format('%d units %d %s damaged', [VictoryCondition^.numDamaged, VictoryCondition^.percentDamage, '%']); frmMain.VClstbxItems.Items.Add (Format('GT achieved: %8.8d, vc#%.1d %s; %s; Pertains to: %s; %s; Require: %d %s, %s', [VictoryCondition^.gameTimeAchieved, VictoryCondition^.id, AnnexData^.PBSStrings^.SideName[VictoryCondition^.WhichSide], strVT, strUC, strDT, VictoryCondition^.numKilled, strOS, strDam])); // 20230420 added ID end; exports DLLVer, DLLVerInt, DLLDesc, DLLFree, DLLInit, ScenLoad, StartGroup // ALE 20130205 Sends updated GroupPtr whenever that changes ,VictoryConditionsList // ALE 20130812 Sends a pointer to the list of victory conditions when a scenario is loaded ,VictoryConditionLevels // 20230417 new for ver34 interface fires when a vic cond level achieved ,VictoryConditionAchieved // 20230419 fires when a vict cond list item is met ,DBLoaded ; end.