Кастомные абилки. Структура и пример модификатора атаки.

dumbaq

Новичок
12 Авг 2014
3
0
Вступление

Начать нужно с того, что всё, что я опишу ниже, было получено мною только из иностранных туториалов и путём реверс инженеринга. Я не имею ни малейшего понятия о луа, не смотря на то, что затрагиваю его при создании способностей - это всё познания из области реверс инженеринга, не языка программирования.
С горем пополам я понял структуру абилок в DotA 2 и попытаюсь сейчас вам всё объяснить во всех известных подробностях.

Форма создания способности и путь к файлам.

Стандартные способности в DotA 2 находятся в файле /scripts/npc/npc_abilities.txt
D2WT, при создании мода, предлагает нам не создавать новые абилки, а поверхностно переписывать стандартные через /scripts/npc/npc_abilities_custom.txt. Я выбрал файл npc_abilities.txt. Создал в нужной папке файл с таким именем и провёл начальную разметку.
Почему именно этот путь действий? Мне не нужны были лишние абилки в моём моде. Я просто удалил все стандартные и начал писать свои собственные новые. Если бы я пошёл по другому пути - у меня были бы стандартные абилки + мои. Не критично, но я захотел по-своему.

Начальная разметка npc_abilities.txt

Код:
"DOTAAbilities"
{
<-----здесь----->
}
Всё. Больше там ничего не нужно. Абилки будем записывать внутри фигурных скобочек (надеюсь вы понимаете, что они делают в коде)

Структура способности

Код:
"название_способности_в_кавычках"
{
<-----здесь----->
}
Это основа. Внутри будем писать код способности.



Какую способность я делал, и что писал в коде:

У меня, с самого начала, была задумка сделать комплексную способность.
1. Это была бы автокаст-абилка с манакостом (как фрост арровс у траксы)
2. У неё был бы кулдаун после применения (как у ликвид файр жакиро)
3. Она применялась бы на врагов и была бы модификатором автоатаки (как всё вышесказанное)
4. При применении, она давала бы стан/министан, и не наносила урона цели
5. После попадания по цели, она отскакивала бы в другого врага и наносила урон уже ему, но другой (я не решил какой - пониженный или повышенный)

Я начал писать код.
Первым делом идут обязательные переменные (они находятся слева) и их значения (они находятся справа):
Код:
        "BaseClass"                       "ability_datadriven" // говорит о том, что наша абилка будет сделана нашими ручками в виде кода
        "ID"					"5003" // уникальный айди, постарайтесь угадать такой, который не будет занят другими абилками
        "AbilityTextureName"          "venomancer_venomous_gale" // иконка на худе
        "AbilityUnitTargetTeam"			"DOTA_UNIT_TARGET_TEAM_ENEMY" // команда, по которой можно целить абилкой
        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_UNIT_TARGET | DOTA_ABILITY_BEHAVIOR_AUTOCAST | DOTA_ABILITY_BEHAVIOR_ATTACK" // определяет поведение абилки (здесь - удар по одиночной цели, автокаст, модификатор автоатаки)
        "AbilityCastAnimation"         "ACT_DOTA_ATTACK" // анимация каста
        "AbilityUnitTargetType"         "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC | DOTA_UNIT_TARGET_MECHANICAL" // какие типы юнитов эта абилка будет затрагивать


        "AbilityCastRange"               "625" // радиус каста
        "AbilityCastPoint"               "0.0 0.0 0.0 0.0" // Что-то из того, чего я не знаю

        "AbilityCooldown"                "3.0 2.5 2.0 1.5" // куллдаун на разных уровнях, пишется через пробле
        
        "AbilityManaCost"                "3" // манакост (он у нас един на всех уровнях, поэтому можно не дублировать)

Весь код, отныне и далее, будет содержать переменные и их значения и ничего больше.

Дальше, так-как это модификатор атаки, мы создаём область, где будут отмечаться все последствия применения на разных временных отрезках.

Код:
"Modifiers"
{
<-----здесь----->
}

Вот тут уже и проявляется структура действия абилок.
Сначала мы пишем в какой момент проявляется нужный эффект. Потом сами эффекты и нужные параметры.
Дадим название модификатору

Код:
"modifier_ваше_название"
{
<-----здесь----->
}

Разберёмся с переменными модификатора. Для начала я нашёл похожую способность по действию - это фрост арровс траксы из Ночи Призраков.

Код:
"Passive"        "1" // пара переменная-значение определяет модификатор как пассивный
"Orb" // переменная и, идущие дальше в скобках, её параметры
				{
					"Priority"			"DOTA_ORB_PRIORITY_ABILITY" // приоритет для каста (аттака защитывается как орб-эффект)
					"ProjectileName"	"drow_frost_arrow" // визуальный вид партикля атаки, можно сделать "шоб как у дезолятора стрелы менялись"
					"CastAttack"		"1" //каст с аттакой
				}
Дальше я использовал событие "во каста орба", которое тоже одолжил у траксы. Сначала идёт название события, потом мы открываем скобку, задаём то, что произойдет в этот момент и закрываем скобки.
Код:
				"OnOrbFire" //название события
				{
					"SpendMana" // то, что произойдёт (потратится мана)
					{
						"Mana"	"%AbilityManaCost" // здесь придётся написать её количество (знак % обозначает ссылку к другой переменной (вы же помните, что они слева находятся) которая у нас уже есть в коде выше - AbilityManaCost)
					}
          
					"FireSound" // произойдёт воспроизведение звука
					{
						"EffectName"			"Hero_DrowRanger.FrostArrows" // задаём название звука
						"Target"				"CASTER" // и источник
					}
          
				}

Полдела - сделано. Теперь следующее событие. Теперь мы решаем, что произойдет в момент, когда наша стрела попадёт по врагу. Я использовал всё ту же абилку траксы из Ночи Призраков и смешал её с ультой ВР из той же Ночи Призраков

Код:
"OnOrbImpact" // событие "при попадании по цели"
				{

					
					"ApplyModifier" // применить модификатор
					{
						"Target"			"TARGET" // определяем цель, как цель автоатаки
						"ModifierName"		"modifier_drow_ranger_frost_arrows_slow" //название модификатора (тут у нас замедло траксы осталось с оригинальной абилки. я не стал его убирать)
						"Duration"			"%slow_duration" //длительность действия модификатора (опять тут ссылка на переменную)
					}

					"Stun" // применить стан
					{
						"Target"		"TARGET" // по цели автоатаки
						"Duration"		"%duration" //длительность со ссылкой
						"Height"		"0" // я так понимаю, высота подброса (для таких вещей как стан Лиона и тд.)
						"ShouldStun"	"1" // застанит ли врага этот стан (странный параметра, не особо разобрался)
					}
          "CreateBonusAttack" // Это кусок ульта ВРки. Создаёт вторую стрелу, для реализации моего рикошета
					{
						"Target" // Определяем цель, но не просто значением "TARGET". Если мы так сделаем, то у нас выйдет геминейт аттак вивера. Мы делаем, чтобы цель определялась в радиусе, от первой цели.
              {
								"Center"		"TARGET" // центр круга определения - цель первой атаки
								"Radius"		"%bonus_arrow_radius" //радиус круга определения - ссылка на переменную
                "Teams"			"DOTA_UNIT_TARGET_TEAM_ENEMY" // команда цели
								"Types"			"DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC" // тип цели
								"MaxTargets"	"1" // и максимум целей
							}
						}
				}


Мы закончили с модификаторами. Абилка сделана. Но у нас есть ещё парочка несуществующих переменных, на которые мы сослались. Определим их для игры.

Начинаем перечислять их после списка модификаторов.

Код:
"Modifiers"
{

}
<-----здесь----->

Код:
        "AbilitySpecial" //заголовок для области перечисления переменных
		{
			"01" //нумерация переменных
			{
				"var_type"						"FIELD_FLOAT" //тип переменных 
				"duration"						"5" // пара переменная-значение (тут - duration = 5)
			}
			"02"
			{
				"var_type"						"FIELD_INTEGER"
				"knockback_distance"			"1"
			}
			"03"
			{
				"var_type"						"FIELD_FLOAT"
				"slow_duration"					"0 0 0 0"
			}
			"04"
			{
				"var_type"						"FIELD_INTEGER"
				"frost_arrows_movement_speed"	"0 0 0 0"
			}
      "05"
			{
				"var_type"						"FIELD_INTEGER"
				"bonus_arrow_radius"			"200 250 300 350"
			}
		}


В итоге, полученный код сохраняем, ищем нужного героя и меняем его, допустим "Ability 1" на нашу "название_способности"

В игре всё, теоретически, должно работать.

В итоге

Весь код абилки:

Код:
"sniper_frost_wing"
    {
        // General
        //-------------------------------------------------------------------------------------------------------------
        "BaseClass"                       "ability_datadriven"
        "ID"					"5003"
        "AbilityTextureName"          "venomancer_venomous_gale"
        "AbilityUnitTargetTeam"			"DOTA_UNIT_TARGET_TEAM_ENEMY"
        "AbilityBehavior"                "DOTA_ABILITY_BEHAVIOR_UNIT_TARGET | DOTA_ABILITY_BEHAVIOR_AUTOCAST | DOTA_ABILITY_BEHAVIOR_ATTACK"
        "AbilityCastAnimation"         "ACT_DOTA_ATTACK"
        "AbilityUnitTargetType"         "DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC | DOTA_UNIT_TARGET_MECHANICAL"
 
        // Casting
        //-------------------------------------------------------------------------------------------------------------
        "AbilityCastRange"               "625"
        "AbilityCastPoint"               "0.0 0.0 0.0 0.0"
 
        // Time    
        //-------------------------------------------------------------------------------------------------------------
        "AbilityCooldown"                "3.0 2.5 2.0 1.5"
        
        // Cost
        //-------------------------------------------------------------------------------------------------------------
        "AbilityManaCost"                "3"
 
        
        
 
        "Modifiers"
		{
			"modifier_sniper_frost_wing"
			{
				"Passive"        "1"
				"Orb"
				{
					"Priority"			"DOTA_ORB_PRIORITY_ABILITY"
					"ProjectileName"	"drow_frost_arrow"
					"CastAttack"		"1"
				}

				"OnOrbFire"
				{
					"SpendMana"
					{
						"Mana"	"%AbilityManaCost"
					}
          
					"FireSound"
					{
						"EffectName"			"Hero_DrowRanger.FrostArrows"
						"Target"				"CASTER"
					}
          
				}

				"OnOrbImpact"
				{
					
					"ApplyModifier"
					{
						"Target"			"TARGET"
						"ModifierName"		"modifier_drow_ranger_frost_arrows_slow"
						"Duration"			"%slow_duration"
					}

					"Stun"
					{
						"Target"		"TARGET"
						"Duration"		"%duration"
						"Height"		"0"
						"ShouldStun"	"1"
					}
          "CreateBonusAttack"
					{
						"Target"
              {
								"Center"		"TARGET"
								"Radius"		"%bonus_arrow_radius"
                "Teams"			"DOTA_UNIT_TARGET_TEAM_ENEMY"
								"Types"			"DOTA_UNIT_TARGET_HERO | DOTA_UNIT_TARGET_BASIC"
								"MaxTargets"	"1"
							}
						}
				}
			}
		}
        
        // Special   
        //-------------------------------------------------------------------------------------------------------------
        "AbilitySpecial"
		{
			"01"
			{
				"var_type"						"FIELD_FLOAT"
				"duration"						"5"
			}
			"02"
			{
				"var_type"						"FIELD_INTEGER"
				"knockback_distance"			"1"
			}
			"03"
			{
				"var_type"						"FIELD_FLOAT"
				"slow_duration"					"0 0 0 0"
			}
			"04"
			{
				"var_type"						"FIELD_INTEGER"
				"frost_arrows_movement_speed"	"0 0 0 0"
			}
      "05"
			{
				"var_type"						"FIELD_INTEGER"
				"bonus_arrow_radius"			"200 250 300 350"
			}
		}
    }

