library AARdata; {$mode objfpc} {$H+} {$R *.res} uses Classes { you can add units after this } ,uHCDefines ,uHCGCI, uHCGlobals, uHCTypeDefs, uHCEventHelpers ,uHCDateTime, uHCAnnexDefs, uHCAnnexHelpers, uLazGUIGlobals, Windows, IniFiles, Forms ,ShellAPI ,SysUtils ,Types ,Dialogs, Controls, Interfaces; // end classes const DLLVERN = 7; DLLVERINTN = 17; var intGameTime, intGameTimeStrt: Long; intGameTimeLeft: Long; strUnitSink, strDateNow, strMsgLog, strTimeFact, strTimeNow, strFileID, iniFileID : string; dtNow: THCDateTimeRec; Pdt_scen_start: PHCDateTimeRec; RepFile, Inifile:TINIfile; frstStart, scenLoaded: Boolean; PAllDeadUnits: PHCDeadListItem; HCdisk_id_to_annex_id: THCdisk_id_to_annex_id; HCannex_id_to_disk_id: THCannex_id_to_disk_id; PStartGroup: PHCGroup; ActTDstrt: TDateTime; 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 := 'data collection for After Action Reports'; end; procedure StartGroup(StartGroup: PHCGroup);export;cdecl; // ddt 211105 begin PStartGroup:= StartGroup; end; Function FullDate(dtshort: THCDateTimeRec): string; var mnth: string; begin case dtshort.month of 1: mnth:= 'Jan'; 2: mnth:= 'Feb'; 3: mnth:= 'March'; 4: mnth:= 'April'; 5: mnth:= 'May'; 6: mnth:= 'Jume'; 7: mnth:= 'July'; 8: mnth:= 'Aug'; 9: mnth:= 'Sep'; 10: mnth:= 'Oct'; 11:mnth:= 'Nov'; 12:mnth:= 'Dec'; end; Result:= Format('%d %s %4.4d, %2.2d:%2.2d:%2.2d',[dtshort.day, mnth, dtshort.year, dtshort.hour, dtshort.minute, dtshort.second]); end; //needswork 220619 procedure DLLInit(hwndHC: HWND; pathHC: PAnsiChar; verHC: PAnsiChar; verSaveGame: LongWord; funcRefs: PHCDLL_FUNC_REF; PGEClosing: Pointer; PDLLBusy: Pointer; verInterface: LongWord);export;cdecl; var funcTmp: PHCDLL_FUNC_REF; begin // here we initialize globals and such for the life of the DLL Application.Initialize; uLazGUIGlobals.PGEClosing:=PGEClosing; uLazGUIGlobals.PDLLBusy:=PDLLBusy; uLazGUIGlobals.intVerInterface:=verInterface; //?? see Tonys line 93 uLazGUIGlobals.intVerSaveGame:=verSaveGame; funcTmp := funcRefs; while (funcTmp <> nil) do begin if (funcTmp^.funcName = 'annex_id_to_disk_id') then HCannex_id_to_disk_id := THCannex_id_to_disk_id(funcTmp^.funcPtr) else if (funcTmp^.funcName = 'disk_id_to_annex_id') then HCdisk_id_to_annex_id := THCdisk_id_to_annex_id(funcTmp^.funcPtr) ; funcTmp := funcTmp^.next; end; //If Not FileExists(Application.Location+'\AARdata.txt') //then // begin // RepFile:=Tinifile.Create(Application.Location+'\AARdata.txt'); // RepFile.WriteString('Initial Start', 'Actual Date ',' ' + DateTimeToStr(Now)); // frstStart:= True; // end //else frstStart:= False; scenLoaded:= False; end; // needs work 20220629 see tony l 312 procedure ScenLoad(strHarpPath: PAnsiChar; intScenNum: SmallInt; strScenFPath: PAnsiChar; intBSNum: ShortInt; strBSFName: PAnsiChar; intSide: byte; intGameTimeIn: Long; intGameTimeLeftIn: Long; dt_scen_start_in: PHCDateTimeRec; AnnexDataIn: PHCAnnexes_disk);export;cdecl; var strFullDate: string; begin ulazguiglobals.AnnexData:= AnnexDataIn; HCAnnexHelper := THCAnnexHelper.Create(AnnexDataIn, HCannex_id_to_disk_id, uLazGUIGlobals.intVerInterface, uLazGUIGlobals.intVerSaveGame); scenLoaded:= True; intGameTime := intGameTimeIn; intGameTimeStrt := intGameTime; intGameTimeLeft := intGameTimeLeftIn; ActTDstrt := Now; Pdt_scen_start := dt_scen_start_in; // have to build the thcdatetimerec from the new data in components dtNow:= HCDateTimeInc(Pdt_scen_start^, intGameTime); strFullDate:= FullDate(dtNow); // ====== strFileID:= strBSFName + IntToStr(intScenNum + 1); iniFileID:= '\AARdata-' + strFileID + '.txt' ; If Not FileExists(Application.Location+ iniFileID) then begin RepFile:=Tinifile.Create(Application.Location+ iniFileID); RepFile.WriteString('Initial Start', 'Actual Date ',' ' + DateTimeToStr(Now)); frstStart:= True; // RepFile.WriteString('Initial Start', 'GameTimeStart ', IntToStr(intGameTimeIn)); // ddt 220718 testing end else begin frstStart:= False; RepFile:=Tinifile.Create(Application.Location+iniFileID); end; // ==== RepFile.WriteString('Session Summary','Session Start ',strFullDate); RepFile.WriteString('Log','==' , '=='); RepFile.WriteString('Log', 'session start ', strFullDate); RepFile.WriteString('Log', 'Actual Date ', DateTimeToStr(Now)); RepFile.WriteString('Time Factor', strFullDate, 'Initial ' + strTimeFact); if frstStart = True then begin RepFile.WriteString('Initial Start', 'Battleset ',strBSFName); if intScenNum = -1 then //custom scenario RepFile.WriteString('Initial Start', 'Scenario ',strScenFPath) else RepFile.WriteString('Initial Start', 'Scenario ',strBSFName+'/Scen#'+IntToStr(intScenNum+1)); end else begin if intScenNum = -1 then //custom scenario RepFile.WriteString('Log', ' Scenario ',' ' + strScenFPath) else RepFile.WriteString('Log', ' Scenario ', ' ' + strBSFName +'/Scen#'+IntToStr(intScenNum+1)); end; end; procedure TimeFactor(TimeFactor: longint);export;cdecl; var mnth, strDateTime: string; begin if scenLoaded = True then begin dtNow:= HCDateTimeInc(Pdt_scen_start^, intGameTime); strDateTime:= FullDate(dtNow); strTimeFact:= Format(' TimeFactor = 1:%d', [TimeFactor]); RepFile:=Tinifile.Create(Application.Location+iniFileID); RepFile.WriteString('Time Factor', strDateTime, strTimeFact); end else strTimeFact:= Format(' TimeFactor = 1:%d', [TimeFactor]); end; procedure MsgLog(MsgLine: PAnsiChar);export;cdecl; begin RepFile.WriteString('log', 'Event ', MsgLine); end; procedure GameTime(GameTime: Long; GameTimeLeft: Long);export;cdecl; begin intGameTime := GameTime; intGameTimeLeft := GameTimeLeft; end; //procedure ListMagazines(); DDT 211127 //var // PHCThisGroup: PHCGroup; // PSelectedUnit: PHCUnit; // PThisMag: PHCMagRec; // PHCAnnexC1: PHCAnnexC1_disk; // PHCAnnexD1: PHCAnnexD1_disk; // PHCAnnexE1: PHCAnnexE1_disk; // PHCAnnexF1: PHCAnnexF1_disk; // strWepName: string; // MagCount: integer; // //begin // PHCThisGroup:= PStartGroup; //start top of group list // while PHCThisGroup <> nil do // begin // // look for each unit in the group and list magazine // PSelectedUnit:= PHCThisGroup^.Units; // first unit must exist // while PSelectedUnit <> nil do // begin // // new unit,set mag count and look for magazines // MagCount:= 0; // if (PSelectedUnit^.Mags <> nil) then // begin // PThisMag:= PSelectedUnit^.Mags; // while (PThisMag <> nil) do // go thru all the mags of this unit // 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' // end; // // // RepFile.WriteString(Format('Magazine: %2.2s%0.3d %s',[PHCThisGroup^.id, PSelectedUnit^.id, PSelectedUnit^.name]), // IntToStr(MagCount), // (format('%s: Count: %d, ReloadTime: %d',[strWepName, PThisMag^.Count, PThisMag^.ReloadTime]))); // PThisMag:= PThisMag^.next; // MagCount:= MagCount + 1; // end; // end; //end mags // // get next unit // PSelectedUnit:= PSelectedUnit^.next; // end; // PHCThisGroup := PHCThisGroup^.toSouth; // end; //end; procedure GetLastKill(); var PThisDeadUnit: PHCDeadListItem; strDeadUnit, strClass, strUname, strSide, strDateTime: String; intCarrierKill, intShipKill, intSubKill, intPlaneKill, intHeloKill, intBaseKill, intFixKill, intMobKill, intArmKill, intUnarmKill, intS: integer; ThisA1_disk: PHCAnnexA1_disk; ThisB1_disk: PHCAnnexB1_disk; begin for intS := 0 to 2 do begin case intS of 0: strSide:= 'Blue Side '; 1: strSide:= 'Red Side '; 2: strSide:= 'Neutral Side '; end; PThisDeadUnit:= PAllDeadUnits; intCarrierKill:= 0; intShipKill:= 0; intSubKill:= 0; intPlaneKill:= 0; intHeloKill:=0; intBaseKill:= 0; intFixKill:= 0; intMobKill:= 0; intArmKill:= 0; intUnarmKill:= 0; // if (PThisDeadUnit = nil) then ShowMessage('no dead unit') else ddt 211206 removed // debug 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; // now look for class details // I'm having trouble here grrr case HCAnnexShift(PThisDeadUnit^.Annex) of // this checked out, got raw annexclassIDs SHIP_FLAG: begin ThisA1_disk := HCAnnexHelper.HCGetAnnexA1(PThisDeadUnit^.Annex); strUname:= ThisA1_disk^.ClassName; end; PLANE_FLAG: begin ThisB1_disk := HCAnnexHelper.HCGetAnnexB1(PThisDeadUnit^.Annex); strUname:= ThisB1_disk^.ClassName; end; BASE_FLAG: strUname:= PHCAnnexP1_disk(HCAnnexHelper.HCGetAnnexP1(PThisDeadUnit^.Annex))^.Name; SUB_FLAG: strUname:= PHCAnnexA2_disk(HCAnnexHelper.HCGetAnnexA2(PThisDeadUnit^.Annex))^.ClassName; else strUname:= IntToStr(PThisDeadUnit^.Annex); end; // don't get this far, no legit strUname // end look for class detail // now write data RepFile.WriteString('Kill Detail ' + strSide, strUname + '/' + strClass, IntToStr(PThisDeadUnit^.count)); end; PThisDeadUnit:= PThisDeadUnit^.next; end; // end loop deadunitptr if intCarrierKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'Carriers:', intCarrierKill); if intShipKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'Ships:', intShipKill); if intSubKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'Submarines:', intSubKill); if intPlaneKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'Planes:', intPlaneKill); if intHeloKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'Helicopters:', intHeloKill); if intMobKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'AD mobile:', intMobKill); if intFixKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'AD fixed:', intFixKill); if intArmKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'Armoured:', intArmKill); if intUnarmKill > 0 then RepFile.WriteInteger('Kill Summary ' + strSide,'Unarmoured:', intUnarmKill); end; // finished all sides end; procedure DLLFree();export;cdecl; var GameTimeDuration, TotGameTimeDuration : LongInt; GameTimeHrs, GameTimeMins, TotGameTimeHrs, TotGameTimeMins : Integer; begin // Do any cleanup here, this is the end and closes library GameTimeDuration:= intGameTime - intGameTimeStrt; if GameTimeDuration > 3600 then //this session begin GameTimeHrs := GameTimeDuration Div 3600; GameTimeMins := (GameTimeDuration Div 60) - (GameTimeHrs * 60); end else begin GameTimeMins := GameTimeDuration Div 60; GameTimeHrs := 0; end; //end this session calc TotGameTimeDuration := intGameTime - 100000; //game time starts at 100000 if TotGameTimeDuration > 3600 then begin TotGameTimeHrs := TotGameTimeDuration Div 3600; TotGameTimeMins := (TotGameTimeDuration Div 60) - (TotGameTimeHrs * 60); end else begin TotGameTimeMins := TotGameTimeDuration Div 60; TotGameTimeHrs := 0; end; GetLastKill(); // RepFile.WriteString('Session Summary', '==', '=='); RepFile.WriteString('Session Summary', 'GameTimeDuration ThisSession ', IntToStr(GameTimeHrs) + 'Hrs' + IntToStr(GameTimeMins) + ' Mins'); RepFile.WriteString('Session Summary', 'TotalGameTimeDuration ',IntToStr(TotGameTimeHrs) + 'Hrs' + IntToStr(TotGameTimeMins) + 'Mins'); RepFile.WriteString('Session Summary', 'Session End RealTime ', DateTimeToStr(Now)); RepFile.WriteString('Session Summary', 'RealTimeDuration ThisSession ', TimeToStr(Now - ActTDstrt)); RepFile.WriteString('Session Summary', '==== ', '===='); // ListMagazines(); RepFile.UpdateFile; // DDT 210801 moved from GetLastKill end; procedure AllDeadUnitsPtr(AllDeadUnitsPtr: PHCDeadListItem);export;cdecl; begin // get/update deadunitpointer PAllDeadUnits:= AllDeadUnitsPtr; end; // DDT 210727 Taken out, don't like it //procedure UnitFree(UnitID: Byte; GroupID: PAnsiChar);export;cdecl; //var // strFullDT, strUnitID: string; //begin // dtNow:= HCDateTimeInc(Pdt_scen_start^, intGameTime); // strFullDT:= FullDate(dtNow); // strUnitID:= format(':%2.2d',[UnitID]); // RepFile.WriteString('Unit Free', strFullDT, GroupID + strUnitID); //end; procedure UnitSink(UnitID: Byte; GroupID: PAnsiChar);export;cdecl; // DDT 210727 added var strFullDT, strUnitID: string; begin strFullDT:= FullDate(dtNow); strUnitID:= format(':%2.2d',[UnitID]); RepFile.WriteString('Unit Sunk', strFullDT , GroupID + ':' + strUnitID); end; exports DLLVer, DLLVerInt, DLLDesc, DLLFree, DLLInit, AllDeadUnitsPtr, ScenLoad, TimeFactor, MsgLog, GameTime, // UnitFree, UnitSink, StartGroup ; end.