doter.ua

Пользователь

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

doter.ua

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

Эта тема может быть неактуальна по причине того, что вышел новый движок Source 2.

Спойлер: "Первая часть"

*** Вторая часть ***

  • Создаем юнитов.
  • Создаем лагерь юнитов.
  • Создаем динамический лагерь (название сам придумал)

1) Первым делом пару слов про "Динамический лагерь".  Олдскулы, игравшие в разные мапы третьего Варика  должны помнить о лагерях  бесконечного фарма. В таких лагерях после смерти крипов появляются новые, как правило, более мощные. По-моему даже в Петрах такие есть, там панды фармят ночью (или днем:))

2) Сразу вставлю конечный результат:

3) Начнем с самого простого: создание юнита.

Описание метода

handle CreateUnitByName(string a, Vector b, bool c, handle d, handle e, int f)

Creates a DOTA unit by its dota_npc_units.txt name ( szUnitName, vLocation, bFindClearSpace, hNPCOwner, hUnitOwner, iTeamNumber )

     Требует на вход 6 аргументов, подсмотрев исходник кибермэта,  пришел к выводу, что нам понадобятся только зеленые аргументы, а вместо красных передадим заглушки ( один false, и два nil)

    Наш метод примет вид:

CreateUnitByName(Название_из_dota_npc_units.txt, Vector(x, y, z), false, nil, nil, DOTA_TEAM_NEUTRALS)

Подробнее про аргументы

(рассмотрим только зеленые)

    Первый аргумент это название юнита, из тхт файла http://rghost.ru/57412109

например "
npc_dota_neutral_kobold" в этом файле описываются юниты, вначале каждого описания есть такое название (начинается на npc_dota_)

    
Второй аргумент это координаты "высадки" юнита. задаются вектором:

Vector(число, число, число)

Спойлер: "Как определить нужные координаты?"

Разместите любой объект, например дерево, в редакторе и выделите его

в свойствах объекта будут его координаты (потом объект можно удалить:))

a1d69eb5f096825cc59d42f79c64bbe3.png

Свойство origin - то что нам нужно

    Следующие три аргумента пропускаем...

    
Последний аргумент это константа из доков. https://developer.valvesoftware.com/wiki/Dota_2_Workshop_Tools/Scripting/Constants

На скрине раздел
Teams. Наш юнит будет нейтралом

4) Создание лагеря? просто создаем в цикле несколько юнитов.

5)
Динамический лагерь. необходимо учесть пару моментов:

  • массив для хранения живых крипов. units = {nil, nil, nil}
  • Заготовить массив с разными крипами (пару названий из тхт файла)
  • Создать отдельную функцию создания лагеря (для удобства)
  • Создать массив с id номерами юнитов, нам придется обрабатывать гибель определенных юнитов (именно из нашего лагеря)
  • Создать событие "гибель юнита"  onEntityKilled
  • Спавнить юнитов в разные точки (Vector) крипы могут застрять друг в друге.

6) Сразу отмечу, что в конце будет весь код целиком (а здесь лишь фрагменты + пояснение)

Массив с крипами:

local spawnType= {"npc_dota_neutral_kobold", "npc_dota_neutral_polar_furbolg_champion", "npc_dota_neutral_centaur_khan"} - зверухи, которые в видео.

Отдельная функция + цикл:

function имя()

for  count = 1, 3  do

      units<count] = CreateUnitByName(массив_названий<count], Vector(x + массив_чисел<count], y, z), false, nil, nil, DOTA_TEAM_NEUTRALS )

end

end

Где массив_названий - массив с разными зверухами.

     массив_чисел - числа для суммирования с координатой (чтобы крипы спавнились в разные точки) отличаются немного - крипы будут рядом.

Массив id номеров

Ранее мы создали массив units из трех элементов(3 живых крипа)

такой же массив будет хранить числа - id номера.

метод
юнит:GetEntityIndex()

