Здравствуйте. Сегодня мы научимся писать автокастовые заклинания. Сразу отмечу, здесь и далее под "автокастовыми" подразумеваются не просто способности, которые можно применять автоматически (их создание ничем не отличается от обычных), а те, которые применяются при атаке. Типичный пример - "Огненные стрелы" Жрицы Луны.
В целях расширения аудитории повествование будет вестись на чистом JASS2 с некоторыми вставками на чистом русском... Или наоборот, если хотите.
Давайте поставим перед собой какую-нибудь задачу, решая которую, мы разберемся в теме. Допустим, мы хотим создать автоприменяемую способность, которая при атаке наносит цели урон в размере 30/45/60/75% от интеллекта мага. Назовем ее... скажем, "Glaives of Wisdom".
В качестве базовой способности можно взять "Черную стрелу" или "Отравленные стрелы". О последней способности знают немногие, ведь ее нет ни у одного стандартного героя. Тем не менее, она обладает широким спектром настроек и очень полезна. Я не буду углубляться в конфигурирование, скажу лишь, что нам понадобится свой buff-эффект.
А теперь самое интересное: пришло время кодинга! Прежде всего, вынесем все константы в отдельную часть кода. Это является признаком хорошего тона и просто полезно: если потребуется, их можно будет легко изменить.[code=jass]//Raw-код способности. constant function Trig_GlaivesOfWisdom_Spell takes nothing returns integer return 'A000' endfunction
//Наносимый урон, в зависимости от уровня способности и интеллекта мага. constant function Trig_GlaivesOfWisdom_Damage takes integer level, integer intelligence returns real return (level + 1) * intelligence * .15//30/45/60/75% endfunction[/code]Давайте на минуту задумаемся. Дополнительный урон нужно наносить при попадании снаряда в цель, то есть при получении целью урона. Но событие "Получает урон", как известно, можно задать только для конкретного юнита, а не для любого на карте. А значит, эти события нужно добавлять динамически, то есть по ходу игры. Таким образом, нам потребуются два объекта-триггера: один для нанесения урона, другой для регистрации первого на события. Пишем функцию-инициализатор:[code=jass]function InitTrig_GlaivesOfWisdom takes nothing returns nothing //Триггер-регистратор. local trigger reg = CreateTrigger() local integer i = 0 //Основной триггер. set gg_trg_GlaivesOfWisdom = CreateTrigger() loop //Регистратор должен срабатывать и при автоатаке, и при касте спелла вручную. call TriggerRegisterPlayerUnitEvent(reg, Player(i), EVENT_PLAYER_UNIT_ATTACKED, null) call TriggerRegisterPlayerUnitEvent(reg, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null) exitwhen i == 15 set i = i + 1 endloop //Добавляем условия и действия в оба триггера. С ними мы разберемся чуть позже. call TriggerAddCondition(reg, Condition(function Trig_GlaivesOfWisdom_RegConditions)) call TriggerAddAction(reg, function Trig_GlaivesOfWisdom_RegActions) call TriggerAddCondition(gg_trg_GlaivesOfWisdom, Condition(function Trig_GlaivesOfWisdom_Conditions)) call TriggerAddAction(gg_trg_GlaivesOfWisdom, function Trig_GlaivesOfWisdom_Actions) set reg = null endfunction[/code]Заметьте, у основного триггера пока нет ни одного отслеживаемого события!
Разберемся сначала с регистратором. Однако сразу же возникает пробема: если триггер сработал по событию _ATTACKED, то кастер - это GetAttacker(), а если по _SPELL_EFFECT - то GetTriggerUnit(). У кого же нам проверять уровень способности? К счастью, Blizzard крайне предусмотрительно создали функцию[code=jass]constant native GetTriggerEventId takes nothing returns eventid[/code], которая возвращает сработавшее событие. С ее помощью мы можем написать условия регистратора:[code=jass]function Trig_GlaivesOfWisdom_RegConditions takes nothing returns boolean //Если юнит был атакован... if GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED then //Проверим уровень способности у атакующего. return GetUnitAbilityLevel(GetAttacker(), Trig_GlaivesOfWisdom_Spell()) > 0 endif //Иначе было применено заклинание. //Проверим, "наше" ли. return GetSpellAbilityId() == Trig_GlaivesOfWisdom_Spell() endfunction[/code]Теперь нам нужен механизм, позволяющий добавить событие для юнита, но только один раз. Простейший способ - создать группу, в которой будут находиться все юниты, на которых триггер уже зарегистрирован. Создайте ее в Редакторе переменных и назовите GoW_Group.[code=jass]function Trig_GlaivesOfWisdom_RegActions takes nothing returns nothing local unit target //Так же, как и в условиях, определяем, что за событие вызвало наш триггер. if GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED then set target = GetTriggerUnit()//Цель - атакованный юнит. else set target = GetSpellTargetUnit()//Цель - юнит-цель способности. endif //Если цели еще нет в нашей группе... if not IsUnitInGroup(target, udg_GoW_Group) then //То добавим ее туда. call GroupAddUnit(udg_GoW_Group, target) //И зарегистрируем триггер на событие получения целью урона. call TriggerRegisterUnitEvent(gg_trg_GlaivesOfWisdom, target, EVENT_UNIT_DAMAGED) endif set target = null endfunction[/code]Теперь наш основной триггер будет вызываться каждый раз, когда в юнита попадет способность "Glaives of Wisdom". Но на самом деле он будет срабатывать куда чаще. Поэтому нам нужно дополнительное условие:[code=jass]function Trig_GlaivesOfWisdom_Conditions takes nothing returns boolean //Если у юнита есть buff-эффект, то это точно то, что надо. return GetUnitAbilityLevel(GetTriggerUnit(), Trig_GlaivesOfWisdom_Buff()) > 0 endfunction[/code]И, наконец, то, ради чего мы все это затеяли - нанесение урона:[code=jass]function Trig_GlaivesOfWisdom_Actions takes nothing returns nothing local unit victim = GetTriggerUnit() local unit caster = GetEventDamageSource()//К магу обращаемся как к источнику урона. //Прежде всего удалим buff с цели. call UnitRemoveAbility(victim, Trig_GlaivesOfWisdom_Buff()) //А потом нанесем сколько надо урона. call UnitDamageTarget(caster, victim, Trig_GlaivesOfWisdom_Damage(GetUnitAbilityLevel(caster, Trig_GlaivesOfWisdom_Spell()), GetHeroInt(caster, true)), true, false, null, DAMAGE_TYPE_UNIVERSAL, null) set victim = null set caster = null endfunction[/code]Заметьте, я использовал "null, DAMAGE_TYPE_UNIVERSAL, null", что эквивалентно "ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS". Все вместе это дает нам чистый урон. Также встречаются "null, DAMAGE_TYPE_NORMAL, null" и "ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, null" - соответственно физический и магический урон. Эти три комбинации используются в подавляющем большинстве случаев.
Также обратите внимание, что мы сначала убираем эффект и только потом наносим урон. Если бы сначала наносился урон, триггер запустился бы еще раз, и урон нанесся бы еще раз, и так пока юнит бы не умер.
Поздравляю, теперь вы умеете создавать автокастовые заклинания! Ниже я привожу полный код, который вы можете использовать как шаблон для своих собственных способностей:
[code=jass]constant function Trig_GlaivesOfWisdom_Spell takes nothing returns integer return 'A000' endfunction
constant function Trig_GlaivesOfWisdom_Buff takes nothing returns integer return 'B000' endfunction
constant function Trig_GlaivesOfWisdom_Damage takes integer level, integer intelligence returns real return (level + 1) * intelligence * .15 endfunction
//=========================================================================== function Trig_GlaivesOfWisdom_RegConditions takes nothing returns boolean if GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED then return GetUnitAbilityLevel(GetAttacker(), Trig_GlaivesOfWisdom_Spell()) > 0 endif return GetSpellAbilityId() == Trig_GlaivesOfWisdom_Spell() endfunction
function Trig_GlaivesOfWisdom_RegActions takes nothing returns nothing local unit target if GetTriggerEventId() == EVENT_PLAYER_UNIT_ATTACKED then set target = GetTriggerUnit() else set target = GetSpellTargetUnit() endif if not IsUnitInGroup(target, udg_GoW_Group) then call GroupAddUnit(udg_GoW_Group, target) call TriggerRegisterUnitEvent(gg_trg_GlaivesOfWisdom, target, EVENT_UNIT_DAMAGED) endif set target = null endfunction
function Trig_GlaivesOfWisdom_Actions takes nothing returns nothing local unit victim = GetTriggerUnit() local unit caster = GetEventDamageSource() call UnitRemoveAbility(victim, Trig_GlaivesOfWisdom_Buff()) call UnitDamageTarget(caster, victim, Trig_GlaivesOfWisdom_Damage(GetUnitAbilityLevel(caster, Trig_GlaivesOfWisdom_Spell()), GetHeroInt(caster, true)), true, false, null, DAMAGE_TYPE_UNIVERSAL, null) set victim = null set caster = null endfunction
//=========================================================================== function InitTrig_GlaivesOfWisdom takes nothing returns nothing local trigger reg = CreateTrigger() local integer i = 0 set gg_trg_GlaivesOfWisdom = CreateTrigger() loop call TriggerRegisterPlayerUnitEvent(reg, Player(i), EVENT_PLAYER_UNIT_ATTACKED, null) call TriggerRegisterPlayerUnitEvent(reg, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null) exitwhen i == 15 set i = i + 1 endloop call TriggerAddCondition(reg, Condition(function Trig_GlaivesOfWisdom_RegConditions)) call TriggerAddAction(reg, function Trig_GlaivesOfWisdom_RegActions) call TriggerAddCondition(gg_trg_GlaivesOfWisdom, Condition(function Trig_GlaivesOfWisdom_Conditions)) call TriggerAddAction(gg_trg_GlaivesOfWisdom, function Trig_GlaivesOfWisdom_Actions) set reg = null endfunction[/code]
Спасибо за внимание. Удачи вам в ваших начинаниях!
Просмотров: 2467
Добавил: SirNikolas
Добавлено: 25 Августа 2013 в 11:33:53
Звучит очень устрашающе))) Но я не понял (так как нуб в триггерах) ты не мог бы пожалуйста скинуть тестовую карту с этими иероглифами, буду очень благодарен)