Ну и под занавес:
Незаконченный проект "Трейдер".
http://newvlad.nm.ru/trader.html
На тот момент все функции работали.
Принцип работы:
Создавался файл отчетности temp.log, где структурированно отмечались любые запросы на трейдеров и где хранились все операции.
Code: Select all
...
2|2|9|27.02.2009 3:40:11|3|9199|401603|Dark Man|
2|2|13|27.02.2009 3:40:48|45|9154|401603|Dark Man|
2|1|0|27.02.2009 3:42:24|5|9164|401603|Dark Man|
2|1|Disc|27.02.2009 3:42:26|5|9164|401603|Dark Man|
2|1|Disc|27.02.2009 3:42:28|5|9164|401603|Dark Man|
...
Синхронизация по времени происходила в связке комп - и метка на руне на которой писалось время путем переименования руны 
За счет этого было не возможно сбить или обмауть чаров если шарды откатились. Тоесть трейдеры постоянно сверяли метку времени и если произошел откат то все операции совершенные после места отката аннулировались.
Все проведенные тесты были успешными.
Чары со 100% успехом принимали и передавали деньги на лагах на откатах и тд.
В описании не исправлено одна вещь. 
Надо указывать при переводе гп - ИД чара получателя.
--
А теперь расскажу чуть-чуть о неосуществленных мечтах, эхх...
В планы входило прикрутить интернет магазин, через который можно было бы купить вещь или гп в игре за реальные $.
Любой желающий в игре мог положить на чара предмет или перевести гп (предварительно оформив товар в инет магазине) и указав цену.
Клиент заходит в магазин выбирает товар оплачивает, после чего в игре получает товар с трейдера-бота.
Ну поскольку все это требовало времени а времени нет то быть может кому-то мои разработки будут полезны.
===
Trader1
Code: Select all
Program New;
//EXPER1
{$Include 'all.inc'}
const
fname='C:\games\uo\stealth_v1.0 (rc 3)\Stealth_v1.0 (RC 3)\temp.log';
NumberBot=1;
NumberBotOther=2;
IdOtherBot=$000194F6;
IdSelf=$000CB284;
Runa=$4024FBCC;
TimeToSaveSphere=36.0;
TimeToInfoMsg=600000; // 1000 = 1 sec
TimeToSynhro=20000;
TradeKurs=1.0;
MaxTradeGp=10000;
MinTradeGp=10;
var
IdClient, MyGold,IdGainer : Cardinal;
NameClient : String;
starttime, TimeClient : TDateTime;
GoldCoin : array[1..3] of Cardinal;
i :Integer;
FrazeGoodbye : String;
InfoTimer ,SynchroTimer : TTimer;
Procedure CheckGold;
begin
  SetGlobal('stealth','GoldO1',IntToStr(Gold));
end;
procedure WaitConnectionEx(WaitTime : Integer);
begin
if Connected then Exit;
while not Connected do begin SetGlobal('stealth',IntToStr(IdSelf),'0'); Wait(1000); SetGlobal('stealth','TestVar1',IntToStr(IdSelf)); end;
{WaitTime - Waiting After Connected}
wait(WaitTime);
SetGlobal('stealth',IntToStr(self),'1');
end;
Procedure PutMoneyBank;
var
j:Integer;
Bank: Cardinal;
begin
  uosay('bank');
  checklag;
  Bank:=ObjAtLayer(BankLayer);
  if Bank <> 0 then
  begin
    for j:=1 to 3 do  
	  while CountEx(GoldCoin[j],$0000,backpack) > 0 do 
	  begin
	    if (FindTypeEx (GoldCoin[j],$0000,Backpack,True) > 0) then MoveItem(FindItem,0,Bank,0,0,0);
		checklag;
	  end;
  end;
end;
Function GetMoneyBank(TransferGold : Cardinal) : Boolean;
var j,i : Integer;
BackPackGold ,BankGold, Bank: Cardinal;
t: TDateTime;
begin
  if TransferGold > Gold then begin Result:=false; exit; end;
  
  BackPackGold := 0;
  BankGold := 0;
  
  for j:=1 to 3 do  BackPackGold := BackPackGold + CountEx(GoldCoin[j],$0000,backpack);
  
  if BackPackGold >= TransferGold then begin Result:=true; exit; end;
  
  uosay('bank');
  checklag;
  Bank:=ObjAtLayer(BankLayer);
  if Bank = 0 then begin Result:=false; exit; end; 
  t := Now;
  while BackPackGold < TransferGold do
  begin
    BankGold := TransferGold - BackPackGold;
    for j:=1 to 3 do   
      if (FindTypeEx (GoldCoin[j],$0000,Bank,True) > 0) then 
      begin
        MoveItem(FindItem,BankGold,backpack,0,0,0);
        checklag;
        BackPackGold:=0;
        for i:=1 to 3 do  BackPackGold := BackPackGold + CountEx(GoldCoin[i],$0000,backpack);
        BankGold := TransferGold - BackPackGold;
      end;
  end;
  BackPackGold:=0;
  for i:=1 to 3 do  BackPackGold := BackPackGold + CountEx(GoldCoin[i],$0000,backpack);
  Result := BackPackGold >= TransferGold;
end;
Function RuneRename(Id:Cardinal;Text:String):boolean;
var
Time : TDateTime;
 begin
   Time:=Now;
   useobject(Id);
   checklag;
   if IsSystemMsg('What is the new name',Time,Now) then begin ConsoleEntryReply(Text);Result:=true; end
   else Result:=false;   
 end;
Function RuneGetName(Id:Cardinal) : String ;
var
Time : TDateTime;
 begin
  Time:=Now;
  ClickOnObject(Id);
  checklag;
  if (InJournalBetweenTimes('Rune to',Time,Now) > -1) and (LineID=Id)  then Result:=Journal(LineIndex)
  else Result:='false'; 
 end;
Procedure GoMe;
begin
 uosay('; Добрый день, '+NameClient+'! Ваш ID: '+IntToHex(IdClient,8));
 wait(2000);
end;
Procedure GoExit;
begin
 uosay('; Неверная команда');
 wait(1000);
end;
Procedure GoKurs;
begin
 uosay('Курс нашего обменного пункта Офри->Опей на сегодняшний день : '+ Copy(FloatToStr(TradeKurs),0,3));
 wait(2000);
 uosay('За 10000 золотых тут вы получаете : '+ IntToStr(Round(10000*TradeKurs))+' золотых на Опей');
 wait(4000);
end;
Procedure GoHelp;
begin
 uosay('; '+NameClient+'! Вас приветствует обменный пункт золота с шарда Oskom Free на шард Oskom Pay');
 wait(5000);
 uosay(';  Для обмена денег наберите команду "!trade"');
 wait(5000);
 uosay(';  Для завершения операции обмена денег с Опей на Офри наберите "!give"');
 wait(5000);
 uosay(';  Узнать курс обмена Офри->Опей "!kurs"');
 wait(5000);
end;
Procedure Synchronization;
var 
f,Line,Line2 : TStringList;
s : string;
RuneTime : TDateTime;
i,j, NGive : Integer;
begin
  checklag;
  WaitConnectionEx(2000);
  s:=RuneGetName(Runa);
  if s <> 'false' then 
  begin
	  RuneTime:=StrToDateTime(copy(s,24,Length(S)-23));
	  while GetGlobal('stealth','FileAccessFlag') <> '0' do wait(20);
	  SetGlobal('stealth','FileAccessFlag','1');
	  f := TStringList.Create;
	  Line := TStringList.Create;
	  try
		 try
		   f.loadFromFile(fname);
		 except
		   f.SaveToFile(fname);
		 end;
		 if f.Count > 0 then for i := f.Count - 1 downto 0 do
		   begin
			  StrBreakApart(f.Strings[i],'|',Line);
			  if (Line.Strings[0] = intToStr(NumberBot)) and (StrToDateTime(Line.Strings[3]) = RuneTime) then 
				begin
				   Line.clear;
				   Break;
				end;
			  if (Line.Strings[0] = intToStr(NumberBot)) and (Line.Strings[2] <> 'Disc') and (StrToDateTime(Line.Strings[3]) > RuneTime) and (Line.Strings[1] <> '3') then
				begin
				   if (Line.Strings[1] = '2') and (Line.Strings[2] <> 'Err') then 
				   begin 
					 NGive := StrToInt(Line.Strings[2]);
					 Line2 := TStringList.Create;
					 StrBreakApart(f.Strings[NGive],'|',Line2);
					 if Line2.Strings[2] = '1' then
					 begin
					   s:='';
					   Line2.Delete(2);
					   Line2.Insert(2,'0');
					   for j:=0 to Line2.Count - 1 do 
					   begin 
						 s:=s+Line2.Strings[j]; 
						 if (j <> Line2.Count - 1) then s:=s+'|'; 
					   end; 
					   f.Delete(NGive);
					   f.Insert(NGive,s);
					 end;
					 Line2.Free;
				   end;
				   s:='';
				   Line.Delete(2);
				   Line.Insert(2,'Disc');
				   for j:=0 to Line.Count - 1 do begin s:=s+Line.Strings[j]; if j<>Line.Count - 1 then s:=s+'|'; end; 
				   f.Delete(i);
				   f.Insert(i,s);
				end; 
			  Line.Clear;
		   end;
		 f.SaveToFile(fname);
	  finally
		 Line.Free;
		 f.Free;
	  end;
	  SetGlobal('stealth','FileAccessFlag','0');
  end
  else addtosystemjournal('Ошибка синхронизации о1');
end;
Procedure InsertInLog(var i:Integer; s : String);
var
f : TStringList;
begin
 while GetGlobal('stealth','FileAccessFlag') <> '0' do wait(20);
  SetGlobal('stealth','FileAccessFlag','1');
  f := TStringList.Create;
  try
     try
       f.loadFromFile(fname);
     except
       f.SaveToFile(fname);
     end;
	 f.Delete(i);
     f.Insert(i,s);
     f.SaveToFile(fname);
  finally
      f.Free;
  end;
  SetGlobal('stealth','FileAccessFlag','0');
end;
Procedure AddToLog(var s:String);
var
f : TStringList;
begin
 while GetGlobal('stealth','FileAccessFlag') <> '0' do wait(20);
  SetGlobal('stealth','FileAccessFlag','1');
  f := TStringList.Create;
  try
     try
       f.loadFromFile(fname);
     except
       f.SaveToFile(fname);
     end;
     f.Add(s);
     f.SaveToFile(fname);
  finally
      f.Free;
  end;
  SetGlobal('stealth','FileAccessFlag','0');
end;
Procedure GoGive;
var
f,Line : TStringList;
i ,j,k,ChkG: Integer;
TmpGold, GoldInContainer, TransferGold, OpponentContainer, MyContainer : Cardinal;
TimeOperand : TDateTime;
TradeString, InsertString, Ok : String;
begin
  FrazeGoodbye:='; Для вас ничего нет.';
  uosay('; Добрый день, '+NameClient+'!');
  wait(2000);
  checklag;
  WaitConnectionEx(2000);
  if GetGlobal('stealth',IntToStr(IdOtherBot)) <> '1' then
  begin
    uosay('; Извините, сервис временно не доступен.');
	exit;
  end;
  //uosay('; Работаем');
  f := TStringList.Create;
  try
     f.loadFromFile(fname);
  except
     f.SaveToFile(fname);
  end;
  Line := TStringList.Create;
  if f.Count > 0 then for i := 0 to f.Count - 1 do
	   begin
    	  StrBreakApart(f.Strings[i],'|',Line);
		  if (Line.Strings[0] = intToStr(NumberBotOther)) and (Line.Strings[1] = '1') and (Line.Strings[2] = '0') and (Line.Strings[8] = intToStr(IdClient)) then 
		    begin
			   if (StrToDateTime(Line.Strings[3]) + (TimeToSaveSphere/86400) > Now) then
			   begin
				  FrazeGoodbye:='; Вы сможете завершить операцию по прошествии 1 часа.';
				  break;
			   end;
			   //UOSAY('ok');
			   TransferGold:=StrToInt(Line.Strings[4]);
			   if not GetMoneyBank(TransferGold) then
			   begin
			     FrazeGoodbye:='; Нету наличности в банке, или недоступен банк, оповесите сервис центр icq 9745475 .';
				 break;
			   end;
			   if not ((GetDistance(IdClient) < 3) and (GetDistance(IdClient) <> -1) and (GetZ(self) = GetZ(IdClient)) and (not IsDead(IdClient))) then
			     begin
				   FrazeGoodbye:='; Пожалуйста, подойдите ближе.';
				   break;
				 end;
			   if TradeCount() >0 then for j:= TradeCount() - 1 DownTo 0 do CancelTrade(j);
			   checklag;
			   WaitConnectionEx(2000); 
			   for j:=1 to 3 do
			     if (FindTypeEx (GoldCoin[j],$0000,backpack,True) > 0) then begin MoveItem(FindItem,TransferGold,IdClient,0,0,0); break; end;
				
			   FrazeGoodbye:='; Извините, меня ждут другие дела'; 
			   checklag;
			   WaitConnectionEx(2000);
			   repeat
			   if TradeCount()>0 then
				 for k:= TradeCount() - 1 DownTo 0 do
				   begin
					 if (GetTradeOpponent(k) <> IdClient) then CancelTrade(k)
					 else 
					   begin
						  OpponentContainer := GetTradeContainer(k,2);
						  MyContainer :=  GetTradeContainer(k,1);
						  //AddToSystemJournal('Nomer '+inttostr(k)+' count '+inttostr(TradeCount()));
						  GoldInContainer:=0;
						  for j:=1 to 3 do  GoldInContainer := GoldInContainer + CountEx(GoldCoin[j],$0000,MyContainer);
						  TmpGold := TransferGold - GoldInContainer;
						  for j:=1 to 3 do  
							  while (GetDistance(MyContainer) = 0) and (GoldInContainer < TransferGold) and (CountEx(GoldCoin[j],$0000,backpack) > 0) do 
							  begin
								if (FindTypeEx (GoldCoin[j],$0000,Backpack,True) > 0) then MoveItem(FindItem,TmpGold,MyContainer,0,0,0);
								checklag;
								GoldInContainer:=0;
						  		for ChkG:=1 to 3 do  GoldInContainer := GoldInContainer + CountEx(GoldCoin[ChkG],$0000,MyContainer);
								TmpGold := TransferGold - GoldInContainer;
							  end;
						  //uosay(IntToStr(i)+' '+IntToStr(TransferGold));
						  uosay('; Подтвердите передачу.');
							
						  
						  if (FindType($FFFF,OpponentContainer) = 0) and TradeCheck(k,2) and (GoldInContainer = TransferGold) and (GetTradeOpponent(k) = IdClient) then 
						  begin
						    ConfirmTrade(k);
							TimeClient := 0;
							uosay('; Выдано денег : '+IntToStr(TransferGold));
							checklag();
						    Synchronization; // synchronization
							checklag;
							WaitConnectionEx(2000);
							if (Gold = MyGold - TransferGold) Then
						    begin //Ok trading
							  MyGold:=Gold; 
							  Ok:= IntToStr(i);
						    end
						    else // Bad Trading
							  Ok:= 'Err';
						    TimeOperand:=Now;
							checklag;
							WaitConnectionEx(2000);
							while not RuneRename(Runa,DateTimeToStr(TimeOperand)) do begin wait(100); checklag; WaitConnectionEx(2000); end;
							If Ok <> 'Err' then
							 begin 
							    Line.Delete(2);
								Line.Insert(2,'1');
								for j:=0 to Line.Count - 1 do 
								begin 
								  InsertString:=InsertString+Line.Strings[j]; 
								  if (j <> Line.Count - 1) then InsertString:=InsertString+'|'; 
								end; 
								InsertInLog(i,InsertString);
							 end;
						   TradeString:=intToStr(NumberBot)+'|'+'2'+'|'+Ok+'|'+DateTimeToStr(TimeOperand)+'|'+intToStr(TransferGold)+'|'+intToStr(MyGold)+'|'+intToStr(IdClient)+'|'+NameClient+'|'+intToStr(IdClient)+'|';
                            AddToLog(TradeString);
							FrazeGoodbye:=('; Спасибо за использование наших услуг! Ждем вас снова!'); 
						  end;	  
					   end; 
				   end;
				wait(3000);
			   until (TimeClient + (20.0/86400) < Now);   
			   break;
			   
			end;
		  Line.clear;
       end;
  Line.free;
  f.clear;
  f.free;
  uosay(FrazeGoodbye);
  //wait(5000);
  //CheckGive;