массив_id[count] =  массив_юнитов[count]:GetEntityIndex()

Чтобы узнать длину массива  в
Lua нужно перед именем масива написать #

переменная = #массив

Осталось только создать событие гибель крипа, и в нем проверять id.

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

Есть
массив из трех юнитов. кто-то на карте сдох - нужно сверить id жмурика с каждым из наших трех крипов (напомню у нас есть массив с id)

for 3 раза do

    
if массив_индексов<count] == keys.entindex_killed then

    
У нас будет счетчик живых крипов (вначале он = 3), если ид совпал тогда уменьшаем его на 1.

end

Проверяем наш счетчик, если он равен 0, значит последний крип сдох и пора заспавнить новых.(вызвать функцию спавна) Еще есть переменная spawnLevel - номер(в массиве) крипов которые будут спавнится. эта переменная увеличивается на 1 перед вызовом Если достигнут макс левел(spawnLevel > 2) то всегда спавним самых кртых крипов (последних)

На самом деле код простой как тапочек:
вот фулл

Спойлер: "КОД"

print( "Dota PvP game mode loaded." )

if DotaPvP == nil then

    DotaPvP = class({})

end

function Activate()

    GameRules.DotaPvP = DotaPvP()

    GameRules.DotaPvP:InitGameMode()

end

function DotaPvP:InitGameMode()

    local GameMode = GameRules:GetGameModeEntity()

    -- Enable the standard Dota PvP game rules

    GameRules:GetGameModeEntity():SetTowerBackdoorProtectionEnabled( true )

    -- Register Think

    GameMode:SetContextThink( "DotaPvP:GameThink", function() return self:GameThink() end, 0.25 )

    --  Spawn creeps

    MAX_SPAWN_COUNT = 3

    spawnCount = 3;

    spawnLevel = 1;

    offset = { 0, 50, -50}

    makeSpawn()

    --listeners

    ListenToGameEvent('entity_killed', Dynamic_Wrap(DotaPvP, 'onEntityKilled'), self)

end

function DotaPvP:GameThink()

    return 0.25

end

function DotaPvP:onEntityKilled(keys)

    for i =  1, #units do

        if spawnIndex ~= nil then

            --print(tostring(spawnIndex) ..  '     '  ..  tostring(keys.entindex_killed))

            if spawnIndex == keys.entindex_killed then

                spawnCount = spawnCount - 1      

                print('##### EQUALS #####')

            end

        end

    end  

    if spawnCount == 0 then  

        if spawnLevel < MAX_SPAWN_COUNT then

        spawnLevel = spawnLevel + 1

        else spawnLevel = MAX_SPAWN_COUNT

        end  

        makeSpawn()

    end

end

function makeSpawn()

    local spawnType= {"npc_dota_neutral_kobold", "npc_dota_neutral_polar_furbolg_champion", "npc_dota_neutral_centaur_khan"}  

    units = {nil, nil, nil}

    spawnIndex = {nil, nil, nil}  

    for count = 1, MAX_SPAWN_COUNT do

        units[count] = CreateUnitByName(spawnType[spawnLevel], Vector(1980 + offset[count] , 1024, 128), false, nil, nil, DOTA_TEAM_NEUTRALS)

        spawnIndex[count] = units[count]:GetEntityIndex()

        print('---------NEW SPAWN CREATED-------------------')

    end

    spawnCount = MAX_SPAWN_COUNT

end

UPDATE: можно использовать функцию [COLOR=#ffff4d]RandomVector[/COLOR](максимальное значение) вместо того велосипеда с массивом.  т.е. спавнить крипа в Vector(x, y, z) + RandomVector(100)

Gefudos

Пользователь

Регистрация: 03.12.2013

Сообщения: 1167

Рейтинг: 314

Gefudos

Регистрация: 03.12.2013

Сообщения: 1167

Рейтинг: 314

img
Спасибо.

Nagibator230

Пользователь

Регистрация: 22.07.2013

Сообщения: 892

Рейтинг: 309

Nagibator230

Регистрация: 22.07.2013

Сообщения: 892

Рейтинг: 309

doter.ua сказал(а):
Спойлер: "Первая часть"

*** Вторая часть ***

  • Создаем юнитов.
  • Создаем лагерь юнитов.
  • Создаем динамический лагерь (название сам придумал)

1) Первым делом пару слов про "Динамический лагерь".  Олдскулы, игравшие в разные мапы третьего Варика  должны помнить о лагерях  бесконечного фарма. В таких лагерях после смерти крипов появляются новые, как правило, более мощные. По-моему даже в Петрах такие есть, там панды фармят ночью (или днем:))

2) Сразу вставлю конечный результат:

3) Начнем с самого простого: создание юнита.

Описание метода

handle CreateUnitByName(string a, Vector b, bool c, handle d, handle e, int f)

Creates a DOTA unit by its dota_npc_units.txt name ( szUnitName, vLocation, bFindClearSpace, hNPCOwner, hUnitOwner, iTeamNumber )

     Требует на вход 6 аргументов, подсмотрев исходник кибермэта,  пришел к выводу, что нам понадобятся только зеленые аргументы, а вместо красных передадим заглушки ( один false, и два nil)

    Наш метод примет вид:

CreateUnitByName(Название_из_dota_npc_units.txt, Vector(x, y, z), false, nil, nil, DOTA_TEAM_NEUTRALS)

Подробнее про аргументы

(рассмотрим только зеленые)

    Первый аргумент это название юнита, из тхт файла http://rghost.ru/57412109

например "
npc_dota_neutral_kobold" в этом файле описываются юниты, вначале каждого описания есть такое название (начинается на npc_dota_)

    
Второй аргумент это координаты "высадки" юнита. задаются вектором:

Vector(число, число, число)

Спойлер: "Как определить нужные координаты?"

Разместите любой объект, например дерево, в редакторе и выделите его

в свойствах объекта будут его координаты (потом объект можно удалить:))

a1d69eb5f096825cc59d42f79c64bbe3.png

Свойство origin - то что нам нужно

    Следующие три аргумента пропускаем...

    
Последний аргумент это константа из доков. https://developer.valvesoftware.com/wiki/Dota_2_Workshop_Tools/Scripting/Constants

На скрине раздел
Teams. Наш юнит будет нейтралом

4) Создание лагеря? просто создаем в цикле несколько юнитов.

5)
Динамический лагерь. необходимо учесть пару моментов:

  • массив для хранения живых крипов. units = {nil, nil, nil}
  • Заготовить массив с разными крипами (пару названий из тхт файла)
  • Создать отдельную функцию создания лагеря (для удобства)
  • Создать массив с id номерами юнитов, нам придется обрабатывать гибель определенных юнитов (именно из нашего лагеря)
  • Создать событие "гибель юнита"  onEntityKilled
  • Спавнить юнитов в разные точки (Vector) крипы могут застрять друг в друге.

6) Сразу отмечу, что в конце будет весь код целиком (а здесь лишь фрагменты + пояснение)

Массив с крипами:

local spawnType= {"npc_dota_neutral_kobold", "npc_dota_neutral_polar_furbolg_champion", "npc_dota_neutral_centaur_khan"} - зверухи, которые в видео.

Отдельная функция + цикл:

function имя()

for  count = 1, 3  do

      units<count] = CreateUnitByName(массив_названий<count], Vector(x + массив_чисел<count], y, z), false, nil, nil, DOTA_TEAM_NEUTRALS )

end

end

Где массив_названий - массив с разными зверухами.

     массив_чисел - числа для суммирования с координатой (чтобы крипы спавнились в разные точки) отличаются немного - крипы будут рядом.

Массив id номеров

Ранее мы создали массив units из трех элементов(3 живых крипа)

такой же массив будет хранить числа - id номера.

метод
юнит:GetEntityIndex()

массив_id[count] =  массив_юнитов[count]:GetEntityIndex()

Чтобы узнать длину массива  в
Lua нужно перед именем масива написать #

переменная = #массив

Осталось только создать событие гибель крипа, и в нем проверять id.

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

Есть
массив из трех юнитов. кто-то на карте сдох - нужно сверить id жмурика с каждым из наших трех крипов (напомню у нас есть массив с id)

for 3 раза do

    
if массив_индексов<count] == keys.entindex_killed then

    
У нас будет счетчик живых крипов (вначале он = 3), если ид совпал тогда уменьшаем его на 1.

end

Проверяем наш счетчик, если он равен 0, значит последний крип сдох и пора заспавнить новых.(вызвать функцию спавна) Еще есть переменная spawnLevel - номер(в массиве) крипов которые будут спавнится. эта переменная увеличивается на 1 перед вызовом Если достигнут макс левел(spawnLevel > 2) то всегда спавним самых кртых крипов (последних)

На самом деле код простой как тапочек:
вот фулл

Спойлер: "КОД"

print( "Dota PvP game mode loaded." )

if DotaPvP == nil then

    DotaPvP = class({})

end

function Activate()

    GameRules.DotaPvP = DotaPvP()

    GameRules.DotaPvP:InitGameMode()

end

function DotaPvP:InitGameMode()

    local GameMode = GameRules:GetGameModeEntity()

    -- Enable the standard Dota PvP game rules

    GameRules:GetGameModeEntity():SetTowerBackdoorProtectionEnabled( true )

    -- Register Think

    GameMode:SetContextThink( "DotaPvP:GameThink", function() return self:GameThink() end, 0.25 )

    --  Spawn creeps

    MAX_SPAWN_COUNT = 3

    spawnCount = 3;

    spawnLevel = 1;  

    offset = { 0, 50, -50}

    makeSpawn()  

    --listeners

    ListenToGameEvent('entity_killed', Dynamic_Wrap(DotaPvP, 'onEntityKilled'), self)

end

function DotaPvP:GameThink()

    return 0.25

end

function DotaPvP:onEntityKilled(keys)

    for i =  1, #units do

        if spawnIndex ~= nil then

            --print(tostring(spawnIndex) ..  '     '  ..  tostring(keys.entindex_killed))

            if spawnIndex == keys.entindex_killed then

                spawnCount = spawnCount - 1          

                print('##### EQUALS #####')

            end  

        end  

    end      

    if spawnCount == 0 then    

        if spawnLevel < MAX_SPAWN_COUNT then

        spawnLevel = spawnLevel + 1

        else spawnLevel = MAX_SPAWN_COUNT

        end      

        makeSpawn()

    end

end

function makeSpawn()

    local spawnType= {"npc_dota_neutral_kobold", "npc_dota_neutral_polar_furbolg_champion", "npc_dota_neutral_centaur_khan"}      

    units = {nil, nil, nil}

    spawnIndex = {nil, nil, nil}      

  

    for count = 1, MAX_SPAWN_COUNT do  

        units[count] = CreateUnitByName(spawnType[spawnLevel], Vector(1980 + offset[count] , 1024, 128), false, nil, nil, DOTA_TEAM_NEUTRALS)

        spawnIndex[count] = units[count]:GetEntityIndex()

        print('---------NEW SPAWN CREATED-------------------')

    end

    spawnCount = MAX_SPAWN_COUNT

end

Нажмите, чтобы раскрыть...

Хорош

Ambassador601

Пользователь

Регистрация: 13.08.2014

Сообщения: 30

Рейтинг: 1

Ambassador601

Регистрация: 13.08.2014

Сообщения: 30

Рейтинг: 1

Все отлично написано, автору спасибо,

