Кодим функции: "дроп с игрока" или "будьте внимательнее"

Илья

Супермодератор
Команда форума
25 Сен 2015
2,348
40
48
27
Реакции
40 0 0
#1
Итак, в этой теме я задавал вопрос: "а как сделать так, чтобы при смерти героя, с него выпадали его вещи?"
Создал отдельную тему, ибо так код будет проще найти да и это же все же скрипт.
Почему не "можно ли", а сразу "как"? Ну, об этом не здесь.

Значит, на данный момент, более простого способа не нашел. На более красивый мне делает намеки CryDeS, за что ему спасибо, но мне тааак лень реализовывать это. Да и ресурсы, которые в итоге будут сэкономлены, не так важны в данной ситуации (мы же не шаттл строим).


Первым делом обращаем внимание на слушателя:

Код:
ListenToGameEvent("entity_killed", OnEntityKilled, nil)
И, взятой отсюда, пример функции вроде:

Код:
 function OnEntityKilled (event)
  local killedEntity = EntIndexToHScript(event.entindex_killed)
  if killedEntity ~= nil then
   CreateDrop("item_flask", killedEntity:GetAbsOrigin())
  end
 end

 function CreateDrop (itemName, pos)
  local newItem = CreateItem(itemName, nil, nil)
  newItem:SetPurchaseTime(0)
  CreateItemOnPositionSync(pos, newItem)
  newItem:LaunchLoot(false, 300, 0.75, pos + RandomVector(RandomFloat(50, 350)))
 end

Кто читал эту тему, да и просто, кто "почти в теме", зададуться сразу же вопросом: хммм, чувак, да по стуи, можно взять этот код, задать слушателю ловить не убийство юнитов, а убийство конкретно игрока, сменить в функции "OnEntityKilled":

Код:
 local killedEntity = EntIndexToHScript(event.entindex_killed)
на

Код:
local killedPlayer = PlayerResource:GetPlayer(data.PlayerID)
Покопаться в этом источнике в поисках подходящих функция и готово, получится что-то вроде этого:

Код:
 function FT:InitGameMode()
   ListenToGameEvent("dota_player_killed", Dynamic_Wrap(FT, "OnHeroKilled"), self) --ловим событие смерти игрока
end 
  
  
function FT:OnHeroKilled(data)
  local killedPlayer = PlayerResource:GetPlayer(data.PlayerID) --получаем игрока
  if killedPlayer:GetNumItemsInInventory() ~=0 then --проверяем наличие вещей в инвентаре
	  for i=0,5 do --Дорогая, как же все шестеро детей на месте? смотри: 0, 1, 2...
			local item = killedPlayer:GetItemInSlot(i); --получаем вещицу из слота инвентаря
			--не знаю, как можно выяснить номера ячеек с вещью, поэтому мутим так
			if item ~= nil then --проверяем на пустую ячейку
				local position = killedPlayer:GetAbsOrigin() -- позиция игрока
				local name = item:GetAbilityName() -- берем имя шмоточки, не знаю альтернативной функции
				killedPlayer:RemoveItem(item)	-- удаляем шмоточку из инвентаря	
				FT:CreateDrop(name, position) -- создаем шмоточку по имени
			end
		end
  end
	
end

 function FT:CreateDrop (itemName, pos)
  local newItem = CreateItem(itemName, nil, nil)
  newItem:SetPurchaseTime(0) --как я понял, чтобы не было задержки
  CreateItemOnPositionSync(pos, newItem) 
  newItem:LaunchLoot(false, 300, 0.75, pos + RandomVector(RandomFloat(50, 350))) --красивый эффект падения
 end

Однако, жмем мы такие, значит, кнопку build и, будучи Бэном Аффлеком, говорим: "Я бэтмен".
А нам в ответ: "нет".
Вы такие: "Что, вот мой костюм, я Бэтмен! "
А вам : "Вы не Кристиан Бэйл".

К чему я это... Да к тому, что код не заработает.
Однако, если мутить не через GetPlayer() при смерти героя, а через EntIndexToHScript() при смерти юнита, то все работает. В чем же косяк? Почему так? Да дело в том, что хоть обе функции

proxy.php?image=http%3A%2F%2Fi.imgur.com%2FkUiPh09.png%3F1&hash=743bfb13f6a900953e80d570a2a1eb6c

proxy.php?image=http%3A%2F%2Fi.imgur.com%2F2132qN9.png%3F1&hash=140184f4b49f0e732126767c0588c8f5

Дают нам handle`r,это еще не говорит о том, что это один и тот же handle`r (хотя в ООП, получая один и тот же класс, тип данных, вы точно уверены, что можете с ним творить то, что разрешено делать с этим классом в документации).

Нет, ребята, тут не ООП. И моя невнимательность привела меня к ошибке.

Так что же не так? А вот, что: если обратить внимание на шапки функций, то можно увидеть следующую картину:
proxy.php?image=http%3A%2F%2Fi.imgur.com%2FysNEsb5.png%3F1&hash=5db5741c8ec8ee96990e04b21dd879bb
(схема 1)​

Кто еще не понял, разъясню: дело в том, что handle`r из метода GetPlayer() относится к классу "CDOTA_PlayerResource", а мы пытаемся на нем развернуть метод, который относится к "CDOTA_BaseNPC_Hero". Обертка одинаковая, а начинка разная.
На "схеме 1" видно, что это методы двух разных дорог, полос развития. На handle`r из GetPlayer() можно воздействовать методами из CBaseEntity, но нельзя воздействовать методами CBazeAnimating и т.д. Однако, методы ветки CBazeAnimating работают для handle`r из Global (EntIndexToHScript()). Handle`r из GetPlayer() - он player-овский, а handle`r из EntIndexToHScript() - это handle`r entity-вский. Хоть player в теории изначально и был entity, но он уже не помидор, а кетчуп.

Но, копаясь дальше в "CDOTA_PlayerResource", находим интересную функцию:

proxy.php?image=http%3A%2F%2Fi.imgur.com%2FuND88T9.png%3F1&hash=9b2712dac34249fa8fb0338974fdb80a

Что это, спросите вы меня? А я вам скажу - это сокосжиматель, делающий из кетчупа помидор.

Конечный код:

Код:
function FT:InitGameMode() 
 ListenToGameEvent("dota_player_killed", Dynamic_Wrap(FT, "OnHeroKilled"), self)
en

function FT:OnHeroKilled(data)
print("----------------------------------------Hero Killed----------------------------------------")
	local killedEntity = PlayerResource:GetSelectedHeroEntity(data.PlayerID)
  if killedEntity:GetNumItemsInInventory() ~=0 then
	  for i=0,5 do
			local item = killedEntity:GetItemInSlot(i);
			if item ~= nil then
				local position = killedEntity:GetAbsOrigin()
				local name = item:GetAbilityName()
				killedEntity:RemoveItem(item)		
				FT:CreateDrop(name, position)
			end
		end
  end
	
end

 function FT:CreateDrop (itemName, pos)
  local newItem = CreateItem(itemName, nil, nil)
  newItem:SetPurchaseTime(0)
  CreateItemOnPositionSync(pos, newItem)
  newItem:LaunchLoot(false, 300, 0.75, pos + RandomVector(RandomFloat(50, 350)))
 end
 
Последнее редактирование модератором:

CryDeS

Друзья CG
14 Июл 2015
1,210
9
38
18
Реакции
9 0 0
#2
Шикарное разбирательство. Плюсанул бы, да сайт уже запрещает тебя плюсить -.-
 

Илья

Супермодератор
Команда форума
25 Сен 2015
2,348
40
48
27
Реакции
40 0 0
#3
Последнее редактирование модератором:

Илья

Супермодератор
Команда форума
25 Сен 2015
2,348
40
48
27
Реакции
40 0 0
#4
Решая некоторые новые вопросы на GitHab`e, наткнулся на один интересный источник.

Таким образом можно задавать конкретной вещи "пассивку" , которая будет ее дропать из инвентаря игрока.
А раз мой код похож на этот, то я не могу не радоваться, ибо выходит, что я более менее правильно реализовал идею.

Может, кому пригодиться на будущее: кто любит прилагать больше усилий, но при этом делать основной код легче.
 
Последнее редактирование модератором:

xxNpCxx

Активный
16 Окт 2015
85
0
6
25
Реакции
0 0 0
#5
[quote author=Илья link=topic=319.msg1727#msg1727 date=1444688990]
Итак, в этой теме я задавал вопрос: "а как сделать так, чтобы при смерти героя, с него выпадали его вещи?"
Создал отдельную тему, ибо так код будет проще найти да и это же все же скрипт.
Почему не "можно ли", а сразу "как"? Ну, об этом не здесь.

Значит, на данный момент, более простого способа не нашел. На более красивый мне делает намеки CryDeS, за что ему спасибо, но мне тааак лень реализовывать это. Да и ресурсы, которые в итоге будут сэкономлены, не так важны в данной ситуации (мы же не шаттл строим).


Первым делом обращаем внимание на слушателя:

Код:
ListenToGameEvent("entity_killed", OnEntityKilled, nil)
И, взятой отсюда, пример функции вроде:

Код:
 function OnEntityKilled (event)
  local killedEntity = EntIndexToHScript(event.entindex_killed)
  if killedEntity ~= nil then
   CreateDrop("item_flask", killedEntity:GetAbsOrigin())
  end
 end

 function CreateDrop (itemName, pos)
  local newItem = CreateItem(itemName, nil, nil)
  newItem:SetPurchaseTime(0)
  CreateItemOnPositionSync(pos, newItem)
  newItem:LaunchLoot(false, 300, 0.75, pos + RandomVector(RandomFloat(50, 350)))
 end

Кто читал эту тему, да и просто, кто "почти в теме", зададуться сразу же вопросом: хммм, чувак, да по стуи, можно взять этот код, задать слушателю ловить не убийство юнитов, а убийство конкретно игрока, сменить в функции "OnEntityKilled":

Код:
 local killedEntity = EntIndexToHScript(event.entindex_killed)
на

Код:
local killedPlayer = PlayerResource:GetPlayer(data.PlayerID)
Покопаться в этом источнике в поисках подходящих функция и готово, получится что-то вроде этого:

Код:
 function FT:InitGameMode()
   ListenToGameEvent("dota_player_killed", Dynamic_Wrap(FT, "OnHeroKilled"), self) --ловим событие смерти игрока
end 
  
  
function FT:OnHeroKilled(data)
  local killedPlayer = PlayerResource:GetPlayer(data.PlayerID) --получаем игрока
  if killedPlayer:GetNumItemsInInventory() ~=0 then --проверяем наличие вещей в инвентаре
	  for i=0,5 do --Дорогая, как же все шестеро детей на месте? смотри: 0, 1, 2...
			local item = killedPlayer:GetItemInSlot(i); --получаем вещицу из слота инвентаря
			--не знаю, как можно выяснить номера ячеек с вещью, поэтому мутим так
			if item ~= nil then --проверяем на пустую ячейку
				local position = killedPlayer:GetAbsOrigin() -- позиция игрока
				local name = item:GetAbilityName() -- берем имя шмоточки, не знаю альтернативной функции
				killedPlayer:RemoveItem(item)	-- удаляем шмоточку из инвентаря	
				FT:CreateDrop(name, position) -- создаем шмоточку по имени
			end
		end
  end
	
end

 function FT:CreateDrop (itemName, pos)
  local newItem = CreateItem(itemName, nil, nil)
  newItem:SetPurchaseTime(0) --как я понял, чтобы не было задержки
  CreateItemOnPositionSync(pos, newItem) 
  newItem:LaunchLoot(false, 300, 0.75, pos + RandomVector(RandomFloat(50, 350))) --красивый эффект падения
 end

Однако, жмем мы такие, значит, кнопку build и, будучи Бэном Аффлеком, говорим: "Я бэтмен".
А нам в ответ: "нет".
Вы такие: "Что, вот мой костюм, я Бэтмен! "
А вам : "Вы не Кристиан Бэйл".

К чему я это... Да к тому, что код не заработает.
Однако, если мутить не через GetPlayer() при смерти героя, а через EntIndexToHScript() при смерти юнита, то все работает. В чем же косяк? Почему так? Да дело в том, что хоть обе функции

proxy.php?image=http%3A%2F%2Fi.imgur.com%2FkUiPh09.png%3F1&hash=743bfb13f6a900953e80d570a2a1eb6c

proxy.php?image=http%3A%2F%2Fi.imgur.com%2F2132qN9.png%3F1&hash=140184f4b49f0e732126767c0588c8f5

Дают нам handle`r,это еще не говорит о том, что это один и тот же handle`r (хотя в ООП, получая один и тот же класс, тип данных, вы точно уверены, что можете с ним творить то, что разрешено делать с этим классом в документации).

Нет, ребята, тут не ООП. И моя невнимательность привела меня к ошибке.

Так что же не так? А вот, что: если обратить внимание на шапки функций, то можно увидеть следующую картину:
proxy.php?image=http%3A%2F%2Fi.imgur.com%2FysNEsb5.png%3F1&hash=5db5741c8ec8ee96990e04b21dd879bb
(схема 1)​

Кто еще не понял, разъясню: дело в том, что handle`r из метода GetPlayer() относится к классу "CDOTA_PlayerResource", а мы пытаемся на нем развернуть метод, который относится к "CDOTA_BaseNPC_Hero". Обертка одинаковая, а начинка разная.
На "схеме 1" видно, что это методы двух разных дорог, полос развития. На handle`r из GetPlayer() можно воздействовать методами из CBaseEntity, но нельзя воздействовать методами CBazeAnimating и т.д. Однако, методы ветки CBazeAnimating работают для handle`r из Global (EntIndexToHScript()). Handle`r из GetPlayer() - он player-овский, а handle`r из EntIndexToHScript() - это handle`r entity-вский. Хоть player в теории изначально и был entity, но он уже не помидор, а кетчуп.

Но, копаясь дальше в "CDOTA_PlayerResource", находим интересную функцию:

proxy.php?image=http%3A%2F%2Fi.imgur.com%2FuND88T9.png%3F1&hash=9b2712dac34249fa8fb0338974fdb80a

Что это, спросите вы меня? А я вам скажу - это сокосжиматель, делающий из кетчупа помидор.

Конечный код:

Код:
function FT:InitGameMode() 
 ListenToGameEvent("dota_player_killed", Dynamic_Wrap(FT, "OnHeroKilled"), self)
en

function FT:OnHeroKilled(data)
print("----------------------------------------Hero Killed----------------------------------------")
	local killedEntity = PlayerResource:GetSelectedHeroEntity(data.PlayerID)
  if killedEntity:GetNumItemsInInventory() ~=0 then
	  for i=0,5 do
			local item = killedEntity:GetItemInSlot(i);
			if item ~= nil then
				local position = killedEntity:GetAbsOrigin()
				local name = item:GetAbilityName()
				killedEntity:RemoveItem(item)		
				FT:CreateDrop(name, position)
			end
		end
  end
	
end

 function FT:CreateDrop (itemName, pos)
  local newItem = CreateItem(itemName, nil, nil)
  newItem:SetPurchaseTime(0)
  CreateItemOnPositionSync(pos, newItem)
  newItem:LaunchLoot(false, 300, 0.75, pos + RandomVector(RandomFloat(50, 350)))
 end
[/quote]
Молодец!
 
Последнее редактирование модератором:
Реклама:

Maker

Новичок
6 Май 2019
8
0
1
19
Проект
Dota2 Monopoly
Реакции
0 0 0
#6
Куда вставлять этот код, в game addon?
 
Реклама: