WarCraft 3: Переход на Jass

Начинающий
Статус
Оффлайн
Регистрация
30 Янв 2014
Сообщения
57
Реакции[?]
6
Поинты[?]
0
Переход на Jass

[HR][/HR]


[HR][/HR]

Автор: pLaY:) (goldplay99)

  1. Вступление.
  2. Первая часть: От глобальных до локальных.
  3. Вторая часть: Хэш и таймер.
  4. Третья часть : GetLocalPlayer().

[HR][/HR]
Вступление

[HR][/HR]
На вопрос: Почему вы не пишете на Jass? – отвечают, что это сильно тяжело и вообще не понятно, что там. Эта статья предназначена, что бы люди научились писать на Jass.
Я не буду показывать, как лучше делать. Просто покажу, как писать на Jass, а оптимизация, качественный текст и т.п. изучат потом. Статья рассчитана на людей, которые уже изучили GUI (триггеры) и знают, что такое глобальные переменные.

Тоже самое, что и глобальные переменные, только используются в пределах одной функции.
Названия триггеров, глобальных или локальных переменных и функция – могут быть произвольными.
Строки которые начинаются на local пишутся в самом начале функции (кроме cJass).

Создаёте глобальную переменную, нужного типа. В уже конвертированный текст добавляете любую английскую букву – вам выбит окно ошибки. Прокручиваете до самого верха, вы увидите Global Variables, а чуть ниже globals. По центру – название ваших переменных, а слева тип переменной.
Или экспортируете код и точно также ищите.
[HR][/HR]
Первая часть: От глобальных до локальных.

[HR][/HR]

Хотите создать способность, что бы после применения цель обжигало? Ну вот вы раскинули мозгами и сделали такой триггер:



Но вас не устраивает, что использовать способность можно раз в 5 секунд.
Что делать?
Правка>Конвертировать в текст.
Что это за функции?


PHP:
function Trig_FIRE_Conditions takes nothing returns boolean
Это условие.

PHP:
function Trig_GUI_FIRE_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A000' ) ) then
        return false
    endif
    return true
endfunction
//Спокойно можете всё стирать. Оставить только:
function Trig_LOCAL_FIRE_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction

function Trig_LOCAL_FIRE_Actions takes nothing returns nothing
Это действие.

PHP:
function InitTrig_LOCAL_FIRE takes nothing returns nothing
И это событие.
Нам понадобится только функция действия. Не тяжело догадаться, что какая строка означает.
Заменяем начало первых трёх строк:

PHP:
set udg_fire_cast на local unit cast
set udg_fire_target на local unit target
call AddSpecialEffectTargetUnitBJ… на local effect eff = AddSpecialEffectTargetUnitBJ…
Что мы сделали? Мы создали три локальных переменных: боевая единица (cast), боевая единица (target) и спецэффект(eff) и присвоили им значения:
cast - применяющий юнит
target - цель - применяемой способности
eff – спецэффект созданный над юнитом target
Дальше нам надо просто заменять:
udg_fire_cast на cast
udg_fire_target на target
udg_fire_effect на eff
Вот и всё. Теперь способность можно применять сколько хочешь раз.

[HR][/HR]
Вторая часть: Хэш и таймер.

[HR][/HR]
Если вы сделаете работу как указано в первой части, то вам скажут что лучше использовать таймеры. А как? Ведь локальные только в пределах одной функции пашут, но тут к нам на помощь прейдёт Хэш-таблица.
Сначала создадим новую функцию в которой будет наше действие. После функции(условия) пишем:
PHP:
function Trig_LOCAL_FIRE_Timer takes nothing returns nothing
endfunction
Trig_LOCAL_FIRE_Timer Название функции. Оно может быть любым, главное что бы не повторялось.
В функции(действия) копируем строку



А потом стираем все, кроме первых 3 и последних 2 строк.

Должно остаться:

PHP:
local unit cast = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local effect eff = AddSpecialEffectTargetUnitBJ( "chest", target, "Abilities\\Spells\\Other\\Doom\\DoomTarget.mdl" )
set cast = null
set target = null
В функции Trig_LOCAL_FIRE_Timer вставляем строку(которую скопировали).
Создаём таймер.Для этого нужно в начале функции(действия) дописать:

PHP:
local timer t = CreateTimer()
Таймер записывается в локальную t

Что бы запустить таймер используем:

call TimerStart (переменная таймера, время, тип таймера, функция)
Время – как часто срабатывает.
Тип таймераfalse или true:
false – однократный
true – многократный
функция – та функция в которой будут нужные действия.
Значит пишем перед set cast = null такую строку:
PHP:
call TimerStart(t,1.0,true,function Trig_LOCAL_FIRE_Timer)
Теперь время использования ХЕШ(
Пожалуйста, авторизуйтесь для просмотра ссылки.
).
Прочли? Продолжим. Создаём глобальную переменную Хэш-таблица с названием Hash. Создаём новый триггер с названием Hash, стираем всё и пишем:

PHP:
function InitTrig_Hash takes nothing returns nothing
set udg_Hash = InitHashtableBJ( )
endfunction
Теперь можно забыть про этот триггер.
Вернёмся к нашим функциям.
В функции (действия) сохраним наши данные.
Перед call TimerStart… пишем

PHP:
call SaveUnitHandle(udg_Hash,GetHandleId(t),1,cast)// Сохраняем применяющего юнита в 1 ячейку.
call SaveUnitHandle(udg_Hash,GetHandleId(t),2,target) )// Сохраняем цель-способности во 2 ячейку.
call SaveEffectHandle(udg_Hash,GetHandleId(t),3,eff) )// Сохраняем созданный спецэффект в 3 ячейку.
и в функции Trig_LOCAL_FIRE_Timer загрузим их:

PHP:
local timer t = GetExpiredTimer()// Использованный таймер
local unit cast = LoadUnitHandle(udg_Hash,GetHandleId(t),1)// Загружаем применяющего юнита из 1 ячейки.
local unit target = LoadUnitHandle(udg_Hash,GetHandleId(t),2) )// Загружаем цель-способности из 2 ячейки.
local effect eff = LoadEffectHandle(udg_Hash,GetHandleId(t),3) )// Загружаем созданный спецэффект из 3 ячейки.
Мы сразу записываем их в переменные. Нечего страшного, что их названия идентичны - это же локальные. Если вы сейчас проверите карту, то урон будет наноситься постоянно. Что бы этого избежать добавим целое число(integer) в функцию(действия):

PHP:
local integer i = 0
и после call SaveEffectHandle…. Сохраним в хэш
call SaveInteger(udg_Hash,GetHandleId(t),4,i)// Сохраняем i в 4 ячейку.
а в функции Trig_LOCAL_FIRE_Timer после local effect eff … загрузим:
local integer i = LoadInteger(udg_Hash,GetHandleId(t),4)//Загружаем i из 4 ячейки.
Теперь создадим условие, которое будет определять, когда надо закончить наносить урон.

PHP:
if i == 5 then Если i равно 5
То
call FlushChildHashtable(udg_Hash,GetHandleId(t))// уничтожаем все ячейки
call DestroyEffect(eff)//уничтожить эффект
call DestroyTimer(t)//уничтожить таймер
set cast = null обнулить переменную
set target = null// обнулить переменную
set eff = null// обнулить переменную
set t = null// обнулить переменную
else//Иначе
call UnitDamageTargetBJ( cast, target, 20.00, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE ) Нанести урон
set i = i + 1// Увеличить значение
call SaveInteger(udg_Hash,GetHandleId(t),4,i) Сохранить в хэш
endif
Вот и всё).
PHP:
function Trig_TIMER_FIRE_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
function Trig_LOCAL_FIRE_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit cast = LoadUnitHandle(udg_Hash,GetHandleId(t),1)
local unit target = LoadUnitHandle(udg_Hash,GetHandleId(t),2)
local effect eff = LoadEffectHandle(udg_Hash,GetHandleId(t),3)
local integer i = LoadInteger(udg_Hash,GetHandleId(t),4)
if i == 5 then
call DestroyEffect(eff)
call DestroyTimer(t)
set cast = null
set target = null
set eff = null
set t = null
else
call UnitDamageTargetBJ( cast, target, 20.00, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE )
set i = i + 1
call SaveInteger(udg_Hash,GetHandleId(t),4,i)
endif
endfunction
function Trig_TIMER_FIRE_Actions takes nothing returns nothing
local timer t = CreateTimer()
local unit cast = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local effect eff = AddSpecialEffectTargetUnitBJ( "chest", target, "Abilities\\Spells\\Other\\Doom\\DoomTarget.mdl" )
local integer i = 0
call SaveUnitHandle(udg_Hash,GetHandleId(t),1,cast)
call SaveUnitHandle(udg_Hash,GetHandleId(t),2,target)
call SaveEffectHandle(udg_Hash,GetHandleId(t),3,eff)
call SaveInteger(udg_Hash,GetHandleId(t),4,i)
call TimerStart(t,1.0,true,function Trig_LOCAL_FIRE_Timer)
set cast = null
set target = null
endfunction
===========================================================================
function InitTrig_TIMER_FIRE takes nothing returns nothing
set gg_trg_TIMER_FIRE = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_TIMER_FIRE, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_TIMER_FIRE, Condition( function Trig_TIMER_FIRE_Conditions ) )
call TriggerAddAction( gg_trg_TIMER_FIRE, function Trig_TIMER_FIRE_Actions )
endfunction
[HR][/HR]
Третья часть: GetLocalPlayer()​