Только после некоторого тестирования спавнов крипов у меня возникает вопрос - кастомные юниты появляются без моделек и т.п. Значком ERROR. Как в данный скрипт ввести юнитов из списка npc_units_custom?

doter.ua

Пользователь

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

doter.ua

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

Ambassador601 сказал(а):
Все отлично написано, автору спасибо,

Только после некоторого тестирования спавнов крипов у меня возникает вопрос - кастомные юниты появляются без моделек и т.п. Значком ERROR. Как в данный скрипт ввести юнитов из списка npc_units_custom?
Нажмите, чтобы раскрыть...

Кастомные в смысле самодельные 3Д модели? с такими я не работал. Не знаю нужно ли кешировать стандартные модели, я не делал.  Список крипов:

https://developer.valvesoftware.com/wiki/Dota_2_Workshop_Tools/Scripting/Built-In_Unit_Names

Лесные нейтралы начинаются с npc_dota_neutral_имя

Как ввести? Нужно передать первым аргументом в CreateUnitByName( "имя крипа" ... другие аргументы)

У меня используется
массив из трех таких имен

local
spawnType= {"npc_dota_neutral_kobold", "npc_dota_neutral_polar_furbolg_champion", "npc_dota_neutral_centaur_khan"}

Я создавал переменную
spawnLevel которая была  равна  1, 2, 3  (и потом все время 3)  

В цикле передавал
массив<spawnLevel]    в итоге использовались:  1-й  2-й  3-й   элементы массива ( названия скрипов)

brax

Пользователь

Регистрация: 23.07.2013

Сообщения: 111

Рейтинг: 130

brax

Регистрация: 23.07.2013

Сообщения: 111

Рейтинг: 130

омг,возьмите нормальный SC2 редактор,а не это кхм..

doter.ua

Пользователь

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

doter.ua

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

brax сказал(а):
омг,возьмите нормальный SC2 редактор,а не это кхм..
Нажмите, чтобы раскрыть...

это альфа

Ambassador601

Пользователь

Регистрация: 13.08.2014

Сообщения: 30

Рейтинг: 1

Ambassador601

Регистрация: 13.08.2014

Сообщения: 30

Рейтинг: 1

имеется в виду не модели кастомные, а крипы с измененными статами, скиллами и т.д. из списка npc_units_custom, я ведь правильно понимаю, что именно в нем скриптить юнитов надо?

Разобрался, просто та моделька, что была в примере у вольво по какой-то причине не прогружалась. Остальные работают и так.

В любом случае спасибо)

Zimennik2

Пользователь

Регистрация: 10.08.2014

Сообщения: 31

Рейтинг: 0

Zimennik2

Регистрация: 10.08.2014

Сообщения: 31

Рейтинг: 0

Мне кажется, что правильней будет сделать префаб и привязать точки спавна к нему. Но вот как это сделать? :3

iSlappy

Пользователь

Регистрация: 15.11.2013

Сообщения: 107

Рейтинг: 13

iSlappy

Регистрация: 15.11.2013

Сообщения: 107

Рейтинг: 13

Почему я раз 20 перечитал эту и первую часть но так и ничего не понял ?

doter.ua

Пользователь

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

doter.ua

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

iSlappy сказал(а):
Почему я раз 20 перечитал эту и первую часть но так и ничего не понял ?
Нажмите, чтобы раскрыть...

Потому, что у тебя iq как у хлебушка.

iSlappy

Пользователь

Регистрация: 15.11.2013

Сообщения: 107

Рейтинг: 13

iSlappy

Регистрация: 15.11.2013

Сообщения: 107

Рейтинг: 13

doter.ua сказал(а):
Потому, что у тебя iq как у хлебушка.
Нажмите, чтобы раскрыть...

просто написано как то все странно.Ни черта не понял

doter.ua

Пользователь

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

doter.ua

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

iSlappy сказал(а):
просто написано как то все странно.Ни черта не понял
Нажмите, чтобы раскрыть...

