library GameStatusDLL; { Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. } uses System.SysUtils, System.Classes, System.JSON, Windows, uHCDateTime in '..\..\shared\pascal\uHCDateTime.pas', uHCDefines in '..\..\shared\pascal\uHCDefines.pas', uHCGlobals in '..\..\shared\pascal\uHCGlobals.pas', uHCTypeDefs in '..\..\shared\pascal\uHCTypeDefs.pas' {/,} , uGameStatusTypeDefs in 'uGameStatusTypeDefs.pas'; {$R *.res} const DLLVERN = 10; DLLVERINTN = 11; version = 1; // ALE 20150820 TMMFGameStatus structure version var dt_scen_start: PHCDateTimeRec; PAllDeadUnits: PHCDeadListItem; PBusyDLL: Pointer; GameStatus: TMMFGameStatus; MMF: TTGPMemMappedFile; { *** 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 := 'DLL to send Game Status to local network viewers, by Tony Eischens'; end; { *** Free DLL *** } procedure DLLFree(); export; cdecl; begin // Do any cleanup here, this is the end MMF.Free; end; { *** Init DLL *** } procedure DLLInit(hwndHC: HWND; pathHC: PAnsiChar; verHC: PAnsiChar; verSaveGame: LongWord; funcRefs: PHCDLL_FUNC_REF; PGEClosing: Pointer; PDLLBusy: Pointer; verInterface: LongWord); export; cdecl; begin PBusyDLL := PDLLBusy; GameStatus.read := True; // ALE 20150819 lets us send the initial game status MMF := TTGPMemMappedFile.Create; end; procedure ScenLoad(strHarpPath: PAnsiChar; intScenNum: SmallInt; strScenFPath: PAnsiChar; intBSNum: ShortInt; strBSFName: PAnsiChar; intSide: byte; intGameTimeIn: Long; intGameTimeLeftIn: Long; dt_scen_start_in: PHCDateTimeRec); export; cdecl; begin byte(PBusyDLL^) := CTRUE; // ALE 20130816 don't process other events in GE dt_scen_start := dt_scen_start_in; byte(PBusyDLL^) := CFALSE; end; procedure GameTime(GameTime: Long; GameTimeLeft: Long); export; cdecl; var dtNow: THCDateTimeRec; intType, intSide: Integer; strLine: String; DeadUnitPtr: PHCDeadListItem; stlOut: TStringList; //killcounts: array [0 .. 9, 0 .. 2] of Integer; begin byte(PBusyDLL^) := CTRUE; // ALE 20130816 don't process other events in GE CopyMemory(@GameStatus, MMF.fPSharedData, SizeOf(TMMFGameStatus)); if (GameStatus.read = True) then begin GameStatus.read := False; GameStatus.version := version; CopyMemory(@(GameStatus.gamestartdatetime), dt_scen_start, SizeOf(THCDateTimeRec)); GameStatus.GameTime := GameTime; GameStatus.GameTimeLeft := GameTimeLeft; // ALE 20150712 store remaining time DeadUnitPtr := PAllDeadUnits; // ALE 20150713 Initialize the array to zeros so we don't get false counts for intType := 0 to 9 do begin for intSide := 0 to 2 do begin GameStatus.killcounts[intType, intSide] := 0; end; end; // ALE 20150713 Tally up the individual dead units by type and side while (DeadUnitPtr <> nil) do begin if DeadUnitPtr.Count >= 1 then begin // intC := intC + DeadUnitPtr.count GameStatus.killcounts[DeadUnitPtr.typeindex, DeadUnitPtr.side] := GameStatus.killcounts[DeadUnitPtr.typeindex, DeadUnitPtr.side] + DeadUnitPtr.Count; end else begin // Inc(intC); Inc(GameStatus.killcounts[DeadUnitPtr.typeindex, DeadUnitPtr.side]); end; DeadUnitPtr := DeadUnitPtr.next; end; stlOut := TStringList.Create; // ALE 20150713 now report on it for intType := 0 to 9 do begin strLine := 'Type: ' + IntToStr(intType) + ', '; for intSide := 0 to 2 do begin strLine := strLine + 'Side: ' + IntToStr(intSide) + ', Count=' + IntToStr(GameStatus.killcounts[intType, intSide]) + ' '; end; stlOut.Add(strLine); end; // tethSendGameStats(stlOut.Text); stlOut.SaveToFile('C:\Games\HC\GameStatusDLL.txt'); stlOut.Free; CopyMemory(MMF.fPSharedData, @GameStatus, SizeOf(TMMFGameStatus)); end; byte(PBusyDLL^) := CFALSE; // ALE 20130816 don't process other events in GE { frmMain.GTlblGameTime.Caption := 'GameTime: ' + Format('%8.8d', [intGameTime]); frmMain.GTlblGameTimeLeft.Caption := 'GameTimeLeft: ' + Format('%8.8d', [intGameTimeLeft]); dtNow := HCDateTimeInc(dt_scen_start^, intGameTime); frmMain.GTlblGameDateTime.Caption := 'GameDateTime: ' + Format('%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d', [dtNow.year, dtNow.month, dtNow.day, dtNow.hour, dtNow.minute, dtNow.second]); } end; procedure AllDeadUnitsPtr(AllDeadUnitsPtr: PHCDeadListItem); export; cdecl; begin PAllDeadUnits := AllDeadUnitsPtr; end; exports DLLVer, DLLVerInt, DLLDesc, DLLFree, DLLInit, ScenLoad, GameTime, AllDeadUnitsPtr; end.