end;
Procedure GoTrade;
var
i,j,k: integer;
AllGold,TmpGold,TransferGold, MaxMaxGp: Cardinal;
Flag : Boolean;
UserList : TStringList;
TimeOperand: TDateTime;
TradeString, Ok:String;
OpponentContainer ,TypeItem ,ColorItem : Cardinal;
begin
 FrazeGoodbye:='; Извините, меня ждут другие дела';
 if GetGlobal('stealth',IntToStr(IdOtherBot)) <> '1' then
  begin
    uosay('; Извините, сервис временно не доступен.');
	exit;
  end;
 MaxMaxGp:=Round(StrToInt(GetGlobal('stealth','GoldO2'))*TradeKurs);
 If MaxMaxGp > MaxTradeGp then MaxMaxGp := MaxTradeGp;
 
 uosay('; Добрый день, '+NameClient+'! Здесь вы можете осуществить перевод денег с этого шарда на шард Оском Opay по курсу '+ Copy(FloatToStr(TradeKurs),0,3));
 wait(2000);
 uosay('; Для этого положите на меня сумму в гп от '+IntToStr(Round(MinTradeGp))+' до '+IntToStr(MaxMaxGp)+', я вам пересчитаю по курсу ваши гп на ОPay');
 uosay('; ID Получателя: '+IntToHex(IdGainer,8));
 //wait(4000);
 //uosay('; После чего подтвердите перевод, перейдите на OPay, У MENALO2 командой !give заберите ваши гп');
  repeat
   if TradeCount()>0 then
     for i:= TradeCount() - 1 DownTo 0 do
       begin
         if (GetTradeOpponent(i) <> IdClient) then CancelTrade(i)
         else 
           begin
              OpponentContainer := GetTradeContainer(i,2);
              AddToSystemJournal('Nomer '+inttostr(i)+' count '+inttostr(TradeCount()));
              if (FindType($FFFF,OpponentContainer)>0) then
                begin
                   UserList := TStringList.Create(); 
                   GetFindedList(UserList);
                   Flag := true; 
                        for k := 0 to (UserList.Count-1) do
                          begin
                            //AddToSystemJournal('GOGO');
                            TypeItem := GetType(StrToInt('$'+UserList.strings[k]));
                            ColorItem := GetColor(StrToInt('$'+UserList.strings[k]));
                            //AddToSystemJournal(IntToStr(TypeItem));
                            //AddToSystemJournal(IntToStr(ColorItem));
                            if not ((TypeItem = GoldCoin[1]) or (TypeItem = GoldCoin[2]) or (TypeItem = GoldCoin[3])) and (ColorItem = $0000) then Flag := false;
                          end;
                   UserList.free;
                   TmpGold:= AllGold;
                   AllGold:=0;
                   for j:=1 to 3 do  AllGold := AllGold + CountEx(GoldCoin[j],$0000,OpponentContainer);
                   if (not Flag) then uosay('; Уберите лишние предметы, только золотые монеты')
                   else 
                     begin
                       if TradeCheck(i,2) and (AllGold > MinTradeGp) and (AllGold < MaxMaxGp) then
                         begin
                           ConfirmTrade(i);
                           TmpGold:=AllGold;
                           TransferGold:=Round(AllGold*TradeKurs);
                           uosay('; Получено денег : '+IntToStr(TmpGold));
                           uosay('; Будет выдано денег : '+IntToStr(TransferGold));
						   uosay('; ID Получателя: '+IntToHex(IdGainer,8));
                           checklag();
						   Synchronization; // synchronization
						   checklag;
						   WaitConnectionEx(2000);
						   // Запись в файл
						   if (TmpGold + MyGold = Gold) Then
						   begin //Ok trading
							 MyGold:=Gold; 
							 Ok:= '0';
						   end
						   else // Bad Trading
							 Ok:= 'Err';
						   TimeOperand:=Now;
						   checklag;
						   WaitConnectionEx(2000);
						   while not RuneRename(Runa,DateTimeToStr(TimeOperand)) do begin wait(100); checklag; WaitConnectionEx(2000); end;
						   TradeString:=intToStr(NumberBot)+'|'+'1'+'|'+Ok+'|'+DateTimeToStr(TimeOperand)+'|'+intToStr(TransferGold)+'|'+intToStr(MyGold)+'|'+intToStr(IdClient)+'|'+NameClient+'|'+intToStr(IdGainer)+'|';
                           AddToLog(TradeString);
                           wait(2000);
                           uosay('; Чтобы получить деньги наберите получателем в обменном пункте на шарде OPay команду "!give" ');
                           FrazeGoodbye:=('; Спасибо за использование наших услуг! Ждем вас снова!'); 
                           TimeClient := 0;
                         end
                       else
                         begin
                           if (TmpGold<>AllGold) then uosay(';  Ofree: '+IntToStr(AllGold)+' Opay: '+IntToStr(Round(AllGold*TradeKurs))+' . Подтвердите Перевод');
                           TimeClient:=TimeClient+(2.8/86400);
                         end;
                     end;
                end;
           end; 
       end;
    wait(3000);
  until (TimeClient + (30.0/86400) < Now);
  uosay(FrazeGoodbye);
  checklag;
  WaitConnectionEx(2000);
  PutMoneyBank;
  for i:= TradeCount() - 1 DownTo 0 do CancelTrade(i);
end;
Function CheckIdInString(s : String; Pos : Integer) : Integer;
var
i,j : Integer;
a : array of char; 
Flag : Boolean;
begin
  if not (Length(s) = Pos+15) then begin result := 0; exit; end;
  s:=Lowercase(s);
  a:=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
  for i:=Pos+8 to Pos+15 do
  begin
    Flag := false;
    for j:=0 to 15 do if (s[i] = a[j]) then Flag := true;
	if not Flag then begin result := 0; exit; end;
  end;
  result := StrToInt(Copy(s,Pos+7,9));
end;
Procedure ChooseCommand;
begin
   //addtosystemjournal(inttostr(BMSearch(0,Journal(LineIndex),'!trade')));
   //addtosystemjournal(Journal(LineIndex)[1]);
   //addtosystemjournal(Journal(LineIndex)[2]);
   if (BMSearch(0,Journal(LineIndex),'!trade $')>0) then
     begin
	   IdGainer:= CheckIdInString(Journal(LineIndex),BMSearch(0,Journal(LineIndex),'!trade $'));
	   if IdGainer > 0 then GoTrade else GoExit;
	 end
   else if BMSearch(0,Journal(LineIndex),'!give')>0 then GoGive
   else if BMSearch(0,Journal(LineIndex),'!kurs')>0 then GoKurs
   else if BMSearch(0,Journal(LineIndex),'!help')>0 then GoHelp
   else if BMSearch(0,Journal(LineIndex),'!me')>0 then GoMe
   else GoExit;
end;
begin
   GoldCoin[1] := $0EED;
   GoldCoin[2] := $0EEE;
   GoldCoin[3] := $0EEF;
   SetARStatus(true);
   WaitConnectionEx(2000);
   MyGold := Gold;
   
   InfoTimer := setTimer(TimeToInfoMsg);
   SynchroTimer := setTimer(TimeToSynhro); // 300k - 5 min
   SetGlobal('stealth','FileAccessFlag','0');
   SetGlobal('stealth',IntToStr(self),'1');
  repeat
   starttime := Now;
   repeat
      //checklag;
	  WaitConnectionEx(2000);
      //addtosystemjournal(inttostr(TradeCount()));
      if TradeCount() >0 then
        for i:= 0 To TradeCount()-1 do CancelTrade(i); 
      //if  (MsgTimeOut + (40.0/86400) < Now) then 
	  if isTimer(InfoTimer) then
        begin
          resetTimer(InfoTimer);
          uosay('Работает обменный пункт, подробности команда "!hеlp"      http://admir.info');
        end; 
	  if isTimer(SynchroTimer) then
        begin
          resetTimer(SynchroTimer);
          Synchronization;
		  CheckGold;
        end; 
   until (InJournalBetweenTimes('!trade|!give|!help|!kurs|!me', starttime, Now)<>-1);
   if (LineName <> 'System') and (GetDistance(LineID) < 3) and (GetDistance(LineID) <> -1) and (GetZ(self) = GetZ(LineID)) and (not IsDead(LineID)) then
     begin
       IdClient := LineID;
       NameClient := LineName;
       TimeClient :=  LineTime;
       ChooseCommand;
     end;
  until (InJournalBetweenTimes('!stop', starttime, Now)<>-1); 
    
    
end.       
                  
Trader2
Code: Select all
Program New;
//lA2
{$Include 'all.inc'}
const
fname='C:\games\uo\stealth_v1.0 (rc 3)\Stealth_v1.0 (RC 3)\temp.log';
NumberBot=2;
NumberBotOther=1;
IdOtherBot=$000CB284;
IdSelf=$000194F6;
Runa=$40111E9B;
TimeToSaveSphere=36.0;
TimeToInfoMsg=600000; // 1000 = 1 sec
TimeToSynhro=20000;
TradeKurs=1.0;
MaxTradeGp=10000;
MinTradeGp=10;
var
IdClient, MyGold : Cardinal;
NameClient : String;
starttime, TimeClient : TDateTime;
GoldCoin : array[1..3] of Cardinal;
i :Integer;
FrazeGoodbye : String;
InfoTimer ,SynchroTimer : TTimer;
Procedure CheckGold;
begin
  SetGlobal('stealth','GoldO2',IntToStr(Gold));
end;
procedure WaitConnectionEx(WaitTime : Integer);
begin
if Connected then Exit;
while not Connected do begin SetGlobal('stealth',IntToStr(IdSelf),'0'); Wait(1000); end;
{WaitTime - Waiting After Connected}
wait(WaitTime);
SetGlobal('stealth',IntToStr(self),'1');
end;
Procedure PutMoneyBank;
var
j:Integer;
Bank: Cardinal;
begin
  uosay('bank');
  checklag;
  Bank:=ObjAtLayer(BankLayer);
  if Bank <> 0 then
  begin
    for j:=1 to 3 do  
      while CountEx(GoldCoin[j],$0000,backpack) > 0 do 
      begin
        if (FindTypeEx (GoldCoin[j],$0000,Backpack,True) > 0) then MoveItem(FindItem,0,Bank,0,0,0);
        checklag;
      end;
  end;
end;
Function GetMoneyBank(TransferGold : Cardinal) : Boolean;
var j,i : Integer;
BackPackGold ,BankGold, Bank: Cardinal;
t: TDateTime;
begin
  if TransferGold > Gold then begin Result:=false; exit; end;
  
  BackPackGold := 0;
  BankGold := 0;
  
  for j:=1 to 3 do  BackPackGold := BackPackGold + CountEx(GoldCoin[j],$0000,backpack);
  
  if BackPackGold >= TransferGold then begin Result:=true; exit; end;
  
  uosay('bank');
  checklag;
  Bank:=ObjAtLayer(BankLayer);
  if Bank = 0 then begin Result:=false; exit; end; 
  t := Now;
  while BackPackGold < TransferGold do
  begin
    BankGold := TransferGold - BackPackGold;
    for j:=1 to 3 do   
      if (FindTypeEx (GoldCoin[j],$0000,Bank,True) > 0) then 
      begin
        MoveItem(FindItem,BankGold,backpack,0,0,0);
        checklag;
        BackPackGold:=0;
        for i:=1 to 3 do  BackPackGold := BackPackGold + CountEx(GoldCoin[i],$0000,backpack);
        BankGold := TransferGold - BackPackGold;
      end;
  end;
  BackPackGold:=0;
  for i:=1 to 3 do  BackPackGold := BackPackGold + CountEx(GoldCoin[i],$0000,backpack);
  Result := BackPackGold >= TransferGold;
end;
Function RuneRename(Id:Cardinal;Text:String):boolean;
var
Time : TDateTime;
 begin
   Time:=Now;
   useobject(Id);
   checklag;
   if IsSystemMsg('What is the new name',Time,Now) then begin ConsoleEntryReply(Text);Result:=true; end
   else Result:=false;   
 end;
Function RuneGetName(Id:Cardinal) : String ;
var
Time : TDateTime;
 begin
  Time:=Now;
  ClickOnObject(Id);
  checklag;
  if (InJournalBetweenTimes('Rune to',Time,Now) > -1) and (LineID=Id)  then Result:=Journal(LineIndex)
  else Result:='false'; 
 end;
Procedure GoMe;
begin
 uosay('; Добрый день, '+NameClient+'! Ваш ID: '+IntToHex(IdClient,8));
 wait(2000);
end;
Procedure GoExit;
begin
 uosay('goexit');
end;
Procedure GoKurs;
begin
 uosay('Курс нашего обменного пункта Опей->Офри на сегодняшний день : '+ Copy(FloatToStr(TradeKurs),0,3));
 wait(2000);
 uosay('За 10000 золотых тут вы получаете : '+ IntToStr(Round(10000*TradeKurs))+' золотых на Офри');
 wait(4000);
end;
Procedure GoHelp;
begin
 uosay('; '+NameClient+'! Вас приветствует обменный пункт золота с шарда Oskom Opay на шард Oskom Free');
 wait(5000);
 uosay(';  Для обмена денег наберите команду "!trade"');
 wait(5000);
 uosay(';  Для завершения операции обмена денег с Офри на Опей наберите "!give"');
 wait(5000);
 uosay(';  Узнать курс обмена Опей->Офри "!kurs"');
 wait(5000);
end;
Procedure Synchronization;
var 
f,Line,Line2 : TStringList;
s : string;
RuneTime : TDateTime;
i,j, NGive : Integer;
begin
  checklag;
  WaitConnectionEx(2000);
  s:=RuneGetName(Runa);
  if s <> 'false' then 
  begin
      RuneTime:=StrToDateTime(copy(s,24,Length(S)-23));
      while GetGlobal('stealth','FileAccessFlag') <> '0' do wait(20);
      SetGlobal('stealth','FileAccessFlag','1');
      f := TStringList.Create;
      Line := TStringList.Create;
      try
         try
           f.loadFromFile(fname);
         except
           f.SaveToFile(fname);
         end;
         if f.Count > 0 then for i := f.Count - 1 downto 0 do
           begin
              StrBreakApart(f.Strings[i],'|',Line);
              if (Line.Strings[0] = intToStr(NumberBot)) and (StrToDateTime(Line.Strings[3]) = RuneTime) then 
                begin
                   Line.clear;
                   Break;
                end;
              if (Line.Strings[0] = intToStr(NumberBot)) and (Line.Strings[2] <> 'Disc') and (StrToDateTime(Line.Strings[3]) > RuneTime) and (Line.Strings[1] <> '3') then
                begin
                   if (Line.Strings[1] = '2') and (Line.Strings[2] <> 'Err') then 
                   begin 
                     NGive := StrToInt(Line.Strings[2]);
                     Line2 := TStringList.Create;
                     StrBreakApart(f.Strings[NGive],'|',Line2);
                     if Line2.Strings[2] = '1' then
                     begin
                       s:='';
                       Line2.Delete(2);
                       Line2.Insert(2,'0');
                       for j:=0 to Line2.Count - 1 do 
                       begin 
                         s:=s+Line2.Strings[j]; 
                         if (j <> Line2.Count - 1) then s:=s+'|'; 
                       end; 
                       f.Delete(NGive);
                       f.Insert(NGive,s);
                     end;
                     Line2.Free;
                   end;
                   s:='';
                   Line.Delete(2);
                   Line.Insert(2,'Disc');
                   for j:=0 to Line.Count - 1 do begin s:=s+Line.Strings[j]; if j<>Line.Count - 1 then s:=s+'|'; end; 
                   f.Delete(i);
                   f.Insert(i,s);
                end; 
              Line.Clear;
           end;
         f.SaveToFile(fname);
      finally
         Line.Free;
         f.Free;
      end;
      SetGlobal('stealth','FileAccessFlag','0');
  end
  else addtosystemjournal('Ошибка синхронизации о2');
end;
Procedure InsertInLog(var i:Integer; s : String);
var
f : TStringList;
begin
 while GetGlobal('stealth','FileAccessFlag') <> '0' do wait(20);
  SetGlobal('stealth','FileAccessFlag','1');
  f := TStringList.Create;
  try
     try
       f.loadFromFile(fname);
     except
       f.SaveToFile(fname);
     end;
     f.Delete(i);
     f.Insert(i,s);
     f.SaveToFile(fname);
  finally
      f.Free;
  end;
  SetGlobal('stealth','FileAccessFlag','0');
end;
Procedure AddToLog(var s:String);
var
f : TStringList;
begin
 while GetGlobal('stealth','FileAccessFlag') <> '0' do wait(20);
  SetGlobal('stealth','FileAccessFlag','1');
  f := TStringList.Create;
  try
     try
       f.loadFromFile(fname);
     except
       f.SaveToFile(fname);
     end;
     f.Add(s);
     addtosystemjournal('addtolog');
     f.SaveToFile(fname);
  finally
      f.Free;
  end;
  SetGlobal('stealth','FileAccessFlag','0');
end;
Procedure GoGive;
var
f,Line : TStringList;
i ,j,k,ChkG: Integer;
TmpGold, GoldInContainer, TransferGold, OpponentContainer, MyContainer : Cardinal;
TimeOperand : TDateTime;
TradeString, InsertString, Ok : String;
begin
  FrazeGoodbye:='; Для вас ничего нет.';
  uosay('; Добрый день, '+NameClient+'!');
  wait(2000);
  checklag;
  WaitConnectionEx(2000);
  //addtosystemjournal(GetGlobal('stealth',IntToStr(IdOtherBot)))
  if GetGlobal('stealth',IntToStr(IdOtherBot)) <> '1' then
  begin
    uosay('; Извините, сервис временно не доступен.');
    exit;
  end;
  //uosay('; Работаем');
  f := TStringList.Create;
  try
     f.loadFromFile(fname);
  except
     f.SaveToFile(fname);
  end;
  Line := TStringList.Create;
  if f.Count > 0 then for i := 0 to f.Count - 1 do
       begin
          StrBreakApart(f.Strings[i],'|',Line);
          if (Line.Strings[0] = intToStr(NumberBotOther)) and (Line.Strings[1] = '1') and (Line.Strings[2] = '0') and (Line.Strings[6] = intToStr(IdClient)) then 
            begin
               if (StrToDateTime(Line.Strings[3]) + (TimeToSaveSphere/86400) > Now) then
               begin
                  FrazeGoodbye:='; Вы сможете завершить операцию по прошествии 1 часа.';
                  break;
               end;
               //UOSAY('ok');
               TransferGold:=StrToInt(Line.Strings[4]);
               if not GetMoneyBank(TransferGold) then
               begin
                 FrazeGoodbye:='; Нету наличности в банке, или недоступен банк, оповесите сервис центр icq 9745475 .';
                 break;
               end;
               if not ((GetDistance(IdClient) < 3) and (GetDistance(IdClient) <> -1) and (GetZ(self) = GetZ(IdClient)) and (not IsDead(IdClient))) then
                 begin
                   FrazeGoodbye:='; Пожалуйста, подойдите ближе.';
                   break;
                 end;
                
               if TradeCount() >0 then for j:= TradeCount() - 1 DownTo 0 do CancelTrade(j); 
               checklag;
               WaitConnectionEx(2000);
               for j:=1 to 3 do
                 if (FindTypeEx (GoldCoin[j],$0000,backpack,True) > 0) then begin MoveItem(FindItem,TransferGold,IdClient,0,0,0); break; end;
                
               FrazeGoodbye:='; Извините, меня ждут другие дела'; 
               checklag;
               WaitConnectionEx(2000);
               repeat
               if TradeCount()>0 then
                 for k:= TradeCount() - 1 DownTo 0 do
                   begin
                     if (GetTradeOpponent(k) <> IdClient) then CancelTrade(k)
                     else 
                       begin
                          OpponentContainer := GetTradeContainer(k,2);
                          MyContainer :=  GetTradeContainer(k,1);
                          //AddToSystemJournal('Nomer '+inttostr(k)+' count '+inttostr(TradeCount()));
                          GoldInContainer:=0;
                          for j:=1 to 3 do  GoldInContainer := GoldInContainer + CountEx(GoldCoin[j],$0000,MyContainer);
                          TmpGold := TransferGold - GoldInContainer;
                          for j:=1 to 3 do  
                              while (GetDistance(MyContainer) = 0) and (GoldInContainer < TransferGold) and (CountEx(GoldCoin[j],$0000,backpack) > 0) do 
                              begin
                                if (FindTypeEx (GoldCoin[j],$0000,Backpack,True) > 0) then MoveItem(FindItem,TmpGold,MyContainer,0,0,0);
                                checklag;
                                GoldInContainer:=0;
                                  for ChkG:=1 to 3 do  GoldInContainer := GoldInContainer + CountEx(GoldCoin[ChkG],$0000,MyContainer);
                                TmpGold := TransferGold - GoldInContainer;
                              end;
                            
                          uosay('; Подтвердите передачу.');
                            
                          
                          if (FindType($FFFF,OpponentContainer) = 0) and TradeCheck(k,2) and (GoldInContainer = TransferGold) and (GetTradeOpponent(k) = IdClient) then 
                          begin
                            ConfirmTrade(k);
                            TimeClient := 0;
                            uosay('; Выдано денег : '+IntToStr(TransferGold));
                            checklag();
                            Synchronization; // synchronization
                            checklag;
                            WaitConnectionEx(2000);
                            if (Gold = MyGold - TransferGold) Then
                            begin //Ok trading
                              MyGold:=Gold; 
                              Ok:= IntToStr(i);
                            end
                            else // Bad Trading
                              Ok:= 'Err';
                            TimeOperand:=Now;
                            checklag;
                            WaitConnectionEx(2000);
                            while not RuneRename(Runa,DateTimeToStr(TimeOperand)) do begin wait(100); checklag; WaitConnectionEx(2000); end;
                            //if not RuneRename(Runa,DateTimeToStr(TimeOperand)) then Ok:='Err';
                            If Ok <> 'Err' then
                             begin 
                                Line.Delete(2);
                                Line.Insert(2,'1');
                                for j:=0 to Line.Count - 1 do 
                                begin 
                                  InsertString:=InsertString+Line.Strings[j]; 
                                  if (j <> Line.Count - 1) then InsertString:=InsertString+'|'; 
                                end; 
                                InsertInLog(i,InsertString);
                             end;
                           TradeString:=intToStr(NumberBot)+'|'+'2'+'|'+Ok+'|'+DateTimeToStr(TimeOperand)+'|'+intToStr(TransferGold)+'|'+intToStr(MyGold)+'|'+intToStr(IdClient)+'|'+NameClient+'|';
                            AddToLog(TradeString);
                            FrazeGoodbye:=('; Спасибо за использование наших услуг! Ждем вас снова!'); 
                          end;      
                       end; 
                   end;
                wait(3000);
               until (TimeClient + (20.0/86400) < Now);   
               break;
               
            end;
          Line.clear;
       end;
  Line.free;
  f.clear;
  f.free;
  uosay(FrazeGoodbye);
  //wait(5000);
  //CheckGive;
end;
Procedure GoTrade;
var
i,j,k: integer;
AllGold,TmpGold,TransferGold, MaxMaxGp: Cardinal;
Flag : Boolean;
UserList : TStringList;
TimeOperand: TDateTime;
TradeString, Ok:String;
OpponentContainer ,TypeItem ,ColorItem : Cardinal;
begin
 if GetGlobal('stealth',IntToStr(IdOtherBot)) <> '1' then
  begin
    uosay('; Извините, сервис временно не доступен.');
    exit;
  end;
 MaxMaxGp:=Round(StrToInt(GetGlobal('stealth','GoldO1'))*TradeKurs);
 If MaxMaxGp > MaxTradeGp then MaxMaxGp := MaxTradeGp;
 FrazeGoodbye:='; Извините, меня ждут другие дела';
 uosay('; Добрый день, '+NameClient+'! Здесь вы можете осуществить перевод денег с этого шарда на шард Оском Free по курсу '+ Copy(FloatToStr(TradeKurs),0,3));
 wait(2000);
 uosay('; Для этого положите на меня сумму в гп от '+IntToStr(Round(MinTradeGp))+' до '+IntToStr(MaxMaxGp)+', я вам пересчитаю по курсу ваши гп на ОFree');
 //wait(4000);
 //uosay('; После чего подтвердите перевод, перейдите на OFree, У MENALO2 командой !give заберите ваши гп');
 checklag;
 WaitConnectionEx(2000);
  repeat
   if TradeCount()>0 then
     for i:= TradeCount() - 1 DownTo 0 do
       begin
         if (GetTradeOpponent(i) <> IdClient) then CancelTrade(i)
         else 
           begin
              OpponentContainer := GetTradeContainer(i,2);
              AddToSystemJournal('Nomer '+inttostr(i)+' count '+inttostr(TradeCount()));
              if (FindType($FFFF,OpponentContainer)>0) then
                begin
                   UserList := TStringList.Create(); 
                   GetFindedList(UserList);
                   Flag := true; 
                        for k := 0 to (UserList.Count-1) do
                          begin
                            //AddToSystemJournal('GOGO');
                            TypeItem := GetType(StrToInt('$'+UserList.strings[k]));
                            ColorItem := GetColor(StrToInt('$'+UserList.strings[k]));
                            //AddToSystemJournal(IntToStr(TypeItem));
                            //AddToSystemJournal(IntToStr(ColorItem));
                            if not ((TypeItem = GoldCoin[1]) or (TypeItem = GoldCoin[2]) or (TypeItem = GoldCoin[3])) and (ColorItem = $0000) then Flag := false;
                          end;
                   UserList.free;
                   TmpGold:= AllGold;
                   AllGold:=0;
                   for j:=1 to 3 do  AllGold := AllGold + CountEx(GoldCoin[j],$0000,OpponentContainer);
                   if (not Flag) then uosay('; Уберите лишние предметы, только золотые монеты')
                   else 
                     begin
                       if TradeCheck(i,2) and (AllGold > MinTradeGp) and (AllGold < MaxMaxGp) then 
                         begin
                           ConfirmTrade(i);
                           TmpGold:=AllGold;
                           TransferGold:=Round(AllGold*TradeKurs);
                           uosay('; Получено денег : '+IntToStr(TmpGold));
                           uosay('; Будет выдано денег : '+IntToStr(TransferGold));
                           checklag();
                           Synchronization; // synchronization
                           checklag;
                           WaitConnectionEx(2000);
                           // Запись в файл
                           if (TmpGold + MyGold = Gold) Then
                           begin //Ok trading
                             MyGold:=Gold; 
                             Ok:= '0';
                           end
                           else // Bad Trading
                             Ok:= 'Err';
                           TimeOperand:=Now;
                           checklag;
                           WaitConnectionEx(2000);
                           while not RuneRename(Runa,DateTimeToStr(TimeOperand)) do begin wait(100); checklag; WaitConnectionEx(2000); end;
                           TradeString:=intToStr(NumberBot)+'|'+'1'+'|'+Ok+'|'+DateTimeToStr(TimeOperand)+'|'+intToStr(TransferGold)+'|'+intToStr(MyGold)+'|'+intToStr(IdClient)+'|'+NameClient+'|';
                           AddToLog(TradeString);
                           wait(2000);
                           uosay('; Чтобы получить деньги наберите в обменном пункте на шарде OFree команду "!give" этим же чаром');
                           FrazeGoodbye:=('; Спасибо за использование наших услуг! Ждем вас снова!'); 
                           TimeClient := 0;
                         end
                       else
                         begin
                           if (TmpGold<>AllGold) then uosay(';  Opay: '+IntToStr(AllGold)+' free: '+IntToStr(Round(AllGold*TradeKurs))+' . Подтвердите Перевод');
                           TimeClient:=TimeClient+(2.8/86400);
                         end;
                     end;
                end;
           end; 
       end;
    wait(3000);
  until (TimeClient + (30.0/86400) < Now);
  uosay(FrazeGoodbye);
  checklag;
  WaitConnectionEx(2000);
  PutMoneyBank;
  for i:= TradeCount() - 1 DownTo 0 do CancelTrade(i);
end;
Procedure ChooseCommand;
begin
   if BMSearch(0,Journal(LineIndex),'!trade')>0 then GoTrade
   else if BMSearch(0,Journal(LineIndex),'!give')>0 then GoGive
   else if BMSearch(0,Journal(LineIndex),'!kurs')>0 then GoKurs
   else if BMSearch(0,Journal(LineIndex),'!help')>0 then GoHelp
   else if BMSearch(0,Journal(LineIndex),'!me')>0 then GoMe
   else GoExit;
end;
begin
   GoldCoin[1] := $0EED;
   GoldCoin[2] := $0EEE;
   GoldCoin[3] := $0EEF;
   MyGold := Gold;
   SetARStatus(true);
   InfoTimer := setTimer(TimeToInfoMsg);
   SynchroTimer := setTimer(TimeToSynhro); // 300k - 5 min
   SetGlobal('stealth','FileAccessFlag','0');
   SetGlobal('stealth',IntToStr(self),'1');
  repeat
   starttime := Now;
   repeat
      //checklag;
      WaitConnectionEx(2000);
      //addtosystemjournal(inttostr(TradeCount()));
      if TradeCount() >0 then
        for i:= 0 To TradeCount()-1 do CancelTrade(i); 
      //if  (MsgTimeOut + (40.0/86400) < Now) then 
      if isTimer(InfoTimer) then
        begin
          resetTimer(InfoTimer);
          uosay('Работает обменный пункт, подробности команда "!hеlp"      http://admir.info');
        end; 
      if isTimer(SynchroTimer) then
        begin
          resetTimer(SynchroTimer);
          Synchronization;
          CheckGold;
        end; 
   until (InJournalBetweenTimes('!trade|!give|!help|!kurs|!me', starttime, Now)<>-1);
   if (LineName <> 'System') and (GetDistance(LineID) < 3) and (GetDistance(LineID) <> -1) and (GetZ(self) = GetZ(LineID)) and (not IsDead(LineID)) then
     begin
       IdClient := LineID;
       NameClient := LineName;
       TimeClient :=  LineTime;
       ChooseCommand;
     end;
  until (InJournalBetweenTimes('!stop', starttime, Now)<>-1); 
    //addtosystemjournal(inttostr(GetTradeOpponent(0)));
    //addtosystemjournal(inttostr(TradeCount()));
    //addtosystemjournal(GetTradeOpponentName(0));
    //addtosystemjournal(inttostr(GetTradeContainer(0,1))); // 1- я 2 - оппонент
    //ConfirmTrade(0);
    //CancelTrade(0);
    //if TradeCheck(0,2) then  addtosystemjournal('ok1');  // 2 - оппонент   1- себя
    //uosay('!asd');
    
    
end.