Если никогда не программировал, не знаешь что такое переменные, функции и тд. то конечно будет странно, а если кодил и знаешь, то пост про хлебушек вполне оправдан.

MooMooKhan

Пользователь

Регистрация: 28.01.2015

Сообщения: 7

Рейтинг: 1

MooMooKhan

Регистрация: 28.01.2015

Сообщения: 7

Рейтинг: 1

doter.ua сказал(а):
UPDATE: можно использовать функцию [COLOR=#ffff4d]RandomVector[/COLOR](максимальное значение) вместо того велосипеда с массивом. т.е. спавнить крипа в Vector(x, y, z) + RandomVector(100)
Нажмите, чтобы раскрыть...

Если так делать, то все равно крипы порою спавнятся друг на друге. Можно ли сделать так, чтобы у этого вектора устанавливалось не только максимальное значение, но и минимальное?

doter.ua

Пользователь

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

doter.ua

Регистрация: 04.07.2012

Сообщения: 547

Рейтинг: 214

MooMooKhan сказал(а):
Если так делать, то все равно крипы порою спавнятся друг на друге. Можно ли сделать так, чтобы у этого вектора устанавливалось не только максимальное значение, но и минимальное?
Нажмите, чтобы раскрыть...

https://developer.valvesoftware.com/wiki/Dota_2_Workshop_Tools/Scripting/API/Global.FindClearSpaceForUnit

используй на крипа сразу после спавна

Lw_Player

Пользователь

Регистрация: 15.10.2014

Сообщения: 23

Рейтинг: 0

Lw_Player

Регистрация: 15.10.2014

Сообщения: 23

Рейтинг: 0

Спасибо

Lw_Player

Пользователь

Регистрация: 15.10.2014

Сообщения: 23

Рейтинг: 0

Lw_Player

Регистрация: 15.10.2014

Сообщения: 23

Рейтинг: 0

Как сделать задержку например в 30 секунд для каждого крипа в отдельности.

Т.е мы убиваем одного крипа из 3х и через 30 секунд этот крип появится и в лагере их снова будет 3? И как добавить второй лагерь?

Nagibator230

Пользователь

Регистрация: 22.07.2013

Сообщения: 892

Рейтинг: 309

Nagibator230

Регистрация: 22.07.2013

Сообщения: 892

Рейтинг: 309

Lw_Player сказал(а):
Как сделать задержку например в 30 секунд для каждого крипа в отдельности.

Т.е мы убиваем одного крипа из 3х и через 30 секунд этот крип появится и в лагере их снова будет 3? И как добавить второй лагерь?
Нажмите, чтобы раскрыть...

Надо создать кастомное событие отслеживающее смерть крипа, по его срабатыванию запустить таймер (библиотека от БМД). По окончанию таймера заспавнить крипа.

Есть еше вариант, создать невидимый спел, запускающий скрипт, который вызывает код на LUA, который запускает таймер от БМД. По окончанию спавнить крипа.

Мне больше нравиться, метод номер 2, так как универсален для всех типов крипов + в качестве селектора вы, тоесть кому дали спел тот и воскреснет.

wRadchuk

Пользователь

Регистрация: 31.10.2015

Сообщения: 10

Рейтинг: 0

wRadchuk

Регистрация: 31.10.2015

Сообщения: 10

Рейтинг: 0

А кто знает где можно посмотреть про библиотеки, классы и функции? Просто занялся скриптингом, в прошлом кодил на яве и пыхе. Думаю посмотрев мануал по дота-луа, я смогу что либо написать. Кстати как бы это не звучало странно, меня интересует документация на английском, но не помешает посмотреть и на русском. Так же огромное спасибо Дотер.юа за четыре прекрасных статьи. Пиши ещё, твои статьи актуальны и интересны читателю, ну а я надеюсь что кто либо даст ссылку на доки. Спасибо за внимание. С уважением Владимир.