Алгоритмы, Наработки и Способности
Способ реализации:
Jass
Тип:
Наработка
Версия Warcraft:
1.26
Это карта - система приказов, простая, на ней по всюду разбросаны итемы.
Автоподбор - способность, которая поможет заполнить инвентарь героя до отказа. Кликая по ней, ваш юнит сначала ищет ближайший предмет, и только после этого бежит подбирать. Затем пойдет искать следующий, и так до сих пор, пока не добьет сумку. Есть особые условия для работы этой способности:
  1. Есть определенный радиус действия, около которого перебирает все предметы. Можете указать это радиус в триггере.
  2. Если вокруг этого радиуса действия ни одного предмета не обнаруживается, то абилка выключается
  3. Если инвентарь полон, то юнит завершает подбор, абилка деактивируется
  4. Если игрок выдернул юнита во время подбора, то абилка здесь тоже становится неактивной.
Автопродажа - способность, которая продает все имеющие итемы в магазин. Тем более этот скилл сам ищет ближайший магазин. Когда носильщик добежит до магазина, то тут же продаст все итемы в одно мгновение. И вам не нужно перетаскивать итемы из каждого слота, за вас сделает сама система. Условие НЕ работы:
  1. Если инвентарь пуст
  2. Если игрок выдернул юнита во время продажи, то абилка здесь тоже становится неактивной.
Для работы копируете две категории (папки) с триггерами: "Автоподбор предметов" и "Продажа предмета". При переносе глобальных триггеров с одной карты на другую главную роль играет триггер "in" - специально вывел в GUI.
триггер инициализации
короче всякие настройки для теста, инициализицируем хэш-таблицу (очень важно)
проверяем приказы при автоподборе.
Тут всего 4-5 проверок:
Тут работаем с кнопкой "Укрыться за щитом" - она не сбивает приказ, юнит не останавливается.
  1. Если нажата кнопка "включить" - включается автопоиск + автоподбор. Сначала проверяется есть ли у героя хотя бы один пустой слот в инвентаре (если нет, то автоподбор вырубается). ЗАМЕТКА: при поиске ближайшего итема мы помечаем итем, чтобы затем снова его не подбирать. Дело в том, что может быть так, что за одним итемом побегут два-три раба. А так, можно сделать, чтобы условно, договорились, кто что будет делать
  1. Если нажата кнопка "выключить" - автоподбор прерывается
  2. Если цель - объект, короче получил какой-то другой приказ на цель, но целью не является итем, это должно происходить во время включенного подбора. В итоге автоподбор прерывается.
  3. получил приказ щелчком правой кнопки мыши отойти в точку. это должно происходить во время включенного автоподбора. Автоподбор прерывается
function T_order_C takes nothing returns boolean
    local integer id = GetIssuedOrderId()
    local integer x1 = 852055 //приказ defend
    local integer x2 = 851971 //приказ smart
    local integer x3 = 852056 //приказ undefend
    local integer Id = GetHandleId(GetTriggerUnit()) //Id-Handle герой
    local boolean b = LoadBoolean(udg_Hash, Id, 0) //включен ли автоподбор
    local integer Ev = GetHandleId(GetTriggerEventId()) //Id-Handle события (38 - без цели, 39 - точка, 40 - цель)
    local boolean b1 = (id == x1 and Ev == 38) //включить автоподбор
    local boolean b2 = (id != x2 and GetOrderTargetItem() == null and Ev == 40 and b) //получил какой-то другой приказ по цели, но целью не является итем, это должно происходить во время включеннного подбора
    local boolean b3 = (id == x2 and Ev == 39 and b) //получил приказ щелчком правой кнопки мыши отойти в точку. это должно происходить во время включенного автоподбора
    local boolean b4 = (id == x3 and Ev == 38) //выключить автоподбор
    local boolean b5 = ( (id != x1 or id !=x2 or id != x3) and (Ev == 38 or Ev == 39) and b) //если ни один из проверок выше не работает
    //local boolean b6 = ( (not b1) and b2 and b3 and b4 and b5) and (Ev > 37 and Ev < 41) //старая версия b5
    
    return (b1) or (b2) or (b3) or (b4) or (b5) //or (b6)//происходит проверка
endfunction


function Trig_XX2 takes nothing returns nothing
    local real x1 = GetUnitX(udg_unit) //координаты юнита
    local real y1 = GetUnitY(udg_unit)
    local real x2 = GetItemX(GetEnumItem()) //координаты выбранного итема, каждый раз итем сменяется на другой, короче цикл здесь
    local real y2 = GetItemY(GetEnumItem())
    local real dx = x2 - x1 //разность между координатами направление вектора короче
    local real dy = y2 - y1
    // ищем самый ближайщий предмет
    // проверяем расстояние (дистанцию) между точками - юнитом и предметом
    set udg_dist1 = SquareRoot(dx * dx + dy * dy) //подсчитывает расстояние, допустим dx * dx или dy * dy - возводим в степень,  SquareRoot - функция корня
    if udg_dist1 < udg_DD then //сравнивают, если расстояние между итемом и юнитов меньше, чем должно то подходит
    
        if ( udg_dist1 < udg_dist2 ) then //сравнивают, если расстояние между итемом и юнитов меньше, чем должно то подходит
            set udg_dist2 = udg_dist1
            set udg_item[0] = GetEnumItem()
        endif
        set udg_h = udg_h + 1
    endif
    set udg_MAXX = udg_MAXX + 1
    
endfunction

function FG takes nothing returns boolean
local integer i = GetPlayerId(GetOwningPlayer(udg_unit)) //номер игрока 
local integer id = GetHandleId(GetFilterItem()) //Id-Handle итема
local boolean b = LoadBoolean(udg_Hash, id, i) //подзагружает проверку, короче метку (помечен ли юнит, если в хэше ничего не сохранено. то выдаст false)
return IsItemVisible(GetFilterItem()) and (not b) //выбирает итемы если видимы и не помечены
endfunction

function NHR takes nothing returns nothing
local timer t = GetExpiredTimer() //запущенный таймер
local integer id = GetHandleId(t) //Id-Handle таймера
local unit u = LoadUnitHandle(udg_Hash, id, 0) //подзагружаем нашего героя

call PauseTimer(t) //паузим таймер
call DestroyTimer(t) //уничтожаем
call FlushChildHashtable( udg_Hash, id ) //очищаем хэш-таблицу от хэндла таймера
     
call BJDebugMsgXX( "|cFFff1e00На карте нет итемов, поэтому будет отдан приказ < выключить автоподбор >|r", u )
call DisableTrigger(GetTriggeringTrigger()) //выключаем триггер перед применением приказов. Выключаем специально, чтобы не было зацикливания и вылета
call IssueImmediateOrderById( u, 852056 ) //приказ использовать undefend
call EnableTrigger(GetTriggeringTrigger()) //включать триггер
set t = null
set u = null
endfunction



function TH takes unit u, real mind1, real maxd2 returns nothing
local integer id = GetHandleId(u) //Id-Handle юнита
local timer t = LoadTimerHandle(udg_Hash, id, 1) //подзагружаем таймер
local integer Id = GetHandleId(t) //Id-Handle таймера
local integer ID //Id-Handle итема
local boolexpr f //это фильтр, в него заносится функция которая отсеивает не нужное
local integer n //номер игрока

    //засовываем в глобалки, чтобы в отдельной функции перебрать все итемы
    
    set udg_unit = u //юнит
    set udg_h = 0 //счетчик на кол-во предметов в радиусе maxd2, обнуляем счетчик на ноль
    set udg_MAXX = 0 //счетчик на кол-во предметов по всей карте, обнуляем счетчик на ноль
    set udg_dist1 = mind1 //изначальная дистанция (эта дистанция ничего не значит. так как все равно будет перезаписана)
    set udg_dist2 = maxd2 //макс. дистанция, это важный пункт, показывает с какой радиус действия подбора итемов
    set udg_DD = maxd2 //в эту переменную записывают реальное число, короче макс. дистанцию
    
    
    // выбираем все предметы которые есть на карте, короче идет перебор между предметами
    set f = Condition(function FG) //фильтр помогает отсеивать не нужные данные, например в EnumItemsInRect подберет те итемы, которые указаны в function FG, то есть итемы, которые видны (есть итемы, которые исчезают вроде рун), но вообще-то условие фильтра потом может увеличится со временем
    
    call EnumItemsInRect( bj_mapInitialPlayableArea, f, function Trig_XX2 ) //перебирает все итемы на карте
    
    call BJDebugMsgXX( "|cFFD852FFкол-во предметов по всей карте:|r " + I2S(udg_MAXX), u )
    
    
    if udg_h > 0 then //если на карте кол-во итемов больше
        call BJDebugMsgXX( "|cFFFFB0C2кол-во предметов в радиусе " + R2S(maxd2) + ":|r " + I2S(udg_h), u )
        call BJDebugMsgXX( "|cFF00C850найден самый ближайщий итем|r " + "|cFFFFDC00"  + GetItemName(udg_item[0])+ " |r", u )
        set ID = GetHandleId(udg_item[0]) //Id-Handle итема
        set n = GetPlayerId(GetOwningPlayer(u))
        call SaveBoolean( udg_Hash, ID, n, true ) //запоминаем то, что этот предмет решился взять юнит
        call SaveUnitHandle( udg_Hash, ID, n+100, u ) //запоминаем, что юнит данного игрока подбирает итем
        call SaveBoolean( udg_Hash, id, 49, true ) //сохраняем проверку, что этот юнит пошел подбирать итем
        call SaveItemHandle(udg_Hash, id, 50, udg_item[0] ) //сохраняем итем
        
        call GroupAddUnit( udg_Group, u)
        call IssueTargetOrderById( u, 851971, udg_item[0] ) //приказ подобрать итем
    elseif udg_h == 0 then
        call BJDebugMsgXX( "|cFFff1e00на карте отсутствуют итемы|r - |cFFD852FFкол-во итемов: " + I2S(udg_h) + " |r", u )
        call SaveBoolean( udg_Hash, id, 0, false ) //пересохраняем то, что автоподбор выключен
        call GroupRemoveUnit( udg_Group, u ) //удаляем юнита из группы !!!это действие бесполезно и нигде не используется, можно удалить!!!
        
        call TimerStart(t, 0.00, false, function NHR) //используется вместо вэйта
    endif  
    
    
    call DestroyBoolExpr(f) //не обязательно удалять, знаю привычка
    set f = null
    set t = null
    
    
endfunction

function GHJK takes nothing returns nothing
local timer t = GetExpiredTimer() //запущенный таймер
local integer id = GetHandleId(t) //Id-Handle таймера
local unit u = LoadUnitHandle(udg_Hash, id, 0) //подзагружаем нашего героя
local real dx = LoadReal(udg_Hash, id, 1) //подзагружаем прошедшие координаты
local real dy = LoadReal(udg_Hash, id, 2)
local integer tu = GetHandleId(u) //Id-Handle героя

local integer i = 0 //для цикла - помогает перебирать слоты
local integer count = 0 //для цикла - помогает подсчитать кол-во итемов
local boolean b = LoadBoolean(udg_Hash, tu, 0) //проверяет включена ли у него способность
local integer ID = GetUnitCurrentOrder(u) //текущий приказ, имеет числовое значение

local boolean b1 = (dx == GetUnitX(u) and dy == GetUnitY(u)) //сверяет прошедшедшее положение с текущим (есть ли смещения). GetUnitX/GetUnitY - определяют текущее положение, dy/dy - прошедшее
local boolean b2 = LoadBoolean(udg_Hash, tu, 49) //метка о том, что юнит подбирает итем

if (b) then //включен ли автоподбор
    if ((b1) and ID == 0) or (not b2) then //если стоит на одном месте, и не выполняет никаких приказов или этот юнит не подбирает предмет
        //то проверяем сколько свободных слотов имеет
        loop
            exitwhen i > 5
            if ( UnitItemInSlot(u, i) == null ) then // если пустая ячейка то прибавляем к переменной единицу
                set count = ( count + 1 )
            endif
            set i = i + 1
        endloop

        call BJDebugMsgXX( "|cFF00b25cЮнит стоит на одном месте, и ничего не делает|r " + "|cFFA000FFсвободных слотов: " + I2S(count) + " |r", u )
        
        // потом проверяем если свободных слотов count больше 0, и автоподбор включен (b), значит ищем итемы
        if count > 0 and b then
            call BJDebugMsgXX( "|cFFFF00FFИдем искать итем (запускаем автопоиск итемов)|r", u )
            call TH(u, 0, 1000000.) //запускаем функцию автопоиска предметов (здесь можно указать минимальный и максимальный радиус поиска предметов. максимальный стоит на 1000000. - почти на всю карту, нужно поубавить радиус)
        
        
        // потом проверяем если свободных слотов нет (count=0), но автоподбор включен (b), значит выключаем автоподбор, удаляем таймер и чистим все
        elseif (count == 0)and(b) then
            call PauseTimer(t) //паузим таймер
            call DestroyTimer(t) //удаляем таймер
            call FlushChildHashtable( udg_Hash, id ) //чистим хэш-таблицу по ид-таймера
            
            call SaveBoolean( udg_Hash, tu, 0, false ) //пересохраняем то, что автоподбор выключен
           
            set ID = GetHandleId(LoadItemHandle(udg_Hash, tu, 50)) //Id-Handle итема
            call SaveBoolean(udg_Hash, ID, GetPlayerId(GetOwningPlayer(u)), false) //убираем метку
            call SaveItemHandle(udg_Hash, tu, 50, null ) //обнуляем из хэша итем
            
            //внизу ссылочные данные (один ссылается на юнита. другой на итем), нужны чтобы удалить метки или ссылать на других
            call SaveUnitHandle( udg_Hash, ID, GetPlayerId(GetOwningPlayer(u))+100, null ) //обнуляем юнита данного игрока, что решился ранее подобрать итем
            call SaveBoolean( udg_Hash, tu, 49, false ) //стираем проверку (метка), что этот юнит когда-то хотел подобрать итем
           
           
           
           //не знаю нужно ли выключать/включать триггер здесь
            call DisableTrigger(GetTriggeringTrigger())//выключаем триггер перед применением приказов. Выключаем специально, чтобы не было зацикливания и вылета 
            call IssueImmediateOrderById( u, 852056 ) //приказ использовать undefend
            call EnableTrigger(GetTriggeringTrigger()) //включаем обратно
            call BJDebugMsgXX( "|cFFFF9E00Cлоты заняты, поэтому отключаем абилку (отдаем приказ < выключить автоподбор > ) и удаляем таймер|r", u )
        endif

    elseif (not b1) then //эта проверка говорит, что координаты смещены, то есть юнит двигается или делает какие-нибудь дела
        call SaveReal(udg_Hash, id, 1, GetUnitX(u)) //пересохраняем
        call SaveReal(udg_Hash, id, 2, GetUnitY(u))
    endif
    
elseif (not b) then //если выключен автоподбор, то таймер нужно удалить
    
    //бывают случаи, когда отключаешь автоподбор, а юнит дальше бежит подбирать итем, то тут здесь, в этом блоке if надо дать приказ "стоп"  
    
    
    call PauseTimer(t) //паузим таймер
    call DestroyTimer(t) //уничтожаем таймер
    call FlushChildHashtable( udg_Hash, id ) //очищаем хэш-таблицу от хэндла таймера (это важно, здесь мы очишаем от хэндла таймера который не нужен)
    call SaveBoolean( udg_Hash, tu, 0, false ) //сохраняем то, что автоподбор выключен
    call BJDebugMsgXX( "|cFFFF9E00Если автоподбор отключен, то удаляем таймер|r", u )
endif


set t = null
set u = null

endfunction





function T_order_A takes nothing returns nothing
    local integer OId = GetIssuedOrderId() //текущий Id-приказ юнита
    local unit U = GetOrderedUnit() //юнит, получивший этот приказ
    local integer id = GetHandleId(U) //Id-Handle юнита (короче номер объекта. у каждого он свой)
    local integer i = 0 //для цикла - помогает перебирать слоты
    local integer count = 0 //для цикла - помогает подсчитать кол-во итемов
    local integer ID //Id-Handle итема
    
    local integer x1 = 852055 //приказ defend
    local integer x2 = 851971 //приказ smart
    local integer x3 = 852056 //приказ undefend
    local boolean b = LoadBoolean(udg_Hash, id, 0) //проверяет включен ли у юнита автоподбор (если там ничего не сохранено, то вернет false)
    local integer Ev = GetHandleId(GetTriggerEventId()) //Id-Handle события (38 - без цели, 39 - точка, 40 - цель)
    local boolean b1 = (OId == x1 and Ev == 38) //включить автоподбор
    local boolean b2 = (OId != x2 and GetOrderTargetItem() == null and Ev == 40 and b) //получил какой-то другой приказ по цели, но целью не является итем, это должно происходить во время включеннного подбора
    local boolean b3 = (OId == x2 and Ev == 39 and b) //получил приказ щелчком правой кнопки мыши отойти в точку. это должно происходить во время включенного автоподбора
    local boolean b4 = (OId == x3 and Ev == 38) //выключить автоподбор
    local boolean b5 = ( (OId != x1 or OId !=x2 or OId != x3) and (Ev == 38 or Ev == 39) and b) //если ни один из приказов не работает
    //local boolean b6 = ( (not b1) and b2 and b3 and b4) and (Ev > 37 and Ev < 41) //старая версия b5
    local item ITM
    
    local timer t = null //таймер
    local integer it //Id-Handle таймера
    local integer n //номер игрока
    
     //автоподбор включен, 852055 - приказ укрыться щитом (defend)
    if ( b1 ) then
        call BJDebugMsgXX( "|cFF00b25cавтоподбор включен|r", U )
        //циклом проверяем слоты
        loop
            exitwhen i > 5
            // если пустая ячейка то прибавляем к переменной count единицу
            if ( UnitItemInSlot(U, i) == null ) then 
                set count = ( count + 1 )
            endif
            set i = i + 1
        endloop
        call BJDebugMsgXX( "|cFFdbf900кол-во свободных слотов:|r " + I2S(count), U )
        
        
        // потом проверяем если свободных слотов count больше 0, и значит делаем действия
        if ( count > 0 ) then
            call BJDebugMsgXX( "|cFFA0C2DFКол-во свободных слотов больше нуля, значит есть места, запускаем автопоиск (Идем искать итем) и таймер по отслеживанию состояния героя (делает ли герой что-нибудь)|r", U )
        
            set t = LoadTimerHandle(udg_Hash, id, 1) //подзагружаем таймер (если ранее таймер не был создан, то вернет null)
            
            
            
            if t == null then //если переменная пустая, значит таймер не запущен у раба, следовательно, запускаем новый
                
                
                //здесь создается таймер, который ежесекундно проверяет раба, стоит ли он или что-то делает
                set t = CreateTimer()
                set it = GetHandleId(t) //Id-Handle таймера
                call SaveUnitHandle(udg_Hash, it, 0, U) //сохраняем героя
                call SaveReal(udg_Hash, it, 1, GetUnitX(U)) //сохраняем текущие координаты
                call SaveReal(udg_Hash, it, 2, GetUnitY(U))
                
                call SaveTimerHandle(udg_Hash, id, 1, t) //сохраняем таймер
                call TimerStart(t, 0.03, true, function GHJK) //запускаем таймер
                
                call BJDebugMsgXX( "|cFFA0C200У этого юнита нет таймера, поэтому создаем и запускаем новый таймер|r", U )
            endif
            
            call SaveBoolean( udg_Hash, id, 0, true ) //сохраняем то, что автоподбор включен (это важная фишка для работы системы, проверяет включен ли автоподбор у героя)
            
            call TH(U, 0, 1000000.) //запускаем функцию автопоиска предметов (здесь можно указать минимальный и максимальный радиус поиска предметов. максимальный стоит на 1000000. - почти на всю карту, нужно поубавить радиус)
                
        elseif count == 0 then //если нет свободных слотов (count = 0), то отключаем автоподбор
            call SaveBoolean( udg_Hash, id, 0, false ) //пересохраняем то, что автоподбор выключен
            
            set ITM = LoadItemHandle(udg_Hash, id, 50) //загружаем итем в локалку (если в хэше ничего не сохранено, то вернет null) 
            set ID = GetHandleId(ITM) //Id-Handle итема
            
            set n = GetPlayerId(GetOwningPlayer(U)) //номер игрока
            call SaveBoolean(udg_Hash, ID, n, false) //убираем метку
            call SaveItemHandle(udg_Hash, id, 50, null ) //обнуляем из хэша итем
            
            //внизу ссылочные данные (один ссылается на юнита. другой на итем), нужны чтобы удалить метки или ссылать на других
            call SaveUnitHandle( udg_Hash, ID, n+100, null ) //обнуляем юнита данного игрока, что решился ранее подобрать итем
            call SaveBoolean( udg_Hash, id, 49, false ) //стираем проверку (метка), что этот юнит когда-то хотел подобрать итем
            
            //call GroupRemoveUnit( udg_Group, U ) //удаляем юнита из группы !!!это действие бесполезно и нигде не используется!!!
            //call FlushChildHashtable( udg_Hash, id ) //это стирает все данные по хэндлу !!!будьте осторожны, из-за этого у меня в другой системе не работало, лучше отказаться от нее!!!
            
            
            call TriggerSleepAction(0.) //вэйт, его нужно !!! попробовать убрать !!!!
            
            call DisableTrigger(GetTriggeringTrigger()) //выключаем триггер перед применением приказов. Выключаем специально, чтобы не было зацикливания и вылета
            call IssueImmediateOrderById( U, 852056 ) //использовать приказ undefend
            call EnableTrigger(GetTriggeringTrigger()) //включаем обратно триггер
            call BJDebugMsgXX( "|cFFff1e00кол-во свободных слотов равно ноль (мест нет, куда положить итемы), автоподбор выключен|r", U )
        endif
    
    
    
    
    //здесь может быть ситуация, когда может дан другой приказ, отличающий от автоподбора и приказа подобрать итем (щелчком правой кнопки мыши по итему - smart)
    //иначе если переменная "Итем-цель приказа" пуста и приказ не равен 851971 (smart), короче отсеиваем отданный приказ взять итем
    //или если приказ щелчком мыши кликнули по земле, то нужно это тоже предусмотреть, щелчок правой кнопки мыши (smart = 851971) мы можем отвести юнита от итема, короче автоподбор должен выключится
    //или если какой-нибудь другой приказ отдан будет
    //три условия выше срабатывают, при условии, что автоподбор (b) включен
    elseif (b2 or b3 or b4 or b5) then //851971 - приказ smart
        call SaveBoolean( udg_Hash, id, 0, false ) //пересохраняем то, что автоподбор выключен
        
        set ITM = LoadItemHandle(udg_Hash, id, 50 ) //подзагрузим итем в глобалку, глобалка нужна в качестве ссылки. Мы короче ссылаемся на udg_item[44] в нижних функциях
        set ID = GetHandleId(ITM) //Id-Handle итема

        //Внизу будет сохранение метки, короче мы помечаем, что этот предмет подобран игроком.
        //У каждого игрока одна метка, то есть у этого игрока только один его юнит может взять, а остальные не могут
        //посоперничать игроки могут конечно за итем, но вряд ли до такого абсурда дойдет
        set n = GetPlayerId(GetOwningPlayer(U))
        call SaveBoolean( udg_Hash, ID, n, false ) // (МЕТКА) пересохраняем то, что этот предмет больше никто не берет из юнитов игрока
        call SaveItemHandle(udg_Hash, id, 50, null ) //обнуляем из хэша итем
        
        
        //внизу ссылочные данные (один ссылается на юнита. другой на итем), нужны чтобы удалить метки или ссылать на других
        call SaveUnitHandle( udg_Hash, ID, n+100, null ) //обнуляем юнита данного игрока, что решился ранее подобрать итем
        call SaveBoolean( udg_Hash, id, 49, false ) //стираем проверку (метка), что этот юнит когда-то хотел подобрать итем
        
        //очистка
        //call GroupRemoveUnit( udg_Group, U ) //удаляем юнита из группы !!!эта группа вообще не нужна, не нашел в ней нужды и нигде не используется, можно удалить!!!
        //call FlushChildHashtable( udg_Hash, id ) //это стирает все данные по хэндлу !!!будьте осторожны, из-за этого у меня в другой системе не работало, лучше отказаться от нее!!!
        if b2 then
            call BJDebugMsgXX( "|cFFff1e00Автоподбор выключен, удаляем метку с итема |r" + "Причина: был отдан другой приказ. В качестве цели является цель, либо целью не является итем (а мб юнит, декорация и др.), либо отдан другой приказ (атаковать итем). Все это произошло во время автоподбора. Id приказ: " + I2S(OId) + ". Название приказа: " + OrderId2StringBJ(OId) + ". Номер событий: " + I2S(Ev),U)
        elseif b3 then
            call BJDebugMsgXX( "|cFFff1e00Автоподбор выключен, удаляем метку с итема |r" + "Причина: был отдан другой приказ. В качестве цели является точка, был отдан приказ щелчком по правой кнопки мыши в точку, короче был отдан приказ отойти во время автоподбора" , U )
        elseif b4 then
            call BJDebugMsgXX( "|cFFff1e00Автоподбор выключен, удаляем метку с итема |r" + "Причина: Была нажата кнопка выключить автоподбор", U )
        elseif b5 then
            call BJDebugMsgXX( "|cFFff1e00Автоподбор выключен, удаляем метку с итема |r" + "Причина: был отдан неизвестный другой приказ во время автоподбора. Id приказ: " + I2S(OId) + ". Название приказа: " + OrderId2StringBJ(OId) + ". Номер событий: " + I2S(Ev),U)
            
        
        endif
            
            
            
        if ( OId != 852056 ) then //проверяем, что данный приказ не равно undefend
            call DisableTrigger(GetTriggeringTrigger()) //выключаем триггер, чтобы не было зацикливания при отдаче приказа
            call IssueImmediateOrderById( U, 852056 ) //приказ использовать щит, короче undefend
            call EnableTrigger(GetTriggeringTrigger()) //включаем обратно
        elseif ( OId == 852056 ) then
            call DisableTrigger(GetTriggeringTrigger()) //выключаем триггер перед применением приказов. Выключаем специально, чтобы не было зацикливания и вылета
            call IssueImmediateOrderById( U, 851972 ) //приказ стоп
            call IssueImmediateOrderById( U, 852056 ) //приказ использовать щит, короче undefend
            call EnableTrigger(GetTriggeringTrigger()) //включаем обратно триггер
        endif

    endif
    set t = null
    set U = null
    set ITM = null
endfunction

//===========================================================================
function InitTrig_order_pick_of_item takes nothing returns nothing
    set gg_trg_order_pick_of_item = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_order_pick_of_item, EVENT_PLAYER_UNIT_ISSUED_ORDER )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_order_pick_of_item, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_order_pick_of_item, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
    call TriggerAddCondition( gg_trg_order_pick_of_item, Condition( function T_order_C ) )
    call TriggerAddAction( gg_trg_order_pick_of_item, function T_order_A )
endfunction
удаления рун
при получении итема, ставим метку на итем
function Trig_item_Conditions takes nothing returns boolean
    local integer ID = GetHandleId( GetManipulatedItem()) ////Id хэндл итема
    local boolean b = LoadBoolean(udg_Hash, ID, GetPlayerId(GetTriggerPlayer())) //проверяем метку
    return( b ) //если помечен, то ...
endfunction

function Trig_item_Actions takes nothing returns nothing
local integer id1 = GetHandleId(GetManipulatedItem()) //Id хэндл итема
local unit u = GetTriggerUnit() //юнит который продал итем
local integer n = GetPlayerId(GetTriggerPlayer()) //номер игрока
local unit U 
local integer i = 0 //для цикла
local integer y = 0 //для подсчета юнитов

loop
    exitwhen i>11
    set U = LoadUnitHandle( udg_Hash, id1, i+100) //подзагружаем юнита из хэша (если в хэше ничего не сохранено, то вернет null, короче пусто будет)
    if U != u and U != null then //юнит не равен герою. который подобрал, и не равен пустоте
        call SaveBoolean(udg_Hash, GetHandleId(U), 49, false) //тут пересохраняем
        set y = y + 1
    endif
    set i = i + 1
endloop
call FlushChildHashtable( udg_Hash, id1 )
call BJDebugMsgXX( "подобран итем " + GetItemName(GetManipulatedItem()), u )
call BJDebugMsgXX( "кол-во юнитов, которые не смогли подобрать " + I2S(y), u )


set u = null
set U = null

endfunction

//===========================================================================
function InitTrig_unit_pickup_item takes nothing returns nothing
    set gg_trg_unit_pickup_item = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_unit_pickup_item, EVENT_PLAYER_UNIT_PICKUP_ITEM )
    call TriggerAddCondition( gg_trg_unit_pickup_item, Condition( function Trig_item_Conditions ) )
    call TriggerAddAction( gg_trg_unit_pickup_item, function Trig_item_Actions )
endfunction
проверяем приказы при автопродаже
Здесь используется другая способность - магическая защита. Преимущество - не сбивает приказ, не останавливается, недостаток - не дает натравить вражеские заклинания. Замените тогда, на магический щит.
  1. Если мы включаем кнопку, первое, что на нужно сделать это проверить наличие хотя бы одного итема. Затем ищем магазин, и помечаем в хэше, что этот раб идет продавать. Здесь метка отличается от метки итема при автоподборе. Дело в том, что юнит сначала дропает итем в магазин, а потом продает (закладывает).
  2. Если кнопка отключена, автопродажа отключена.
  3. Если отдан другой какой-нибудь приказ, то автопродажа отменяется.
function T_ss_C takes nothing returns boolean
    local integer id = GetIssuedOrderId() //Id отданный приказ 
    local integer Id = GetHandleId(GetTriggerUnit()) //Id-Handle героя
    local integer x1 = 852478 //приказ magicdefense
    local integer x2 = 852479 //приказ magicundefense
    local integer x3 = 852001 //приказ dropitem
    local integer Ev = GetHandleId(GetTriggerEventId()) //Id-Handle события (38 - без цели, 39 - точка, 40 - цель)
    local boolean b = LoadBoolean(udg_Hash, Id, 67) //загружаем метку (не бежит ли в данный момент герой продавать итемы)
    local boolean b1 = (id == x1 and Ev == 38) //автопродажа включена
    local boolean b2 = (id == x2 and Ev == 38) //автопродажа выключена
    local boolean b3 = (id != x1 and id != x2 and id != x3 and (Ev > 38 and Ev < 41) and b) //отдан какой-нибудь другой приказ
    
    
    return (b1 or b2 or b3)
endfunction


function Tfilter takes nothing returns boolean
    return (GetUnitAbilityLevel(GetFilterUnit(), 'Apit') > 0) //те кто имеет скил лавка продать итем, без этого скила никто не сможет продать предметы
endfunction

function TXS takes nothing returns nothing
    local real x1 = GetUnitX(udg_unit) //юнит
    local real y1 = GetUnitY(udg_unit)
    local real x2 = GetUnitX(GetEnumUnit()) //выбранный магазин
    local real y2 = GetUnitY(GetEnumUnit())
    local real dx = x2 - x1 //направление вектора
    local real dy = y2 - y1
    
    //вычисляем расстояние между героем и выбранным магазином
    set udg_dist1 = SquareRoot(dx * dx + dy * dy) //SquareRoot - корень, dx * dx - возводим в степень 2
    
    
    if ( udg_dist1 < udg_dist2 ) then //если расстояние между героем и данным магазином меньше текущего, то ...
        set udg_dist2 = udg_dist1 //перезапоминаем текущее расстояние (если в будущем попадется меньше, то перезапишется снова)
        set udg_U[55] = GetEnumUnit() //запоминаем магазин
    endif
    set udg_h = udg_h + 1
    
    
endfunction 


function TTT takes player p, unit u5 returns unit 
local boolexpr b 
call GroupClear(udg_ggg) //очищаем группу от юнитов
set udg_Player = p //эта переменная игрок бесполезна. но может пригодится в качестве ссылки, будем ссылаться на игрока, нужна для переноса в функцию фильтр (проверять враг или союзник и так далее). Вместо этого можно использовать классификацию нейтральный например
set b = Condition(function Tfilter)
call GroupEnumUnitsOfPlayer(udg_ggg, p, b)
call DestroyBoolExpr(b) //не обязательно удалять, знаю привычка
call BJDebugMsgXX( "|cFFFFBF00Начинаем поиск магазина|r", u5)

//засовываем в переменные
set udg_unit = u5
set udg_dist1 = 0.00
set udg_dist2 = 1000000000.00
set udg_h = 0 //счетчик на кол-во магазинов, обнуляем на ноль
call ForGroup(udg_ggg, function TXS)
call BJDebugMsgXX( "|cFFFF00FFкол-во магазинов на карте " + I2S(udg_h) + " |r", u5 )

return udg_U[55]
endfunction


function T_ss_A takes nothing returns nothing
local unit u1 = GetTriggerUnit() //герой
local unit u2 //предпологаемый магазин, в данный момент переменная пуста
local integer id = GetHandleId(u1) //Id-Handle героя
local integer i = 0 //для цикла, нужно при пробеге по слотам
local integer c = 0 // для подсчета кол-ва итемов в инвентаре героя
local boolean b = false //это нужно, чтобы выбрать первый итем
local integer n //номер первого слота 
local integer ID = GetIssuedOrderId() //Id отданный приказ
local integer x1 = 852478 //приказ magicdefense
local integer x2 = 852479 //приказ magicundefense
local integer x3 = 852001 //приказ dropitem
local integer Ev = GetHandleId(GetTriggerEventId()) //Id-Handle события (38 - без цели, 39 - точка, 40 - цель)
local boolean b0 = LoadBoolean(udg_Hash, id, 67) //загружаем метку (не бежит ли в данный момент герой продавать итемы)
local boolean b1 = (ID == x1 and Ev == 38) //автопродажа включена
local boolean b2 = (ID == x2 and Ev == 38) //автопродажа выключена
local boolean b3 = (ID != x1 and ID != x2 and ID != x3 and (Ev > 38 and Ev < 41) and b0) //отдан какой-нибудь другой приказ

if b1 then
    call BJDebugMsgXX( "|cFF00C850автопродажа включена|r", u1 )
    //пробегаем циклом по слотам героя
        loop
            exitwhen i > 5 //условия выхода из цикла (от 0 до 5, нумерация другая не от 1-6, а от 0-5)
            if ( UnitItemInSlot(u1, i) != null ) then  //проверяет не пустой ли слот
                set c = ( c + 1 ) //если не пустой складываем
                if b == false then //если нам попался первый слот
                    set n = i //запоминаем номер первого слота
                    set b = true //запоминаем. что первый слот мы получили
                endif 
            endif
            set i = i + 1
        endloop
    call BJDebugMsgXX( "|cFF4FC6D1Проверка: в начале в инвентаре героя предметов всего |r"+ I2S(c), u1 )
    if c > 0 then
        call BJDebugMsgXX( "|cFF4FDF00Номер слота первого выбранного итема: " + I2S(n+1) + " |r", u1 )
        call BJDebugMsgXX( "|cFF00FFFFслоты еще не пустые, поэтому сохраняем юнита и ...|r" , u1 )
        call BJDebugMsgXX( "|cFFFFB0C2Ищем ближайший магазин|r", u1)
        set u2 = TTT(GetTriggerPlayer(), u1) //ищем магазин
        call BJDebugMsgXX( "|cFFFFBF00Найден ближайший магазин, имя ему " + GetUnitName(u2) + " |r", u1)
        call SaveUnitHandle(udg_Hash,id, 4, u2) //магазин
        call UnitDropItemTarget( u1, UnitItemInSlot(u1, n), u2 ) //Приказываем дропнуть/продать/заложить в лавку
        call SaveBoolean(udg_Hash, id, 67, true) //сохраняем то, что юнит получил приказ продать итем, пока он бежит к магазину, он имеет эту метку. Как только получит другую метку, то произойдет отмена автопродажи
    elseif c == 0 then
        call BJDebugMsgXX( "|cFFff1e00Автопродажа отключена, потому что у героя нет больше итемов.|r Проверка использована после включения кнопки < включить автопродажу >. Будет отдан приказ использовать кнопку < выключить автопродажу >. ", u1 )
        call SaveUnitHandle(udg_Hash, id, 4, null) //обнуляем данные
        call SaveBoolean(udg_Hash, id, 67, false) //обнуляем данные
        
        call DisableTrigger(GetTriggeringTrigger()) //выключаем триггер перед применением приказов. Выключаем специально, чтобы не было зацикливания и вылета
        call IssueImmediateOrderById( u1, 851972 ) //приказ стоп
        call TriggerSleepAction(0.) //очень важная пауза, помогает сменить иконку выключенную кнопки на включенную
        call IssueImmediateOrderById( u1, 852479 ) //приказ magicundefense
        call EnableTrigger(GetTriggeringTrigger())
    endif

elseif (b2 or b3) then
    call SaveUnitHandle(udg_Hash, id, 66, null) //обнуляем данные
    call SaveBoolean(udg_Hash, id, 67, false) //обнуляем данные
    call DisableTrigger(GetTriggeringTrigger()) //выключаем триггер перед применением приказов. Выключаем специально, чтобы не было зацикливания и вылета
    call IssueImmediateOrderById( u1, 851972 ) //приказ стоп
    call IssueImmediateOrderById( u1, 852479 ) //приказ magicundefense
    call EnableTrigger(GetTriggeringTrigger()) //включаем триггер
    if b2 then
        call BJDebugMsgXX( "|cFFff1e00Автопродажа отключена.|r " + "Причина: была нажата кнопка < выключить автопродажа >", u1 )
    elseif b3 then
        call BJDebugMsgXX( "|cFFff1e00Автопродажа отключена.|r " + "Причина: был отдан другой приказ во время автопродажи. Id приказ: " + I2S(ID) + ". Название приказа: " + OrderId2StringBJ(ID) + ". Номер событий: " + I2S(Ev), u1 )
    endif
endif
    
set u1 = null
set u2 = null
endfunction

//===========================================================================
function InitTrig_order_drop_of_item takes nothing returns nothing
    set gg_trg_order_drop_of_item = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_order_drop_of_item, EVENT_PLAYER_UNIT_ISSUED_ORDER )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_order_drop_of_item, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_order_drop_of_item, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
    call TriggerAddCondition( gg_trg_order_drop_of_item, Condition( function T_ss_C ) )
    call TriggerAddAction( gg_trg_order_drop_of_item, function T_ss_A )
endfunction
при дропе итема снимаем метку (короче хэш чистим и все)
function T_sell_item_C takes nothing returns boolean
    local integer id = GetHandleId(GetTriggerUnit())
    local boolean b = LoadBoolean(udg_Hash, id, 67)
    return(b)
endfunction

function T_sell_item_A takes nothing returns nothing
local unit u1 = GetTriggerUnit() //продавец (герой)
local integer id = GetHandleId(u1) //Id-Handle героя
local unit u2 = LoadUnitHandle(udg_Hash, id, 4) //покупатель (магазин)

local integer i = 0
local integer c = 0
local boolean b = false
local integer n
local item it1

call BJDebugMsgXX( "|cFF00C850Проданный итем|cFFFFBB00 " + GetItemName(GetSoldItem()) + " |r", u1 )
call TriggerSleepAction(0.) //ЭТОТ ВЭЙТ ОЧЕНЬ ВАЖНАЯ ШТУКА делает задержку, очень необходима, так как триггер срабатывает и показывает, что итем уже продан. но самом деле данный предмет еще не продан
    
//проверяем инвентарь героя, пробегаемся по слотам (от 1 до 6)
    loop
        exitwhen i > 5
        if ( UnitItemInSlot(u1, i) != null ) then  //если слот не пустой...
            set c = ( c + 1 ) //то прибавляем кол-во итемов
            if b == false then //если это в первый раз
                set n = i //запоминаем номер слота
                set it1 = UnitItemInSlot(u1, i) //запоминаем первый итем
                set b = true //запоминаем уже, что это не первый раз
            endif 
        endif
        set i = i + 1
    endloop
    call BJDebugMsgXX( "|cFF2B81FFкол-во ПРЕДМЕТОВ в инвентаре героя:|r " + I2S(c), u1 )
        
        
    if c > 0 then
        call SaveUnitHandle(udg_Hash, id, 4, u2)
        call SaveBoolean(udg_Hash, id, 67, true)
        call BJDebugMsgXX( "|cFF00FFFFВыставляем на продажу|r", u1 )
        call BJDebugMsgXX( "|cFF4FDF00Номер слота следующего выбранного итема: " + I2S(n+1) + " |r", u1 )
        call BJDebugMsgXX( "|cFFA0FF00Имя героя|cFFFFA900 - " + GetUnitName(u1)+"/|cFFA000FFИмя лавки|cFFFFA900 - " + GetUnitName(u2)+ "/|cFFA0FC61Название выбранной на продажу вещи|cFFFFA900 - " +GetItemName(it1) + " |r", u1)

        call UnitDropItemTarget( u1, it1, u2 )

    elseif c == 0 then
        call BJDebugMsgXX( "|cFFff1e00Автопродажа отключена, потому что у героя нет больше итемов.|r Проверка использована при продаже. Будет отдан приказ использовать кнопку < выключить автопродажу >.", u1 )
        call SaveUnitHandle(udg_Hash, id, 4, null) //обнуляем данные
        call SaveBoolean(udg_Hash, id, 67, false) //обнуляем данные
        //пока вылетов не было я не стал выключать / включать триггер
        call IssueImmediateOrderById( u1, 852479 ) //приказ magicundefense
    endif

set u1 = null
set u2 = null
set it1 = null
endfunction

//===========================================================================
function InitTrig_unit_pawn_item takes nothing returns nothing
    set gg_trg_unit_pawn_item = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_unit_pawn_item, EVENT_PLAYER_UNIT_PAWN_ITEM )
    call TriggerAddCondition( gg_trg_unit_pawn_item, Condition( function T_sell_item_C ) )
    call TriggerAddAction( gg_trg_unit_pawn_item, function T_sell_item_A )
endfunction
`
ОЖИДАНИЕ РЕКЛАМЫ...
Этот комментарий удален
0
27
7 лет назад
Отредактирован MpW
0
Пока не в каких проектах. Просто потянуло создать систему подбора и продажи. Изначально, я посмотрел видео Вадима, где играл в карту под названием Весёлая ферма. Механика карты понравилась, но все было сыровато. Там нужно было без конца кликать, и практически не было возможности что-либо сделать (осмотрется, и др.), если в поле вырастало кучу овощей, нужно было собрать. Сумка у героя не резиновая, и много не положишь, поэтому нужно было потом собранное отнести куда-то. Если нужно было продать или занести куда-то, то выискивать магазин и положить. На это время теряется, так и ещё нужно было поляну обрабатывать, сорняки выдергивать и др. Жалко, что кнопочки не было. Я вспомнил одну замечательную свою наработку в первоначальном виде xgm.guru/forum/showthread.php?t=59707 И предложил автору карты PUver, пообещал доработать. Походу дела автор просил много чего переделать и доработать. Puver был внимателен (где я зачастую не разглядел ошибки), и помогал тестировать. За что спасибо ему. Мы вдвоём создали наработку. Пока карта Весёлая ферма не обновляется =((. Странно, что мало отписавшихся и не отображается в ресурсах. Просто не хочу, что наработка не пропала, МБ пригодится кому-то
Чтобы оставить комментарий, пожалуйста, войдите на сайт.