Урок [lua] Убираем все косметические предметы с героя.

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Иногда может понадобится убрать с героя все косметические предметы(например что бы надеть другие, или что бы не прекешировать их, экономия ресурсов же!).
Собственно весь процесс можно разбить на несколько логичных частей:

  • [li]Выборка всех моделей с героя с классом "dota_item_wearable" и последующая запись в массив на удаление[/li]
    [li]Собственно, само удаление предметов.[/li]
Чутка отойду от темы и разберу несколько стандартных функций
Код:
void UTIL_Remove(handle) -- удаляет какую либо вещь(а точнее объект, будь то модель(model), частица(particle), или же произвольный юнит (unit))
Дальнейшие функции рассматривают все параметры героя, будь то надетые на нем предметы или же его способности.
Код:
handle FirstMoveChild() -- возвращает первый указатель на часть содержащуюся в другом обьекте(в нашем примере она будет возвращать класс, который мы и будем проверять на совпадения его названия с "dota_item_wearable")
Код:
handle NextMovePeer() --то же что и предыдущая, только возвращает не первый указатель, а следующий(по порядку)
Код:
string GetClassname() - возвращает название класса по указателю на объект(смотри дальше по примеру)
Код:
#TABLE - выдаст длинну TABLE

Собственно сама функция:
Код:
function RemoveWearables(hero)
  print('#RemoveWearables')
  local wearables = {} -- объявление локального массива на удаление
  local cur = hero:FirstMoveChild() -- получаем первый указатель над подобъект объекта hero ()

  while cur ~= nil do --пока наш текущий указатель не равен nil(пустота/пустой указатель)
    cur = cur:NextMovePeer() -- выбираем следующий указатель на подобъект нашего обьекта
    if cur ~= nil and cur:GetClassname() ~= "" and cur:GetClassname() == "dota_item_wearable" then -- проверяем, елси текущий указатель не пуст, название класса не пустое, и если этот класс есть класс "dota_item_wearable", то есть надеваемые косметические предметы
      table.insert(wearables, cur) -- добавляем в таблицу на удаление текущий предмет(сверху проверяли класс текущего объекта)
    end
  end
 
  for i = 1, #wearables do -- собственно цикл для удаления всего занесенного в массив на удаление
    UTIL_Remove(wearables[i]) -- удаляем объект
  end
end
Собственно используя данную функцию можно очистить нужного героя от всех косметических предметов.
Когда это может понадобится? Например когда вы заменяете модель одного героя, на другую.
Например я заменил модель бруды на модель антимага без удаления косметических предметов, и вышло ЭТО:
LZnHHmXrlbg.jpg
PS. hero - объект героя, не его имя
PSS. Автор данной функции некий Noya, я только разжевал ее по частям.
 
Последнее редактирование модератором:
  • Нравится
Реакции: dovernento

wetalq

Пользователь
19 Авг 2015
30
0
Этот скрипт вставлять в addon_game_mode.lua, а в качестве аргумента функции писать npc_dota_hero_omniknight если хочу снять вещи с Омника ?
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Этот скрипт вставлять в addon_game_mode.lua, а в качестве аргумента функции писать npc_dota_hero_omniknight если хочу снять вещи с Омника ?
Вставлять туда куда полезет, не обязательно в addon_game_mode.
И нет, передавать не имя героя, а объект героя, который уже в игре существует.
 
Последнее редактирование модератором:

wetalq

Пользователь
19 Авг 2015
30
0
Вставлять туда куда полезет, не обязательно в addon_game_mode.
И нет, передавать не имя героя, а объект героя, который уже в игре существует.

можешь показать пример как его активировать ?
я так понимаю во время выбора героя, на герое будут надеты все косметические предметы ?
 
Последнее редактирование модератором:

CryDeS

Друзья CG
14 Июл 2015
1,210
11
можешь показать пример как его активировать ?
я так понимаю во время выбора героя, на герое будут надеты все косметические предметы ?
Правильно понимаешь друг.
В InitGameMode слушателя добавь на пик героя
Код:
ListenToGameEvent("dota_player_pick_hero", Dynamic_Wrap(GameMode, "OnHeroPicked"), self)
А в сам обработчик слушателя:
Код:
function GameMode:OnHeroPicked (event)
  	local hero = EntIndexToHScript(event.heroindex)
	if hero then 
       RemoveWearables(hero)
  	end

	print("Hero picked, hero:" .. hero:GetUnitName())
	PrecacheUnitByNameAsync(hero:GetUnitName(), function() end) -- это у меня в гейммоде требуется штука, у себя можешь убрать
end
PS. GameMode имя твоего мода из Activate()
 
Последнее редактирование модератором:

wetalq

