Здравствуйте. Сегодня мы научимся писать автокастовые заклинания. Сразу отмечу, здесь и далее под "автокастовыми" подразумеваются не просто способности, которые можно применять автоматически (их создание ничем не отличается от обычных), а те, которые применяются при атаке. Типичный пример - "Огненные стрелы" Жрицы Луны.
В целях расширения аудитории повествование будет вестись на чистом 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]
Спасибо за внимание. Удачи вам в ваших начинаниях!
Просмотров: 2518
Добавил: SirNikolasДобавлено: 25 Августа 2013 в 11:33:53
Звучит очень устрашающе))) Но я не понял (так как нуб в триггерах) ты не мог бы пожалуйста скинуть тестовую карту с этими иероглифами, буду очень благодарен)
Финальная версия очень неплохой карты в категории AoS, с обновлениями от 06.10.2008 года. Играть очень интересно полными составами 3х3х3. Сорок четыре героя на ваш выбор. Максимальный уровень героев который они могут достичь на этой карте 25. При игре полными составами, сражаясь в центре карты, от количества сражающихся, у вас может притормаживать компьютер!