WarCraft 3 Reforged: Встраивание триггеров в mpq.

» Раздел: Триггеры и объекты
» Автор оригинала: Ev3nt
Думаю, многие хотели бы использовать нестандартные триггеры на всех картах, однако это считалось невозможным. На самом деле, это решили еще в годы мода Nirvana, но никто не обратил внимание, по крайней мере, я не находил информации. Меня много раз просили написать статью, но мне было лень, но, как видите, руки всё же дошли до дела.
Первое, что нам нужно, это создать триггер либо в GUI, либо в Jass. Для примера я написал триггер по перехвату контроля над юнитом. Если ваш триггер изначально написан на Jass, можно пропустить следующий шаг.

Далее наш триггер нужно перевести в Jass, для этого нажмем на пункт "Правка" и в всплывшем меню выберем "Конвертировать в текст".

Отлично, теперь мы обладаем кучей кода, который нам нужно будет пристроить к WC3, для этого открываем War3Patch.mpq и достаем из него Blizzard.j (Scripts/Blizzard.j). Там мы ищем функцию InitBlizzard, как показано на скриншоте.
Внимание, у WC3 - TFT и ROC разные Blizzard.j, будьте внимательны!
» Мой код
function Trig_Take_Control_Func001A takes nothing returns nothing
    call SetUnitOwner( GetEnumUnit(), GetTriggerPlayer(), true )
endfunction

function Trig_Take_Control_Actions takes nothing returns nothing
    call ForGroupBJ( GetUnitsSelectedAll(GetTriggerPlayer()), function Trig_Take_Control_Func001A )
endfunction

//===========================================================================
function InitTrig_Take_Control takes nothing returns nothing
    set gg_trg_Take_Control = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(0), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(1), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(2), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(3), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(4), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(5), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(6), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(7), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(8), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(9), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(10), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(11), "-takecontrol", true )
    call TriggerAddAction( gg_trg_Take_Control, function Trig_Take_Control_Actions )
endfunction

Чтобы всё работало, код, к которому будут обращаться, должен располагаться выше вызова. Прошу заметить, что я также немного изменил его, а именно заменил оператор set на local trigger, показав, что эта переменная типа триггер и является локальной. Также, для простоты чтения, я дописал комментарии и вынес все функции вызова в отдельную функцию InitCustomTrigs. Не знаю почему, но когда я указывал название InitCustomTriggers, то возникала ошибка. Как я это определил, узнаем чуть ниже.
» Мой код
//===========================================================================
// Command: -takecontrol

function Trig_Take_Control_Func001A takes nothing returns nothing
    call SetUnitOwner( GetEnumUnit(), GetTriggerPlayer(), true )
endfunction

function Trig_Take_Control_Actions takes nothing returns nothing
    call ForGroupBJ( GetUnitsSelectedAll(GetTriggerPlayer()), function Trig_Take_Control_Func001A )
endfunction

//===========================================================================
function InitTrig_Take_Control takes nothing returns nothing
    local trigger gg_trg_Take_Control = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(0), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(1), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(2), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(3), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(4), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(5), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(6), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(7), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(8), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(9), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(10), "-takecontrol", true )
    call TriggerRegisterPlayerChatEvent( gg_trg_Take_Control, Player(11), "-takecontrol", true )
    call TriggerAddAction( gg_trg_Take_Control, function Trig_Take_Control_Actions )
endfunction

//===========================================================================
// Custom triggers initializing

function InitCustomTrigs takes nothing returns nothing
	call InitTrig_Take_Control()
endfunction

//===========================================================================
function InitBlizzard takes nothing returns nothing
    // Set up the Neutral Victim player slot, to torture the abandoned units
    // of defeated players.  Since some triggers expect this player slot to
    // exist, this is performed for all maps.
    call ConfigureNeutralVictim()

    call InitBlizzardGlobals()
    call InitQueuedTriggers()
    call InitRescuableBehaviorBJ()
    call InitDNCSounds()
    call InitMapRects()
    call InitSummonableCaps()
    call InitNeutralBuildings()
    call DetectGameStarted()
	call InitCustomTrigs()
	
endfunction

Так, теперь нам пора опробовать наше творение, для этого каким-либо способом подгружаем получившийся Blizzard.j к WC3. Я это буду делать через mix. Также создаем папку Scripts и кидаем файл туда.

Для проверки кода на валидность, заходим в сражение, и если меню настройки лобби у вас не пропало, то всё работает. Так себе метод, но главное, что работает.

И так, вот и пришло время проверки, я всегда хотел поиграть за Тралла в кампании орды от WC3 - TFT, ну и вот, что получилось)
На всякий случай прикреплю mix к статье.

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

dmgr #1 - 2 месяца назад 0
Красавчик! Определенно плюс! Странно что такие полезности не замечают сразу!
ScorpioT1000 #2 - 2 месяца назад (отредактировано ) 1   
Лол)) это было известно чуть ли не с рождения xgm
Bergi_Bear #3 - 2 месяца назад 1   
Эта игра слишком древняя, новое поколение повторно делает открытия, и не вижу в этом ничего плохого
Ev3nt #4 - 2 месяца назад 0
ScorpioT1000, возможно, однако в свое время искал статьи, но так и не нашел\ Был где-то 2015

Ах да, касательно отправленной ссылки, там речь-то о common.j идет, где прописаны константы и нативки, а не про встраивание триггеров :DDD
DioD #5 - 1 месяц назад 0
единственное что нужно дополнить, в мультиплеере это вызывает мгновенный десинк.
Ev3nt #6 - 1 месяц назад 0
DioD, ну почему, если это будет встроено в карту, или mix будет у всех клиентов + сервера, то всё будет работать.
Lotus101 #7 - 3 недели назад 0
Ev3nt:
DioD, ну почему, если это будет встроено в карту, или mix будет у всех клиентов + сервера, то всё будет работать.
Камера для игрока у которого микс тоже дессинхрон будет?
Ev3nt #8 - 3 недели назад (отредактировано ) 0
Lotus101, ну, так как камера по клиентской части, то нет.
Я не проверял, но через mix с хаком всё работает.