Пользователь
19 Авг 2015
30
0
[quote author=CryDeS link=topic=214.msg1383#msg1383 date=1440034390]
Правильно понимаешь друг.
В InitGameMode слушателя добавь на пик героя
Код:
ListenToGameEvent("dota_player_pick_hero", Dynamic_Wrap(GameMode, "OnHeroPicked"), self)
А в сам обработчик слушателя:
Код:
function GameMode:OnHeroPicked (event)
  	local hero = EntIndexToHScript(event.heroindex)
	if hero then 
       RemoveWearables(hero)
  	end

	print("Hero picked, hero:" .. hero:GetUnitName())
	PrecacheUnitByNameAsync(hero:GetUnitName(), function() end) -- это у меня в гейммоде требуется штука, у себя можешь убрать
end
PS. GameMode имя твоего мода из Activate()
[/quote]

Сделал вот так

Код:
function Activate()
	GameRules.AddonTemplate = CAddonTemplateGameMode()
	GameRules.AddonTemplate:InitGameMode()
end

function CAddonTemplateGameMode:InitGameMode()
	print( "Template addon is loaded." )
	GameRules:GetGameModeEntity():SetThink( "OnThink", self, "GlobalThink", 2 )
	ListenToGameEvent("dota_player_pick_hero", Dynamic_Wrap(CAddonTemplateGameMode, "OnHeroPicked"), self)
end

function CAddonTemplateGameMode:OnHeroPicked (event) 
  	local hero = EntIndexToHScript(event.heroindex)
	if hero then 
       RemoveWearables(hero)
  	end

	print("Hero picked, hero:" .. hero:GetUnitName())

end

function RemoveWearables(hero)
  print('#RemoveWearables')
  local wearables = {} -- объявление локального массива на удаление
  local cur = hero:FirstMoveChild() -- получаем первый указатель над подобъект объекта hero ()

  while cur ~= nil do --пока наш текущий указатель не равен nil(пустота/пустой указатель)
    cur = cur:NextMovePeer() -- выбираем следующий указатель на подобъект нашего обьекта
    if cur ~= nil and cur:GetClassname() ~= "" and cur:GetClassname() == "dota_item_wearable" then -- проверяем, елси текущий указатель не пуст, название класса не пустое, и если этот класс есть класс "dota_item_wearable", то есть надеваемые косметические предметы
      table.insert(wearables, cur) -- добавляем в таблицу на удаление текущий предмет(сверху проверяли класс текущего объекта)
    end
  end
 
  for i = 1, #wearables do -- собственно цикл для удаления всего занесенного в массив на удаление
    UTIL_Remove(wearables[i]) -- удаляем объект
  end
end

в Addon_Game_Mode.lua

в игре пишет вот такого плана ошибку

image.png
 
Последнее редактирование модератором:

CryDeS

Друзья CG
14 Июл 2015
1,210
11
[quote author=wetalq link=topic=214.msg1386#msg1386 date=1440069353]
Сделал вот так

Код:
function Activate()
	GameRules.AddonTemplate = CAddonTemplateGameMode()
	GameRules.AddonTemplate:InitGameMode()
end

function CAddonTemplateGameMode:InitGameMode()
	print( "Template addon is loaded." )
	GameRules:GetGameModeEntity():SetThink( "OnThink", self, "GlobalThink", 2 )
	ListenToGameEvent("dota_player_pick_hero", Dynamic_Wrap(CAddonTemplateGameMode, "OnHeroPicked"), self)
end

function CAddonTemplateGameMode:OnHeroPicked (event) 
  	local hero = EntIndexToHScript(event.heroindex)
	if hero then 
       RemoveWearables(hero)
  	end

	print("Hero picked, hero:" .. hero:GetUnitName())

end

function RemoveWearables(hero)
  print('#RemoveWearables')
  local wearables = {} -- объявление локального массива на удаление
  local cur = hero:FirstMoveChild() -- получаем первый указатель над подобъект объекта hero ()

  while cur ~= nil do --пока наш текущий указатель не равен nil(пустота/пустой указатель)
    cur = cur:NextMovePeer() -- выбираем следующий указатель на подобъект нашего обьекта
    if cur ~= nil and cur:GetClassname() ~= "" and cur:GetClassname() == "dota_item_wearable" then -- проверяем, елси текущий указатель не пуст, название класса не пустое, и если этот класс есть класс "dota_item_wearable", то есть надеваемые косметические предметы
      table.insert(wearables, cur) -- добавляем в таблицу на удаление текущий предмет(сверху проверяли класс текущего объекта)
    end
  end
 
  for i = 1, #wearables do -- собственно цикл для удаления всего занесенного в массив на удаление
    UTIL_Remove(wearables[i]) -- удаляем объект
  end
end

в Addon_Game_Mode.lua

в игре пишет вот такого плана ошибку

[/quote]
Добавь проверку на IsHero
 
Последнее редактирование модератором:

MahouShoujo

Продвинутый
3 Ноя 2016
251
23
Юзлесс. Может отдаленно пригодиться только если нужно удалять в рантайме.

"DisableWearables" "1"
 
Последнее редактирование модератором:
  • Нравится
Реакции: Sannin

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Юзлесс. Может отдаленно пригодиться только если нужно удалять в рантайме.

"DisableWearables" "1"
Если мне не изменяет память(а она может), то DisableWearables вышло после этого топика, ну или я даун.
 
Последнее редактирование модератором:

Илья

Друзья CG
25 Сен 2015
2,348
41
[quote author=CryDeS link=topic=214.msg9369#msg9369 date=1494876228]
Если мне не изменяет память(а она может), то DisableWearables вышло после этого топика, ну или я даун.
[/quote]

3eol5w.jpg
 
  • Нравится
Реакции: Son1cPr00wer

MahouShoujo

Продвинутый
3 Ноя 2016
251
23
Если мне не изменяет память(а она может), то DisableWearables вышло после этого топика, ну или я даун.

Не изменяет, штука относительно (выхода реборна) новая. Либо про нее просто не знали. Я и имел в виду что теперь юзлесс.
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Последнее редактирование модератором:

Sannin

Пользователь
6 Янв 2019
28
5
Проект
NWHC
"DisableWearables" убирает предметы в самой игре (после пика они не удаляются всё ещё). Если смотреть на предложенный ранее скрипт, то может вместо события
OnHeroPicked есть какое-то ещё, которое удалит всё на стадии пика?
 
Реклама: