Forum in READ ONLY mode! All questions and discussions on Discord official server, invite link: https://discord.gg/VxsGzJ7

Новый Эвент для вызова процедур по команде клиента

Only for requests.
Post Reply
Prof
Posts: 9
Joined: 09.01.2015 15:20

Новый Эвент для вызова процедур по команде клиента

Post by Prof »

Привет!

Я долго ломал голову о том, как нормально запускать скрипты стелса по хоткеям и нашел боле менее приемлемый костыль:
использование "evSpeech" евента и биндинга в клиенте кнопок на Whisper '....'

как работает:
запускается такой скрипт в главном окне стелса:

Code: Select all

Program Macros;
const
CarveCorpses = true;

var // GLOBAL VARS
ctimeq: TDatetime;
checkheal: integer;
Corpses : Array of Cardinal; 

{$Include 'common.inc'} 
{$Include 'heal.inc'} 
{$Include 'loot.inc'} 

procedure dispatcher(text,SenderName : String; SenderID : Cardinal);
begin
  if SenderID = Self then
  begin
    AddToSystemJournal('Event: ' + text);
    case text of
      'h' : Heal;
      'l' : SmartLoot;
    end;
  end;
end;

begin
 SetEventProc(evSpeech,'dispatcher');
 while not dead and connected do
  wait(100);
end.
Вкратце: код слушает, что скажет наш чар, и если услышит только буквы 'h' или 'l', то запустит нужные процедуры.

Далее, если уже в самом клиенте (даже без DLL, а с разором) сказать:

Code: Select all

; h
То запустится процедура лечения, что нам то и было нужно. Точка запятой вначале означает Whisper/шепот, т.е. то что чар скажет увидят только те, кто рядом с вами в пределах 1го тайла. Не палимся ... :)

Это решение весьма неудобно, потому что:
1. речь чара выводит из хайда
2. не очень быстро откликается
3. Это костыль

Что хочется:
Новый евент ("evExecCommand : [Command : String]" например), который будет дергаться, если клиент набрал команду вида ",exec heal", чтобы нивелировать все перечисленные недостатки.

Зачем хочется:
1. в запуске скриптов по хоткеям из DLL нельзя хранить состояние переменных между запусками. SetGloba/GetGlobal не устраивают из-за того, что можно хранить только строки, да и все скрипты переписывать нужно.
2. Ну все-таки хочется играть с разором для простых вещей и того + суперсложные скрипты стелса, вызываемые по хоткею.

Спасибо!
drabadan
Expert
Expert
Posts: 730
Joined: 13.12.2012 17:35
Contact:

Re: Новый Эвент для вызова процедур по команде клиента

Post by drabadan »

Prof wrote:1. в запуске скриптов по хоткеям из DLL нельзя хранить состояние переменных между запусками.
можно пример этого? Желательно выписать его кодом или, может, покажи одну из процедур которой ты бы хотел ето реализовать? Может есть другое решение таких задач?

Всегда можно написать себе внешний скрипт с соответствующими обработчиками, и не парить себе голову.
Prof
Posts: 9
Joined: 09.01.2015 15:20

Re: Новый Эвент для вызова процедур по команде клиента

Post by Prof »

drabadan wrote:
Prof wrote:1. в запуске скриптов по хоткеям из DLL нельзя хранить состояние переменных между запусками.
можно пример этого? Желательно выписать его кодом или, может, покажи одну из процедур которой ты бы хотел ето реализовать? Может есть другое решение таких задач?

Всегда можно написать себе внешний скрипт с соответствующими обработчиками, и не парить себе голову.
Как раз есть пример из твоего скрипта по автофарму (спасибо за него громное :)), для лута трупов нужна функция, которая запоминает уже полутанные трупы "InCorpseList". Где хранить массив полутанных трупов? Хитрый лут трупов я хочу использовать не только на макросах, но и в игре по хоткею.


Также я могу назвать еще одно преимущество данной фичи:
Возможность управлять своими макросами из клиента. Т.е. скрипты могут стать более интерактивные, например, это было бы замечательно, если мой бот, фармящий мобов, мог получить команду типа ",exec go_next_spawn", и пойти на другое место для спавна.
Или для автоламберов, жмакнуть ",exec gobank", скрипт обработал этот эвент сам, без перезапуска и пауз, и отправил чара класть логи в банк.
Prof
Posts: 9
Joined: 09.01.2015 15:20

Re: Новый Эвент для вызова процедур по команде клиента

Post by Prof »

+ еще пример в хилинге, которое должно хранить время старта прошлого хилинга, чтобы хил бинтами не накладывался друг на друга.
drabadan
Expert
Expert
Posts: 730
Joined: 13.12.2012 17:35
Contact:

Re: Новый Эвент для вызова процедур по команде клиента

Post by drabadan »

Prof wrote:Возможность управлять своими макросами из клиента. Т.е. скрипты могут стать более интерактивные, например, это было бы замечательно, если мой бот, фармящий мобов, мог получить команду типа ",exec go_next_spawn", и пойти на другое место для спавна.
Или для автоламберов, жмакнуть ",exec gobank", скрипт обработал этот эвент сам, без перезапуска и пауз, и отправил чара класть логи в банк.
Для этого согласен, что то тут есть.
А вот глобальные перменные...
Запускай свой автолоад и сохраняй там, что угодно.
Ты можешь забиндить любую функцию из любого скрипта если загрузишь скрипт в дллку.
Я сейчас начинаю писать автолоад для пвп.
То-есть я когда загружаюсь в клиент загружаю его в дллку, где у меня есть бинды под функции и процедуры. Но и запускаю его на главной панели стелса как обычный скрипт. Попробуй почитать, может тебе что-то станет полезным.
autoload_pvp

Code: Select all

Program Autoload_PVP;

uses 
 PvPEngine;
 
type
 TPlayer = record
  Id : Cardinal;
  Name : String;
  X, Y : Word;
 end;

const
 WarHorse = $000CD35A;
 WeaponMain = $42527462;
 WeaponParalyzeBlow = $42F6C5A4;
 WeaponDismount = $40974D39; 
 Fukiya = $42390FA4;

var
 G_Healing : Boolean;
 //G_Cursed  : Boolean;
 G_UnCursing : Boolean;
 G_Curing  : Boolean;
 
 EveryOne : Array of Cardinal{TPlayer};
 
procedure TestFunc;
begin
 AddToSystemJournal(IntToHex(LastTarget, 8));
 AddToSystemJournal(GetToolTip(LastTarget));
end;

procedure ThrowDart;
begin
 UseObject(Fukiya);
 if WaitForTarget(1000) then
  TargetToObject(LastTarget);
end;

procedure HealChivaSelf;
begin
 WaitTargetSelf;
 Cast('Close Wounds');
end;

procedure MountSelf;
begin
 //AddToSystemJournal(IntToStr(ObjAtLayer(HorseLayer)) + '  ' + IntToStr(WarHorse));
 if ObjAtLayer(HorseLayer) <> WarHorse then begin
  if Dist(GetX(Self), GetY(Self), GetX(WarHorse), GetY(WarHorse)) > 1 then 
    NewMoveXY(GetX(WarHorse), GetY(WarHorse), true, 1, true);
  UseObject(WarHorse);
  Wait(300);
 end;
end;


procedure DismountBlow;
var
 cTime : TDateTime;
 MS, cycle : Integer;
 Messages : String;
begin
 Attack(LastTarget); 
 UseObject(Self);
 EquipWeapon(WeaponDismount)
 UseSecondaryAbility;
 Messages := 'parry|deliver';
 cTime := Now; 
 repeat
  Inc(cycle)
  Wait(100)
  MS := InJournalBetweenTimes(Messages, cTime, Now);
 until (MS <> 0) or (cycle > 40) Dead;
 MountSelf;
 EquipWeapon(WeaponMain); 
end;

procedure AutoUncurseSelf;
begin
 G_UnCursing := True;
 repeat
  WaitTargetSelf;
  Cast('Remove Curse');
  Wait(600);
 until Dead or (Str >= 110);
 G_UnCursing := False;
end;

Procedure HandleBuff_Debuff(ID,Attribute_ID : Word; IsEnabled:Boolean);  
  begin
    IsEnabled := True;
    //ClientPrint('Buff Debuff Detected :');
    //AddToSYstemJournal('AttributeID :' + IntToStr(Attribute_ID));
    Case Attribute_ID OF
      1001 : ClientPrint('Attribute : Dismount');
      1002 : ClientPrint('Attribute : Disarm');
      //1003 : PlayerBuff.Buff_ := state;
      //1004 : PlayerBuff.Buff_ := state;
      1005 : ClientPrint('Attribute : Nightsight');
      1006 : ClientPrint('Attribute : Death Strike');
      1007 : ClientPrint('Attribute : Evil Omen');
      //1008 : ClientPrint('Attribute : Unknown');
      1009 : ClientPrint('Attribute : Regeneration');
      1010 : ClientPrint('Attribute : Divine Fury');      
      1011 : ClientPrint('Attribute : Enemy of One');
      1012 : ClientPrint('Attribute : Stealth');
      1013 : ClientPrint('Attribute : Active Meditation');
      1014 : ClientPrint('Attribute : Blood Oath as Caster');
      1015 : ClientPrint('Attribute : Blood Oath as Target');
      1016 : ClientPrint('Attribute : Corpse Skin');
      1017 : ClientPrint('Attribute : Mindrot');
      1018 : ClientPrint('Attribute : Pain Strike');
      1019 : ClientPrint('Attribute : Strangle');
      1020 : ClientPrint('Attribute : Gift of Renewal');
      1021 : ClientPrint('Attribute : Attune Weapon');
      1022 : ClientPrint('Attribute : Thunderstorm');
      1023 : ClientPrint('Attribute : Essence of Wind');
      1024 : ClientPrint('Attribute : Ethereal Voyage');
      1025 : ClientPrint('Attribute : Gift of Life');
      1026 : ClientPrint('Attribute : Arcane Emporement');
      1027 : ClientPrint('Attribute : Mortal Strike');
      1028 : ClientPrint('Attribute : Reactive Armor');
      1029 : ClientPrint('Attribute : Protection');
      1030 : ClientPrint('Attribute : Arch Protection');
      1031 : ClientPrint('Attribute : Magic Reflection');
      1032 : ClientPrint('Attribute : Icognito');
      1033 : ClientPrint('Attribute : Disguised');
      1034 : ClientPrint('Attribute : Animal Form');
      1035 : ClientPrint('Attribute : Polimorph');
      1036 : ClientPrint('Attribute : Invisibility');
      1037 : ClientPrint('Attribute : Paralyze');
      1038 : ClientPrint('Attribute : Poisoned');	   
      1039 : ClientPrint('Attribute : Bleed');
      1040 : ClientPrint('Attribute : Clumsy');
      1041 : ClientPrint('Attribute : Feeblemind');
      1042 : ClientPrint('Attribute : Weaken');
      1043 : ClientPrint('Attribute : Cursed');{if not G_UnCursing then AutoUnCurseSelf;}
      1044 : ClientPrint('Attribute : Mass Curse');
      1045 : ClientPrint('Attribute : Agility');
      1046 : ClientPrint('Attribute : Cunning');
      1047 : ClientPrint('Attribute : Strength');
      1048 : ClientPrint('Attribute : Bless');
      //1049 : PlayerBuff.Buff_ := state;
      //1050 : PlayerBuff.Buff_ := state;
      1085 : ClientPrint('Attribute : Horrific Beast Form');
      1086 : ClientPrint('Attribute : Lich Form');
      1117 : ClientPrint('Attribute : Unknown_Meditation');
      1124 :  ClientPrint('Attribute : Wraith Form');
      //else ClientPrint('Attribute : Unknown -> Report your Action to Crome969');
    end;
 end;

procedure AutoHeal;
var
 i : Integer;
begin
 G_Healing := True; 
 ClientPrint('--------------Healing----------------');
 if GetQuantity(FindType($0E21, Backpack)) > 0 then begin
  UOSay('[Bandageself');
  for i := 6 downto 1 do begin
   ClientPrint('Bandage in: ' + IntToStr(i));
   Wait(1000);
  end;  
 end
 else begin
  ClientPrint('ALERT NO BANDAGES FOUND!!!');
  AddToSystemJournal('ALERT NO BANDAGES FOUND!!!');
 end; 
 G_Healing := False;
end;

procedure CureSelf;
begin
 G_Curing := True;
 ClientPrint('---------Curing Self--------------')
 while Poisoned do begin
  WaitTargetSelf;
  Cast('Cleanse by Fire');
  Wait(600);
 end;
 G_Curing := False;
end;

procedure HandleStuff;
begin
 if Poisoned and (not G_Curing) then
  CureSelf;
 if (Hp < MaxHp) and (not G_Healing) then
  AutoHeal; 
end;



procedure AnimationTest(ID:Cardinal; Action : Word);
begin
 if ID <> 0 then
  ClientPrint(IntToHex(Id, 8) + ' ' + IntToHex(Action, 4));
end;

{$Region 'Searcher'}
function GetFoundItems(var Items: Array Of Cardinal): Integer;
var List: TStringList; i: Integer;
begin
  List := TStringList.Create;
  if GetFindedList(List) = False then Result := 0
  else begin
    SetLength(Items, List.Count);
    for i := 0 to Length(Items)-1 do Items[i] := StrToInt('$'+List.Strings[i]);
    Result := Length(Items);
  end;
  List.Free;
end;

function SearchItems(var FoundItems : Array of Cardinal; 
                     FindTypes : Array of Word; 
                     Container : Cardinal; 
                     fFindDistance : Byte): Integer;
var
 i, k : Integer;
 Items : Array of Cardinal;
begin
 FindDistance := fFindDistance;
 
 for i := Low(FindTypes) to High(FindTypes) do
  begin
   FindType(FindTypes[i], Container);
   if GetFoundItems(Items) > 0 then
    for k := Low(Items) to High(Items) do
     begin
      SetLength(FoundItems, Length(FoundItems)+1);
      FoundItems[High(FoundItems)] := Items[k];
     end;
  end;
 Result := Length(FoundItems);
end;
{$EndRegion 'Searcher'}

procedure EvSoundParser(Sound : Word);
begin
 case Sound of
  $005C : ClientPrint('Fizzle');
  $01E1 : ClientPrint('Curse');
  $0208 : ClientPrint('FlameStrike');
  $0205 : ClientPrint('Poison');
  $01F2 : ClientPrint('Heal');
  $0202 : ClientPrint('Greater Heal');
  $01E0 : ClientPrint('Cure');
 end;
end;

procedure EvSoundCallBack(Sound_ID, X, Y, Z : Word);
var
 i : Integer;
begin
 if Sound_ID <> 0 then begin
  SearchItems(EveryOne, [$0191, $0190], Ground, 20);
  for i := Low(EveryOne) to High(EveryOne) do 
   if (X = GetX(EveryOne[i])) and (Y = GetY(EveryOne[i])) then begin
    ClientPrint(IntToHex(Sound_Id, 4){ + ' ' + GetToolTip(EveryOne[i])});
    AddToSystemJournal(IntToHex(Sound_Id, 4));
    Break;
   end;  
 end; 
end;

procedure GetEveryone;
begin
 ClientPrint(IntToStr(SearchItems(EveryOne, [$0191, $0190], Ground, 20)));
 SetLength(EveryOne, 0);
end;

begin
 //SetEventProc(evCharAnimation, 'AnimationTest');
 SetEventProc(evSound, 'EvSoundCallBack');
 //SetEventProc(evBuff_DebuffSystem, 'HandleBuff_Debuff');
 //SetEventProc(evUnicodeSpeech, 'HandleSpeech'); 
 //SetEventProc(evTimer1, 'HandleStuff'); 
 //SetEventProc(evTimer2, 'GetEveryone');
 while true do 
  begin
   wait(600);
   {if Hp < MaxHp then
    UOSay('[Bandageself')}
  end;
 //Body of Script
end.
User avatar
Vizit0r
Developer
Developer
Posts: 3958
Joined: 24.03.2005 17:05
Contact:

Re: Новый Эвент для вызова процедур по команде клиента

Post by Vizit0r »

я не понимаю ваших сложностей.

Инифайлы уже не в моде? Хранить значения переменных надо только и непременно внутри стелса?

Насчет ивента - да, смысл есть.
Возможно скоро так или иначе смогу добраться до нормального инета - тогда сделаю. Или CFA сделает.
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
CFA
Developer
Developer
Posts: 492
Joined: 20.04.2006 6:03
Contact:

Re: Новый Эвент для вызова процедур по команде клиента

Post by CFA »

Кстати, есть такая недокументированная фича, но не ввиде евента.
В файле Stealth.ini есть параметр UserCmdPrefix, по умолчанию пустая, но можно задать свое значение (только через ini файл) - все отправляемые сообщения начинающиеся с этого префикса на сервер отосланы не будут, но в журнале их будет видно и таким образом можно проверить через функции *Journal
Prof
Posts: 9
Joined: 09.01.2015 15:20

Re: Новый Эвент для вызова процедур по команде клиента

Post by Prof »

CFA wrote:Кстати, есть такая недокументированная фича, но не ввиде евента.
В файле Stealth.ini есть параметр UserCmdPrefix, по умолчанию пустая, но можно задать свое значение (только через ini файл) - все отправляемые сообщения начинающиеся с этого префикса на сервер отосланы не будут, но в журнале их будет видно и таким образом можно проверить через функции *Journal
Оу, это уже гораздо лучше ! Спасибо за такую недокументированную функцию :)
Так получается, уже есть/были предпосылки для команд юзера... Или зачем эта UserCmdPrefix опция ?

А сабжевый эвент все-таки на такие команды появится ? :)
Просто, на сколько сожрет проц парсинг журнала каждые 50 мс?
Post Reply