[HR][/HR]
Возможно, вы часто задавались вопросом: почему я вижу этот объект так, а мой другой игрок по-другому? Приведу пример из карты “DOTA”, не потому что она нереальная, а потому что она популярная и каждые знает, про что идёт речь.
1)Герой Invoker > способность Sun Strike.
2)Герой Mortred > способность Blur.
3)Герой Admiral> способность Гейзер и Корабль - точнее, точка его появляния...
Подробней о GetLocalPlayer() можно узнать (тут). Но лучше пример - будем создавать вышеуказанную способность Sun Strike.

Создаём триггер:

Что за “Личный сценарий” и RemoveLocation()?
Личный сценарий - строка из Jass кода.
call RemoveLocation() – уничтожает точку.
Наш триггер конвертируем в текст и аналогично Первой части заменяем переменные.
В локальную eff – сразу не записываем созданный эффект,а делаем это на след строке:
Set eff = AddSpecial….
Второй спецэффект мы сразу удаляем. Мы используем для этого две строки, а можно одну:

PHP:
    call AddSpecialEffectLocBJ(loc, "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" )
    call DestroyEffectBJ( GetLastCreatedEffectBJ() ) на
    call DestroyEffectBJ( AddSpecialEffectLocBJ( loc, "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" ) )
Заменили?
Должно получиться так:

PHP:
function Trig_Jass_Sun_Strike_Actions takes nothing returns nothing
local unit cast = GetSpellAbilityUnit()
local location loc = GetSpellTargetLoc()
local effect eff
set eff = AddSpecialEffectLocBJ( loc, "Abilities\\Spells\\Items\\VampiricPotion\\VampPotionCaster.mdl" )
    call TriggerSleepAction( 2 )
    call DestroyEffectBJ( eff )
    call UnitDamagePointLoc( cast, 0.01, 250.00, loc, 200.00, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DEATH )
    call DestroyEffectBJ( AddSpecialEffectLocBJ( loc, "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" ) )
    call RemoveLocation(loc)
    set cast = null
    set loc = null//Дописать эту строку
endfunction
Сейчас добавим строки, которые для союзников – создадут эффект, а для врагов - нечего. Для этого создадим группу игроков-союзников и запишем туда союзников:

Конвертируем в текст,допишем и изменим:
PHP:
local force for = CreateForce()// Создаём пустую группу игроков и записываем её в for
local string str//Локальная строка
    set bj_forLoopAIndex = 1 // От 1
    set bj_forLoopAIndexEnd = 12 // До 12
    loop //Начало цикла действий, повторяем действия пока exitwhen не будет правдив.
        exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd // Если AIndex> AIndexEnd то exitwhen правдив
        if ( IsUnitAlly(cast, ConvertedPlayer(GetForLoopIndexA())) == true ) then// Если
// То
            call ForceAddPlayerSimple( ConvertedPlayer(GetForLoopIndexA()), for )
else//Иначе, можно стереть        
endif//Конец условия
        set bj_forLoopAIndex = bj_forLoopAIndex + 1//Если exitwhen не правдив, то прибавляет к AIndex единицу
    endloop// Конец границы цикла.
if (IsPlayerInForce(GetLocalPlayer(),for)) then //Если
set str = "Abilities\\Spells\\Items\\VampiricPotion\\VampPotionCaster.mdl"
// То
else//Иначе
set str = " "
endif//Конец условия
set eff = AddSpecialEffectLocBJ( loc, str )
Всё. Но, у нас опять присутствует

PHP:
call TriggerSleepAction( 2 )
А это – не очень хорошо!
Мы уже умеем сохранять и загружать значения из Хеша, но сначала создадим функцию Trig_Jass_Sun_Strike_Boom.

PHP:
local timer t = CreateTimer()//В начале
PHP:
После set eff = …. Пишем:

call SaveUnitHandle(udg_Hash,GetHandleId(t),1,cast)
call SaveLocationHandle(udg_Hash,GetHandleId(t),2,loc)
call SaveEffectHandle(udg_Hash,GetHandleId(t),3,eff)
call TimerStart(t,2.00,false,function Trig_Jass_Sun_Strike_Boom)

Остальное копируем, кроме:

    call DestroyForce(for)// дописываем
    set for = null // дописываем
    set cast = null
    set loc = null

И вставляем в функция Trig_Jass_Sun_Strike_Boom и загружаем наши значения.

local timer t = GetExpiredTimer()
local unit cast = LoadUnitHandle(udg_Hash,GetHandleId(t),1)
local location loc = LoadLocationHandle(udg_Hash,GetHandleId(t),2)
local effect eff = LoadEffectHandle(udg_Hash,GetHandleId(t),3)
    call DestroyEffectBJ( eff )
    call UnitDamagePointLoc( cast, 0.01, 250.00, loc, 200.00, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DEATH )
    call DestroyEffectBJ( AddSpecialEffectLocBJ( loc, "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" ) )
    call FlushChildHashtable(udg_Hash,GetHandleId(t))
    call DestroyTimer(t)
    call RemoveLocation(loc)
    call DestroyForce(for)
    set for = null
    set cast = null
    set t = null
    set loc = null
Вот теперь – точно всё.

function Trig_Jass_Sun_Strike_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction
function Trig_Jass_Sun_Strike_Boom takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit cast = LoadUnitHandle(udg_Hash,GetHandleId(t),1)
local location loc = LoadLocationHandle(udg_Hash,GetHandleId(t),2)
local effect eff = LoadEffectHandle(udg_Hash,GetHandleId(t),3)
call DestroyEffectBJ( eff )
call UnitDamagePointLoc( cast, 0.01, 250.00, loc, 200.00, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_DEATH )
call DestroyEffectBJ( AddSpecialEffectLocBJ( loc, "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" ) )
call FlushChildHashtable(udg_Hash,GetHandleId(t))
call DestroyTimer(t)
call RemoveLocation(loc)
call DestroyForce(for)
set for = null
set cast = null
set t = null
set loc = null
endfunction
function Trig_Jass_Sun_Strike_Actions takes nothing returns nothing
local unit cast = GetSpellAbilityUnit()
local location loc = GetSpellTargetLoc()
local effect eff
local force for = CreateForce()
local string str
local timer t = CreateTimer()
set bj_forLoopAIndex = 1
set bj_forLoopAIndexEnd = 12
loop
exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd
if ( IsUnitAlly(cast, ConvertedPlayer(GetForLoopIndexA())) == true ) then
call ForceAddPlayerSimple( ConvertedPlayer(GetForLoopIndexA()), for )
endif
set bj_forLoopAIndex = bj_forLoopAIndex + 1
endloop
if (IsPlayerInForce(GetLocalPlayer(),for)) then

set str = "Abilities\\Spells\\Items\\VampiricPotion\\VampPotionCaster.mdl"
else
set str = " "
endif
set eff = AddSpecialEffectLocBJ( loc, str )
call SaveUnitHandle(udg_Hash,GetHandleId(t),1,cast)
call SaveLocationHandle(udg_Hash,GetHandleId(t),2,loc)
call SaveEffectHandle(udg_Hash,GetHandleId(t),3,eff)
call TimerStart(t,2.00,false,function Trig_Jass_Sun_Strike_Boom)
set cast = null
set loc = null
endfunction

//===========================================================================
function InitTrig_Jass_Sun_Strike takes nothing returns nothing
set gg_trg_Jass_Sun_Strike = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Jass_Sun_Strike, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Jass_Sun_Strike, Condition( function Trig_Jass_Sun_Strike_Conditions ) )
call TriggerAddAction( gg_trg_Jass_Sun_Strike, function Trig_Jass_Sun_Strike_Actions )
endfunction
Спасибо Doc, ScorpioT1000
Карта пример -
Пожалуйста, авторизуйтесь для просмотра ссылки.



Статья скопирована с сайта:
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Последнее редактирование:
Сверху Снизу