UNIT Unit2;

INTERFACE
USES Windows, SysUtils, Unit8, Unit11;

const
  _WindowName='ONI ';
  _WindowClass='ONI ';
  address_message_pointer:LongWord=$10EC0+$4;
  address_activate_message_offset:LongWord=$10E0;

var
  _WindowHandle:LongWord;
  _ProcessID:LongWord;
  _ProcessHandle:LongWord;

FUNCTION FindWindowA(ClassName:String; WindowName:String):longword; stdcall; external 'user32.dll' name 'FindWindowA';
FUNCTION GetWindowThreadProcessId(hwnd:longword; out processId:longword):longword; stdcall; external 'user32.dll' name 'GetWindowThreadProcessId';
FUNCTION OpenProcess(dwDesiredAccess:longword; bInheritHandle:longword; dwProcessId:longword):longword; stdcall; external 'kernel32.dll' name 'OpenProcess';
FUNCTION ReadProcessMemory(hProcess:longword; lpBaseAddress:longword; out lpBuffer:byte_array; nSize:longword; out lpNumberOfBytesWritten:longword):longword; stdcall; external 'kernel32.dll' name 'ReadProcessMemory';
FUNCTION WriteProcessMemory(hProcess:longword; lpBaseAddress:longword; lpBuffer:byte_array; nSize:longword; out lpNumberOfBytesWritten:longword):longword; stdcall; external 'kernel32.dll' name 'WriteProcessMemory';
FUNCTION CloseHandle(hObject:longword):longword; stdcall; external 'kernel32.dll' name 'CloseHandle';
FUNCTION GetAsyncKeyState(vkey:smallint):word; stdcall; external 'user32.dll' name 'GetAsyncKeyState';
FUNCTION VirtualProtectEx(hProcess:longword; lpAddress:longword; dwSize:longword; flNewProtect:longword; lpflOldProtect:longword):longword; stdcall; external 'kernel32.dll' name 'VirtualProtectEx';
FUNCTION GetLastError:longword; stdcall; external 'kernel32.dll' name 'GetLastError';

FUNCTION ConnectToProcess:Boolean;
FUNCTION ReadMem(address:longword; size:longword):byte_array;
FUNCTION WriteMem(address:longword; size:longword; _buffer:byte_array):boolean;
//FUNCTION GetKey(key:smallint):boolean;
PROCEDURE SetWindowAOT(Handle:Cardinal;AOT:Boolean);

FUNCTION Decode_Int(buffer:byte_array):LongWord;
FUNCTION Decode_Float(buffer:byte_array):Single;
FUNCTION Decode_Str(buffer:byte_array):String;
FUNCTION Encode_Int(input:LongWord):byte_array;
FUNCTION Encode_Float(input:Single):byte_array;
FUNCTION Encode_Str(input:String;bytes:byte):byte_array;

FUNCTION patch_messages_loaded:Boolean;
PROCEDURE SendMessageToOni(_message:String);

FUNCTION Check_Data_Correct(address:LongWord; requested:array of byte; size:Byte):Byte;
PROCEDURE Incorrect_Data_Message(formhandle:LongWord; address:LongWord; error:Byte);

implementation

FUNCTION Check_Data_Correct(address:LongWord; requested:array of byte; size:Byte):Byte;
  VAR i:Byte;
  BEGIN
    result:=0;
    _temp:=ReadMem(address,size);
    IF (_temp[250]=123) THEN BEGIN
      result:=1;
      exit;
    END;
    FOR i:=0 TO size-1 DO BEGIN
      IF NOT (_temp[i]=requested[i]) THEN BEGIN
        result:=2;
        exit;
      END;
    END;
  END;
PROCEDURE Incorrect_Data_Message(formhandle:LongWord; address:LongWord; error:Byte);
  BEGIN
    CASE error OF
      1:BEGIN
          MessageBox(formhandle,PChar('Couldn''t read data from $'+IntToHex(address,8)+'!'),PChar('Error'),MB_OK);
          exit;
        END;
      2:BEGIN
          MessageBox(formhandle,PChar('Incorrect data found for inserting script-var-address-patch at $'+IntToHex(address,8)+'!'),PChar('Error'),MB_OK);
          exit;
        END;
    END;
  END;

FUNCTION patch_messages_loaded:Boolean;
  CONST check_for:LongWord=$10725AE9;
    address_at:LongWord=$425B11;
  BEGIN
    IF Decode_Int(ReadMem(address_at,4))=check_for THEN result:=True
    ELSE result:=False;
  END;

PROCEDURE SendMessageToOni(_message:String);
  CONST message_length=100;
  VAR buffer:byte_array;
    i:byte;
    adr_message:LongWord;
    adr_trigger:LongWord;
  BEGIN
    IF _connected AND patch_messages_loaded THEN BEGIN
      adr_message:=Decode_Int(ReadMem(address_message_pointer,4));
      adr_trigger:=Decode_Int(ReadMem(address_script_var_pointer,4))+address_activate_message_offset;

      IF adr_message>0 THEN BEGIN
        FOR i:=0 TO 250 DO buffer[i]:=$00;
        IF StrLen(PChar(_message))>message_length THEN BEGIN
        END ELSE BEGIN
          FOR i:=0 TO StrLen(PChar(_message))-1 DO buffer[i]:=Ord(_message[i+1]);
          IF StrLen(PChar(_message))<message_length THEN BEGIN
            FOR i:=(StrLen(PChar(_message))) TO message_length-1 DO buffer[i]:=$00;
          END;
        END;
        WriteMem(adr_message,message_length,buffer);
        buffer[0]:=1;
        WriteMem(adr_trigger,1,buffer);
      END;
    END;
  END;

FUNCTION Decode_Int(buffer:byte_array):LongWord;
  BEGIN
    result:=buffer[0]+buffer[1]*256+buffer[2]*256*256+buffer[3]*256*256*256;
  END;

FUNCTION Decode_Float(buffer:byte_array):Single;
  BEGIN
    _valueswitcher.ValueInt:=Decode_Int(buffer);
    result:=_valueswitcher.ValueFloat;
  END;

FUNCTION Decode_Str(buffer:byte_array):String;
  VAR i:Byte;
  BEGIN
    FOR i:=0 TO 249 DO BEGIN
      IF buffer[i]=0 THEN break
      ELSE result:=result+Chr(buffer[i]);
    END;
  END;
FUNCTION Encode_Int(input:LongWord):byte_array;
  BEGIN
    result[0]:=input MOD 256;
    input:=input DIV 256;
    result[1]:=input MOD 256;
    input:=input DIV 256;
    result[2]:=input MOD 256;
    input:=input DIV 256;
    result[3]:=input MOD 256;
  END;
FUNCTION Encode_Float(input:Single):byte_array;
  BEGIN
    _valueswitcher.ValueFloat:=input;
    result:=Encode_Int(_valueswitcher.ValueInt);
  END;
FUNCTION Encode_Str(input:String;bytes:Byte):byte_array;
  VAR i:Byte;
  BEGIN
    FOR i:=1 TO bytes DO BEGIN
      IF i<=Length(input) THEN BEGIN
        result[i-1]:=Ord(input[i]);
      END ELSE BEGIN
        result[i-1]:=$00;
      END;
    END;
  END;

FUNCTION ConnectToProcess:Boolean;
  BEGIN
    _WindowHandle:=FindWindowA(''{_WindowClass},_WindowName);
    IF not (_WindowHandle>0) THEN BEGIN
      result:=False;
      exit;
    END;
    GetWindowThreadProcessId(_WindowHandle, _ProcessID);
    IF not (_ProcessID>0) THEN BEGIN
      result:=False;
      exit;
    END;
    _ProcessHandle:=OpenProcess(PROCESS_ALL_ACCESS, 0, _ProcessID);
    IF not (_ProcessHandle>0) THEN BEGIN
      result:=False;
      exit;
    END;
    result:=True;
  END;
FUNCTION ReadMem(address:longword; size:longword):byte_array;
  VAR _buffer:byte_array;
    temp:longword;
  BEGIN
    FOR temp:=0 TO 250 DO _buffer[temp]:=0;
    IF NOT (ReadProcessMemory(_ProcessHandle, address, _buffer, size, temp)>0) THEN BEGIN
      _buffer[250]:=123;
    END;
    result:=_buffer;
  END;
FUNCTION WriteMem(address:longword; size:longword; _buffer:byte_array):boolean;
  VAR temp:longword;
  BEGIN
    IF NOT (WriteProcessMemory(_ProcessHandle, address, _buffer, size, temp)>0) THEN BEGIN
      result:=False;
    END ELSE BEGIN
      result:=True;
    END;
  END;

PROCEDURE SetWindowAOT(Handle:Cardinal;AOT:Boolean);
  VAR aot_value:Integer;
  BEGIN
    IF AOT THEN aot_value:=HWND_TOPMOST
    ELSE aot_value:=HWND_NOTOPMOST;
    SetWindowPos(Handle,aot_value,0,0,0,0,SWP_NOACTIVATE+SWP_NOMOVE+SWP_NOOWNERZORDER+SWP_NOSIZE);
  END;

end.
