Добавлен , опубликован

Осваиваем World Editor

Содержание:

Переход на Jass

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

Вступление

На вопрос: Почему вы не пишете на Jass? – отвечают, что это сильно тяжело и вообще не понятно, что там. Эта статья предназначена, что бы люди научились писать на Jass.
Я не буду показывать, как лучше делать. Просто покажу, как писать на Jass, а оптимизация, качественный текст и т.п. изучат потом. Статья рассчитана на людей, которые уже изучили GUI (триггеры) и знают, что такое глобальные переменные.
что такое локальные переменные?
Тоже самое, что и глобальные переменные, только используются в пределах одной функции.
Названия триггеров, глобальных или локальных переменных и функция – могут быть произвольными.
Строки которые начинаются на local пишутся в самом начале функции (кроме cJass).
А как узнать тип локальное переменной?
Создаёте глобальную переменную, нужного типа. В уже конвертированный текст добавляете любую английскую букву – вам выбит окно ошибки. Прокручиваете до самого верха, вы увидите Global Variables, а чуть ниже globals. По центру – название ваших переменных, а слева тип переменной.
Или экспортируете код и точно также ищите.

Первая часть: От глобальных до локальных.

Хотите создать способность, что бы после применения цель обжигало? Ну вот вы раскинули мозгами и сделали такой триггер:
Но вас не устраивает, что использовать способность можно раз в 5 секунд.
Что делать?
Правка>Конвертировать в текст.
Что это за функции?
function Trig_FIRE_Conditions takes nothing returns boolean
Это условие.
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
Это действие.
function InitTrig_LOCAL_FIRE takes nothing returns nothing
И это событие.
Нам понадобится только функция действия. Не тяжело догадаться, что какая строка означает.
Заменяем начало первых трёх строк:
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
Вот и всё. Теперь способность можно применять сколько хочешь раз.

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

Если вы сделаете работу как указано в первой части, то вам скажут что лучше использовать таймеры. А как? Ведь локальные только в пределах одной функции пашут, но тут к нам на помощь прейдёт Хэш-таблица.
Сначала создадим новую функцию в которой будет наше действие. После функции(условия) пишем:
function Trig_LOCAL_FIRE_Timer takes nothing returns nothing
endfunction
Trig_LOCAL_FIRE_Timer Название функции. Оно может быть любым, главное что бы не повторялось.
В функции(действия) копируем строку
А потом стираем все, кроме первых 3 и последних 2 строк.
Должно остаться:
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 вставляем строку(которую скопировали).
Создаём таймер.Для этого нужно в начале функции(действия) дописать:
local timer t = CreateTimer()
Таймер записывается в локальную t
Что бы запустить таймер используем:
call TimerStart(переменная таймера, время, тип таймера, функция)
время – как часто срабатывает.
Тип таймераfalse или true:
false – однократный
true – многократный
функция – та функция в которой будут нужные действия.
Значит пишем перед set cast = null такую строку:
call TimerStart(t,1.0,true,function Trig_LOCAL_FIRE_Timer)
Теперь время использования ХЕШ(прочтите).
Прочли? Продолжим. Создаём глобальную переменную Хэш-таблица с названием Hash. Создаём новый триггер с названием Hash, стираем всё и пишем:
function InitTrig_Hash takes nothing returns nothing
set udg_Hash = InitHashtableBJ( )
endfunction
Теперь можно забыть про этот триггер.
Вернёмся к нашим функциям.
В функции (действия) сохраним наши данные.
Перед call TimerStart… пишем
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 загрузим их:
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) в функцию(действия):
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 ячейки.
Теперь создадим условие, которое будет определять, когда надо закончить наносить урон.
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
Вот и всё).
Весь код:
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

Третья часть: ​Get​Local​Player()

Возможно, вы часто задавались вопросом: почему я вижу этот объект так, а мой другой игрок по-другому? Приведу пример из карты “DOTA”, не потому что она нереальная, а потому что она популярная и каждые знает, про что идёт речь.
1)Герой Invoker > способность Sun Strike.
2)Герой Mortred > способность Blur.
3)Герой Admiral> способность Гейзер и Корабль - точнее, точка его появляния...
Подробней о GetLocalPlayer() можно узнать (тут). Но лучше пример - будем создавать вышеуказанную способность Sun Strike.
Создаём триггер:
Что за “Личный сценарий” и RemoveLocation()?
Личный сценарий - строка из Jass кода.
call RemoveLocation() – уничтожает точку.
Наш триггер конвертируем в текст и аналогично Первой части заменяем переменные.
В локальную eff – сразу не записываем созданный эффект,а делаем это на след строке:
Set eff = AddSpecial….
Второй спецэффект мы сразу удаляем. Мы используем для этого две строки, а можно одну:
    call AddSpecialEffectLocBJ(loc, "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" )
    call DestroyEffectBJ( GetLastCreatedEffectBJ() ) на
    call DestroyEffectBJ( AddSpecialEffectLocBJ( loc, "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl" ) )
Заменили?
Должно получиться так:
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
Сейчас добавим строки, которые для союзников – создадут эффект, а для врагов - нечего. Для этого создадим группу игроков-союзников и запишем туда союзников:
Конвертируем в текст,допишем и изменим:
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 )
Всё. Но, у нас опять присутствует
call TriggerSleepAction( 2 )
А это – не очень хорошо!
Мы уже умеем сохранять и загружать значения из Хеша, но сначала создадим функцию Trig_Jass_Sun_Strike_Boom.
local timer t = CreateTimer()//В начале 
После 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
Карта пример - привязана )
Советую - тут
Дополнение - тут
Всё остальное - тут

`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
22
цитирую батьку:
NCrashed:
Нужно добавить в разделе про getLocalPlayer() больше объяснений почему именно так делаем. Конкретно кратко почему call TriggerSleepAction( 2 ) это "не очень хорошо". Непонятно зачем создавать функцию Trig_Jass_Sun_Strike_Boom, хоть бы пару слов для описания что она должна делать. В коде (особенно для новичков) надо поправить отступы,
до тех пор пока не будет исправлено согласно рекомендациям не будет публикации
3
Всем доброго времени суток.
У меня вопрос:
Вот о тригире “GUI FIRE” а точнее я понял, что надо создать переменную
1… Название: fire_cast тип переменной: "боевая единица" без массива и размера
2…Название: fire_target тип переменной: я уже не понял кокой именно тип без массива надо создать?
P.S: Я, конечно, извиняюсь, если такого рода вопрос уже был, но все, же прошу не откажите в вопросе, если конечно не это конечно не затруднит?
15
как обнулить переменную типа Способность, если сделать так
set Spell=null
компилятор ругается на не совпадение типов. Работаю с ГУИ. Глобалка объявлена заранее.
28
Ethernet, способность это инт
значит Spell=0
и вобще её не надо обнулять
15
nvc123:
Ethernet, способность это инт
значит Spell=0
и вобще её не надо обнулять
Когда нужно чтобы переменная не имела значение, ее нужно обнулять:)
28
Ethernet, обнулять инт?
не ну ты герой
что тут ещё скажешь
15
nvc123:
Ethernet, обнулять инт?
не ну ты герой
что тут ещё скажешь
Ты же меня не понял.
28
Ethernet, что тут можно не понять?
инт всегда имеет значение
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.