Сохранение приказов v2.0

» опубликован
» Способ реализации: cJass
» Тип: Наработка
» Версия Warcraft: 1.26а
Наработка, сохраняющая последний приказ юнита и позволяющая его отдавать.
Чтобы отдать приказ обратитесь к функции GiveSavedOrder(unit u).
call GiveSavedOrder(GetTriggerUnit()) //Пример.
GetTriggerUnit() ссылается на юнита, который активирует событие триггера. Вы можете заменить это на любую переменную типа unit, но не забывайте что глобальные переменные, объявленные в редакторе, имеют приставку udg_
Вы также можете указать, чтобы следующий приказ юнита не сохранялся, для этого вызовите функцию NoSaveOrder(unit u).
call NoSaveOrder(GetTriggerUnit()) //Пример.
Нужно для того, чтобы не сохранять не нужные приказы. Например, при перемещении юнита.
» Установка
  • Скопируйте триггер SavingOrder.
» История обновлений
v1.1
  • Исправлен баг.
v2.0
  • Код полностью написан с нуля.
  • Теперь не использует UnitUserDara.
  • Убран лимит юнитов.
  • Исправлены мелкие баги.
  • Добавлен отладочный мод.
  • Работает через хэш-таблицу, вместо массивов.
  • Имитирует произвольный приказ атаки.
  • Функции и переменные стали приватными.
  • Сохраняет только приказы smart, attack, move, harvest, holdposition, stop.
» Код

library SavingOrder initializer svInit
        
    private constant integer orderNoSave_id = 0 //сохранять ли следующий приказ.
    private constant integer orderID_id = 1 //cохранённый ID приказа.
    private constant integer orderWidget_id = 2 //Цель приказа.
    private constant integer orderX_id = 3 //x координата приказа.
    private constant integer orderY_id = 4 //y координата приказа.
    private constant integer orderPoint_id = 5
    private constant integer orderTarget_id = 6
    private constant integer stop = 851972
    private constant integer attack = 851983
    private constant integer move = 851986
    private constant integer smart = 851971
    private constant integer harvest = 852018
    private constant integer holdposition = 851993
    private trigger svTrigger //триггер сохранения приказов.
    private hashtable HT //хэш-таблица.
    private boolean dbg = false //отладочный мод.
    
    private nothing dbgXY( string s, real x, real y ) { // Создает отладочный текст по координатам.
        texttag tt
        tt = CreateTextTagLocBJ( s, null, 0, 10, 60, 60, 100, 20 )
        SetTextTagPos( tt, x + GetRandomReal( -20, 20 ), y + GetRandomReal( -20, 20 ), 0 )
        SetTextTagPermanent( tt, false )
        SetTextTagLifespan( tt, 1.60 )
        SetTextTagFadepoint( tt, 0.80 )
        SetTextTagVelocityBJ( tt, 80.00, 90.00 )
        tt = null
    }
    
    nothing NoSaveOrder( unit u ) {
        integer id = GetHandleId(u)
        SaveInteger( HT, id, orderNoSave_id, 1 )
        u = null
    }
    
    nothing GiveSavedOrder( unit u ) { // Отдает последний сохранённый приказ или приказ "стоп". Приказ стоп отдается в том случае, если orderID = 0.
        DisableTrigger( svTrigger )
        integer id = GetHandleId( GetTriggerUnit() )
        integer orderID = LoadInteger( HT, id, orderID_id )
        real orderX = LoadReal( HT, id, orderX_id )
        real orderY = LoadReal( HT, id, orderY_id )
        widget orderWidget = LoadWidgetHandle( HT, id, orderWidget_id )
        if orderID == 0 {
            SaveReal( HT, id, orderX_id, 0 )
            SaveReal( HT, id, orderY_id, 0 )
            orderX = 0
            orderY = 0
            SaveInteger( HT, id, orderID_id, stop )
            orderID = stop
            SaveWidgetHandle( HT, id, orderWidget_id, null )
            orderWidget = null
        } 
        if LoadBoolean( HT, id, orderPoint_id) == true {
            IssuePointOrderById( u, orderID, orderX, orderY )
            if dbg { dbgXY( OrderId2StringBJ(orderID) + " X" + I2S(R2I(orderX)) + " Y" + I2S(R2I(orderY)), orderX, orderY ) }
        } elseif LoadBoolean( HT, id, orderTarget_id) == true {
            IssueTargetOrderById( u, orderID, orderWidget )
            if dbg { dbgXY( OrderId2StringBJ(orderID) + " tX" + I2S(R2I(GetWidgetX(orderWidget))) + " tY" + I2S(R2I(GetWidgetY(orderWidget))), GetWidgetX(orderWidget), GetWidgetY(orderWidget) ) }
        } else {
            IssueImmediateOrderById( u, orderID)
            if dbg { dbgXY( OrderId2StringBJ(orderID), GetWidgetX(u), GetWidgetY(u) ) }
        }
        u = null
        EnableTrigger( svTrigger )
    }
    
    private nothing svAttack(){ // Сохраняет приказ, когда юнит атакует произвольно, а прошлый приказ был перейти в точку.
        unit u = GetAttacker()
        integer id = GetHandleId(u)
        integer orderNoSave = LoadInteger( HT, id, orderNoSave_id )
        if orderNoSave == 0 {
            real orderX = LoadReal( HT, id, orderX_id )
            real orderY = LoadReal( HT, id, orderY_id )
            if ( orderX != 0 ) and ( orderY != 0 ) {
                SaveBoolean( HT, id, orderPoint_id, false)
                SaveBoolean( HT, id, orderTarget_id, true)
                SaveInteger( HT, id, orderID_id, attack )
                SaveWidgetHandle( HT, id, orderWidget_id, GetTriggerUnit() )
                SaveReal( HT, id, orderX_id, 0 )
                SaveReal( HT, id, orderY_id, 0 )
                if dbg { dbgXY( "attack++" + " | id=" + I2S(id), GetUnitX(u), GetUnitY(u) ) }
            }
        } else {
            SaveInteger( HT, id, orderNoSave_id, 0 )
        }
        u = null
    }
    
    private nothing svActions(){ // Сохраняет отданный приказ.
        integer id = GetHandleId( GetTriggerUnit() )
        integer orderNoSave = LoadInteger( HT, id, orderNoSave_id )
        if orderNoSave == 0 {
            integer ord = GetIssuedOrderId() 
            if ( ord == stop) or ( ord == attack ) or ( ord == move ) or ( ord == holdposition ) or ( ord == smart ) or ( ord == harvest ) {
                if GetWidgetLife(GetOrderTarget()) <= 0. {
                    SaveBoolean( HT, id, orderTarget_id, false)
                } else {SaveBoolean( HT, id, orderTarget_id, true)}
                if GetOrderPointX() == 0. and GetOrderPointY() == 0. {
                    SaveBoolean( HT, id, orderPoint_id, false)
                } else {SaveBoolean( HT, id, orderPoint_id, true)}
                SaveInteger( HT, id, orderID_id, GetIssuedOrderId() )
                SaveWidgetHandle( HT, id, orderWidget_id, GetOrderTarget() )
                SaveReal( HT, id, orderX_id, GetOrderPointX() )
                SaveReal( HT, id, orderY_id, GetOrderPointY() )
                if dbg { dbgXY(OrderId2StringBJ(GetIssuedOrderId()) + "+ | id=" + I2S(id), GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()) ) }
            }
        } else {
            SaveInteger( HT, id, orderNoSave_id, 0 )
        }
    }
    
    
    private nothing svInit(){ // Инициализация.
        HT = InitHashtable()
        
        // Произвольная атака.
        trigger t2 = CreateTrigger()
        TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_ATTACKED )
        TriggerAddAction( t2, function svAttack )
        t2 = null
        
        // Сохранение приказов.
        svTrigger = CreateTrigger()
        TriggerRegisterAnyUnitEventBJ( svTrigger, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
        TriggerRegisterAnyUnitEventBJ( svTrigger, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
        TriggerRegisterAnyUnitEventBJ( svTrigger, EVENT_PLAYER_UNIT_ISSUED_ORDER )
        TriggerAddAction(svTrigger, function svActions )
        
    }
    
endlibrary


Просмотров: 844

Hate #1 - 6 месяцев назад 0
рекомендую отказаться от UnitUserData т.к. обычно его уже где то используют
KaneThaumaturge #2 - 6 месяцев назад 0
Hate, знаю, если его уже используют, то копировать те триггеры и не нужно. Обычно это использует для присвоение id каждому юниту.
Hate, все будет работать, если у каждого юнита не будет повторяющихся UnitUserData.
Hate #3 - 6 месяцев назад 0
с точки зрения архитектуры, зачем выносить глобалки в новую библиотеку? и зачем делать две разных либы которые содержат по одной функции?
Bergi_Bear #4 - 6 месяцев назад 0
Норм, не давно кстати всё это обсуждали, самый просто реализуемый вариант из возможных
KaneThaumaturge #5 - 6 месяцев назад (отредактировано ) 0
Hate, не знаю, пофиксил и заявил на публикацию.
8gabriel8 #6 - 6 месяцев назад 0
Чего-то не понял. Вот был приказ юниту от игрока идти, например, в другой конец карты, на полпути юнит триггерно использует высасывание жизни из врага. Потом он продолжит следовать в другой конец карты?
Обычно приказы для способностей без цели не сбивают приказ. Если они отданы игроком, а не триггерно.
KaneThaumaturge #7 - 6 месяцев назад 0
8gabriel8, Да, если ты укажешь какие-то специальные условия и они не выполнятся. Нет, если все условия совпадут. В оригинале нельзя было изменить максимальный уровень пожираемого юнита против игроков. Искусственно создал эти условия. Я просто сбиваю приказ способности, если не подходят условия, и не сбиваю, если все хорошо. Можно было использовать "stop", но в таком случае приказ бы сбивался.
Однако это можно использовать и в других случаях. Сохранение приказа часто нужно.
8gabriel8, xgm.guru/p/100/224658 - сделал после этого вопроса.
PT153 #8 - 6 месяцев назад 1
Не нашёл - создал.
Но ведь я кидал неделю назад это.
KaneThaumaturge #9 - 6 месяцев назад 0
PT153, не заметил, из недостатков твоя наработка не ловит приказы способностей.
Steal nerves #10 - 6 месяцев назад 0
А может ли серию приказов с таргетами через шифт запомнить? шифт только мем хаком кажись только наверн
quq_CCCP #11 - 6 месяцев назад 0
Steal nerves, самое стремное что любой приказ через IssueXXXOrder сбивает всю очередь, только стан умеет сдвигать всю очередь и сувать свой приказ. Но это можно абузить.
KaneThaumaturge #12 - 6 месяцев назад 0
Steal nerves, можно было бы такое сделать, но я делаю без мемхака, т.к хочу безболезненно адаптировать карту и под новую версию.
KaneThaumaturge #13 - 5 месяцев назад 0

Обновление v2.0

  • Код полностью написан с нуля.
  • Теперь не использует UnitUserDara.
  • Убран лимит юнитов.
  • Исправлены мелкие баги.
  • Добавлен отладочный мод.
  • Работает через хэш-таблицу, вместо массивов.
  • Имитирует произвольный приказ атаки.
  • Функции и переменные стали приватными.
  • Сохраняет только приказы smart, attack, move, harvest, holdposition, stop.
Если руки дойдут, то и бары обновлю, а то они с багом уже месяц висят.
PT153 #14 - 5 месяцев назад 1
Сохраняет только приказы smart, attack, move, harvest, holdposition, stop.
А ведь недавно ты мою систему ругал, что она приказы способностей не сохраняет)
не заметил, из недостатков твоя наработка не ловит приказы способностей.
В этот список ещё можно добавить приказы attackonce и attackground.
GetOrderPointX() == 0. and GetOrderPointY() == 0.
Ведь не факт, что это означает, что приказ не является приказом в точку.
KaneThaumaturge #15 - 5 месяцев назад 0
Ведь не факт, что это означает, что приказ не является приказом в точку.
Ты имеешь ввиду, что может быть приказ в центр карты?
attackonce и attackground.
Добавлю, но что это?
PT153 #16 - 5 месяцев назад 0
Ты имеешь ввиду, что может быть приказ в центр карты?
(0, 0) не всегда центр карты, но в эту точку может быть отдан приказ.
Добавлю, но что это?
Вроде же очевидно из названия: первый, как атаковать, но только один раз, второй атаковать землю.

Полезная библиотека.
KaneThaumaturge #17 - 5 месяцев назад 0
(0, 0) не всегда центр карты, но в эту точку может быть отдан приказ.
Я проверял, в центр карты попасть невозможно, т.к это real и никак нельзя попасть в нулевую координату, как бы я не пытался.
Спасибо.
Clamp #18 - 5 месяцев назад 0
(0, 0) не всегда центр карты, но в эту точку может быть отдан приказ.
Попробуй отдать, можешь даже отметить её какой-нибудь декорацией
8gabriel8 #19 - 5 месяцев назад 0
Clamp, если только там что-то будет, например, портал.
Просто мышкой в землю точно попасть из области фантастики. Там тысячные доли координат считаются.
А может и сотые, давно не проверял, мог перепутать. Но всё равно это особой роли не играет.
PT153, а как игрок может отдать приказ attackonce?
PT153 #21 - 5 месяцев назад 0
Замечание про (0, 0) имеет силу для отданных функцией приказов.
8gabriel8, никак.
Clamp, я не уверен, но вроде функции по координатам возвращают верные координаты, даже если приказ не является точечным. Это как мгновенные приказы в качестве цели всегда возвращают самого кастера (вроде).