Что же я получил на выходе:
1. Автокастовый модификатор автоатаки. :)
2. С манакостом. :)
3. Но без кд. :(
4. Станит врага при попадании, но наносит урон. ::)
5. При попадании создаёт новую автотатаку, которая вылетает из моего героя и попадает в рандомную цель в радиусе. :(

2.5 пункта из пяти. Почему? Потому что я не знаю всех перменных кода, который написаль в Valve.
Вы скажете: так возьми событие "OnOrbImpact" и напиши в коде, чтобы заместо "CreateBonusAttack" выполнялось действие типа "Rikoshet In Other Enemy Without Damage". Я отвечу: не могу, я не знаю какая переменная даёт такой эффект. Бонусную атаку даёт "CreateBonusAttack", стан - "Stun", а нужный мне эффект - не знаю. Где же твой реверс инженеринг? - спросите вы. "Подсмотри как делать рикошет у, например, Луны."
А вот тут и главная загвоздка - там, в коде абилки рикошета Луны, ничего об этом нету. Информация о стандартных абилках DotA 2 хранится где-то глубоко в ядре, и я туда не смог добраться. А в тхт-файлах представлены просто поверхностные сведения. Из них полезной информации не извлечёшь.

И так - со всеми переменными. Единственный источник примеров - другие, более пытливые моддеры и npc_custom_abilities.txt в папке режимы Ночи Прзраков, который содержит изменённые абилки героев с этого режима. Там-то сведения относительно полные, и можно подчерпнуть переменных, чем я и воспользовался.

Поэтому, если вы хотите сделать свою способность - либо учите ЛУА и пишите код с нуля, либо ищите список всех переменных. Иначе у вас вряд ли получится то, что вы хотели сначала.

Заключение

Русское комьюнити D2WT сильно страдает от недостатка информации по скриптингу. В то время, как иноязычные моддеры собираются в довольно крупные сообщества в России D2WT, видимо, мало кого интересует.
Этот туториал содержит ОЧЕНЬ базовые знания о создании абилок в DotA 2, но, на безрыбье и этот, сделанный на коленке, туториал может быть полезным. Именно поэтому я его выложил, не обессудьте.
Никогда не бойтесь спрашивать, я всегда поделюсь крохами знаний. И сами делитесь, потому что у меня ещё куча всего, чему я хотел бы научиться.
 
Последнее редактирование модератором:

Owletass

Пользователь
21 Авг 2014
57
1
Спасибо за гайд. Пойду и попробую что-нибудь замутить.
 

Waltan

Пользователь
23 Авг 2014
19
0
Я выбрал файл npc_abilities.txt. Создал в нужной папке файл с таким именем и провёл начальную разметку.

А что значит "нужная папка"? Я создал npc_abilities.txt в папке с модом, и D2WP вообще перестал запускаться.
И если я вставлял в npc_abilities_custom.txt стандартные способности и менял им манакост \ кулдаун, то все равно ничего не менялось. Как быть?

UPD: Поменял npc_abilities_custom.txt в npc_abilities_override.txt (подсмотрел в Holdout'e) и все стало работать.
 
Последнее редактирование модератором:

doter.ua

Продвинутый
17 Авг 2014
280
5
[quote author=Waltan link=topic=8.msg82#msg82 date=1408788375]
А что значит "нужная папка"? Я создал npc_abilities.txt в папке с модом, и D2WP вообще перестал запускаться.
И если я вставлял в npc_abilities_custom.txt стандартные способности и менял им манакост \ кулдаун, то все равно ничего не менялось. Как быть?

UPD: Поменял npc_abilities_custom.txt в npc_abilities_override.txt (подсмотрел в Holdout'e) и все стало работать.
[/quote]
Оверрайд тут не нужен, походу ты изменял дефолтные А в статье про создание своих по новыми именами, и присвоении их героям: "ability1" "новое_имя"
 
Последнее редактирование модератором:

Waltan

Пользователь
23 Авг 2014
19
0
Оверрайд тут не нужен, походу ты изменял дефолтные А в статье про создание своих по новыми именами, и присвоении их героям: "ability1" "новое_имя"

Нет, я не изменял дефолтные. Дефолтных у меня в папке с дотой вообще нет. Пришлось скачивать отдельно с dev.dota2
 
Последнее редактирование модератором:

doter.ua

Продвинутый
17 Авг 2014
280
5
Нет, я не изменял дефолтные. Дефолтных у меня в папке с дотой вообще нет. Пришлось скачивать отдельно с dev.dota2
Дефолтные вшиты в дотку, в папке с аддоном их не будет. Просто само слово Override означает переопределение. Не буду повторятся по сто раз, если не читал 4-й гайд про скилы почитай:
http://dota2.ru/forum/threads/gajd-po-scripting-chast-4.605020/
 
Последнее редактирование модератором:

Waltan

Пользователь
23 Авг 2014
19
0
[quote author=doter.ua link=topic=8.msg85#msg85 date=1408801883]
Дефолтные вшиты в дотку, в папке с аддоном их не будет. Просто само слово Override означает переопределение. Не буду повторятся по сто раз, если не читал 4-й гайд про скилы почитай:
http://dota2.ru/forum/threads/gajd-po-scripting-chast-4.605020/
[/quote]

Тогда другой вопрос. Как сделать, чтобы с самого начала у героя все способности были доступны?
 

doter.ua

Продвинутый
17 Авг 2014
280
5
Тогда другой вопрос. Как сделать, чтобы с самого начала у героя все способности были доступны?
в переменной hero типа герой.
local myAbility = hero:FindAbilityByName("antimage_blink")
myAbility:SetLevel(1)
и так для каждой
 
Последнее редактирование модератором:

-ExotiC-

Какой-то ноунэйм
Команда форума
11 Авг 2014
498
56
customgames.ru
Nagibator230 написал(а):
Там уже давно норм гайд, который постепенно дописывают.
Ты ответил на сообщение недельной давности. На то время он действительно был "недогайдом".
 
Последнее редактирование:

Instagib

Пользователь
29 Авг 2014
18
0
А как сделать модификатор со счетчиком? Например как у бэтрайдера стики напалм.
 

doter.ua

Продвинутый
17 Авг 2014
280
5
Instagib,
"ItemInitialCharges" "1"
...
"SpendCharge" {}
 
Последнее редактирование модератором:

Instagib

Пользователь
29 Авг 2014
18
0
Что-то не получается. Это же для предметов заряды, или с абилками тоже работает? Пробывал и в абилке писать и в самом модификаторе, не выходит.
 

doter.ua

Продвинутый
17 Авг 2014
280
5
Что-то не получается. Это же для предметов заряды, или с абилками тоже работает? Пробывал и в абилке писать и в самом модификаторе, не выходит.
Для custom items
 
Последнее редактирование модератором:

Lw_Player

Новичок
5 Авг 2015
5
0
Гайд прочитал все круто, но как добавить описание этому касту. Просто все абилки получаются без описания и названия
 

M@G

Пользователь
1 Авг 2015
63
0
Гайд прочитал все круто, но как добавить описание этому касту. Просто все абилки получаются без описания и названия
Найди файл addon_english.txt в паке resource и там можешь менять.
 
Последнее редактирование модератором:
Реклама: