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

Илья

Друзья CG
25 Сен 2015
2,348
41
Итак, в этой теме я задавал вопрос: "а как сделать так, чтобы при смерти героя, с него выпадали его вещи?"
Создал отдельную тему, ибо так код будет проще найти да и это же все же скрипт.
Почему не "можно ли", а сразу "как"? Ну, об этом не здесь.

Значит, на данный момент, более простого способа не нашел. На более красивый мне делает намеки 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() при смерти юнита, то все работает. В чем же косяк? Почему так? Да дело в том, что хоть обе функции

kUiPh09.png

2132qN9.png

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

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

Так что же не так? А вот, что: если обратить внимание на шапки функций, то можно увидеть следующую картину:
ysNEsb5.png
(схема 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", находим интересную функцию:

uND88T9.png

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

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

Код:
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
 
Последнее редактирование модератором:
  • Нравится
Реакции: SH4R1K

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Шикарное разбирательство. Плюсанул бы, да сайт уже запрещает тебя плюсить -.-
 

Илья

Друзья CG
25 Сен 2015
2,348
41
Решая некоторые новые вопросы на GitHab`e, наткнулся на один интересный источник.

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

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

xxNpCxx

Активный
16 Окт 2015
85
0
[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() при смерти юнита, то все работает. В чем же косяк? Почему так? Да дело в том, что хоть обе функции

kUiPh09.png

2132qN9.png

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

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

Так что же не так? А вот, что: если обратить внимание на шапки функций, то можно увидеть следующую картину:
ysNEsb5.png
(схема 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", находим интересную функцию:

uND88T9.png

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

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

Код:
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
Проект
Dota2 Monopoly
Куда вставлять этот код, в game addon?
 
Реклама: