Урок Полезные API для ваших кастомок (30.07.2016 обновлено)

Se7eN

Друзья CG
22 Ноя 2014
334
18
Здесь будут размещены готовые и проверенные APIшки, которые вы сможете подключить к своему моду и не париться за них, так как они 100% рабочие.
API - какая-нибудь функция, которая расширяет ваши возможности.
Допустим в стандартном API от Valve нет функции ResetAllAbilityCooldowns() которая бы перезарядила полностью кулдауны героя на предметах и способностях. Или допустим нет такой функции, которая перед дуэлью сохраняла его позицию, хп, ману, кулдауны, а затем после дуэли возвращала эти значение.
Авторские права соблюдены, я выкладываю только те API, которые нам предоставили на GitHub'e или свои лично.

Предупреждение: это не тема для вопросов "как вставить их к себе?", поскольку если вы не умеете вставлять эти функции, то лучше сначала научиться их писать. Этот топик для экономии времени.

ResetAllAbilitiesCooldown(unit, refresh_items) - перезаряжает способности героя и все его предметы.
Если вторым параметром стоит true, то будут перезаряжены и предметы.
Код:
function ResetAllAbilitiesCooldown(table unit, bool refresh_items) 
	local abilities = unit:GetAbilityCount()
	for i = 0, abilities-1 do
		local ability = unit:GetAbilityByIndex(i)
		if ability and not ability:IsCooldownReady() then
			ability:EndCooldown()
		end
	end
	if unit:HasInventory() and refresh_items then
		for i = 0, 5 do
			local item = unit:GetItemInSlot(i)
			if item and not item:IsCooldownReady() then
			item:EndCooldown()
			end
		end
	end
end

AddRandomAttribute(hero, amount) - повышает случайный аттрибут у героя на указанную величину.
hero - герой
amount - насколько повысить
Код:
function AddRandomAttribute(hero,amount)
local atr = 0
local rnd = math.random(1,3)
	if rnd == 1 
		then 
			atr = hero:GetStrength()
			hero:ModifyStrength(amount)
		end
			
	if rnd == 2 
		then 
			atr = hero:GetAgility()
			hero:ModifyAgility(amount)
		end
	
	if rnd == 3
		then
			atr = hero:GetIntellect()
			hero:ModifyIntellect(amount)
	end
	hero:CalculateStatBonus()
	
	end

CheckRuneModifiersAndRemove(hero) - удаляет эффекты рун с героя. Функция написана дедовским способом, зато никаких проверок.
Код:
function CheckRuneModifiersAndRemove(hero)
hero:RemoveModifierByName("modifier_rune_doubledamage")
hero:RemoveModifierByName("modifier_rune_haste")
hero:RemoveModifierByName("modifier_rune_invis")
hero:RemoveModifierByName("modifier_rune_regen")
end

IsExpSkill(abilityname) - у меня на карте некоторые способности при касте дают опыт. Так вот именно эта функция может быть простеньким примером проверки того, та ли эта способность, которая дает опыт.
Можно переписать под проверку чего угодно - определенного предмета, способности, названия юнитов и прочее.
И еще если вам нужно проверить таблицу на наличие в ней определенного значения - тоже сюда.
abilityname - название способности.
Код:
function IsExpSkill(abilityname)
local SS = {
"omni_bless_datadriven",
"omni_incagi_datadriven",
"omni_anaphema_datadriven",
"omni_holylight_datadriven",
"invoker_alacrity",
"invoker_coldsnap",
"satir_marionet"
}
 	for _,v in pairs(SS) do
		if v == abilityname then return true end
	end
return false
end

function AddExp(hero,amount) - простая функция добавления опыта. Чтобы не запариваться с этими true, false и писать быстрее.
Код:
function AddExp(hero,amount)
hero:AddExperience(amount, false, false)
end

Связка функций function SaveAbout(hero) и function RestorePos(hero)
function SaveAbout(hero) - сохраняет местоположение, хп, кулдауны на скиллах, ману
function RestorePos(hero) - возвращает старые значение хп, кулдауны на скиллах, ману
Нужно, например, перед дуэлью сохранить все. Потом допустим сделать героя фулловым, перезарядить скиллы. Далее герой дерётся и потом вы возвращается его на старое место откуда взяли, вместе с кулдаунами хп и маной.
Код:
function SaveAbout(hero) 

hero.position = hero:GetAbsOrigin()
hero.mana = hero:GetMana()
hero.hp = hero:GetHealth()
hero.saved = true

local count = hero:GetAbilityCount()
--GetCooldownTimeRemaining()
		for i = 0, count do
		 local ability = hero:GetAbilityByIndex(i)
		 if ability:GetLevel() == 0 then hero.ability[i] = nil 
			else
				if ability and not ability:IsCooldownReady() then
					hero.ability[i] = ability:GetCooldownTimeRemaining()
		 end
		end
	end
DeepPrintTable(hero)
print("saved")
end

function RestorePos(hero) --восстановить кдшки, хп, ману и позиция героя после дуэли
	if hero.saved then
		local position = hero.position
		local hp = hero.hp
		local mana = hero.mana
		hero.saved = false
		hero:SetHealth(hp)
		local count = hero:GetAbilityCount()
		FindClearSpaceForUnit(hero, position, false)
			for i = 0, count do
				 if hero.ability[i] ~= nil then 
					hero:GetAbilityByIndex(i):StartCooldown(hero.ability[i])
				 end
			end
			
		hero.position = nil
		hero.hp = nil
		hero.mana = nil
			for i = 0,5 do
				hero.ability[i] = nil
			end
	end
end

HeroHasItemsFromList(hero) - проверяет есть ли у героя предмет из списка (можете прописать, например, зелья)
не забудьте внести в таблицу itemz список предметов, которые будете проверять. У меня важно делить слоты на оружия, зелья и т.п. поэтому и была написана эта апишка
Код:
function IsHeroHasItemsFromList(hero)
local itemz = {"item_tetragrammaton", "item_seven"}
	for _,v in pairs(armor) do
		if hero:HasItemInInventory(v) then return true end
	end
return false
end


Связка функция ItemDrop + ReleaseItem. Первая отвечает за дроп с шансом, вторая за выброс его как лут.
Здесь у меня 3 параметра hero (убийца героя), boss (умирающий юнит), chance (шанс) Не ошибитесь.
Если надо дропнуть другое с другим шансом, либо дублируете функцию, либо дописываете прямо здесь с новой таблицей и новым списком. Допустим кинжалы дропаются с 5% шансом, а зелья с 90%.
Код:
function ItemDrop(hero,boss,chance)
local point = boss:GetAbsOrigin()
local name = boss:GetUnitName()
local drop = {} --список предметов для дропа тут, пишете все предметы. 
drop[1] = "item_cursed_gloves"
drop[2] = "item_big_axe"
drop[3] = "item_ring_of_decrease"
drop[4] = "item_armor_plate"
drop[5] = "item_amulet_of_life"
drop[6] = "item_evasion_wings"
drop[7] = "item_cat_figure_of_resistance"
drop[8] = "item_rosary"
drop[9] = "item_circlet_of_majesty"
drop[10] = "item_helm_of_strength"
drop[11] = "item_platinum_cutter"

	if RollPercentage(chance) then 	
		local itemz = drop[math.random(#drop)]
		local item = CreateItem(itemz, hero,hero)
		ReleaseItem(point,item)
	end
	


end

function ReleaseItem(point,item)
CreateItemOnPositionSync( point, item )
item:LaunchLoot(false, 300, 0.75, point+RandomVector(50))
end
 
Последнее редактирование модератором:
  • Нравится
Реакции: Alex_Inc_ и Qunian

Se7eN

Друзья CG
22 Ноя 2014
334
18
Re: Полезные API для ваших кастомок (26.07.2016 обновлено)

Резервный пост для обновлений.
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Re: Полезные API для ваших кастомок (26.07.2016 обновлено)

table SaveAbilitiesCooldowns(hUnit) - сохраняет кд абилок и айтемов юнита в таблицу
Код:
function SaveAbilitiesCooldowns(unit)
  if not unit then return end
  
  local savetable = {}
  local abilities = unit:GetAbilityCount() - 1
  for i = 0, abilities do
    if unit:GetAbilityByIndex(i) then
      savetable[i] = unit:GetAbilityByIndex(i):GetCooldownTimeRemaining()
    end
  end

  savetable.items = {}

  for i = 0, 5 do
    if unit:GetItemInSlot(i) then
      savetable.items[unit:GetItemInSlot(i)] = unit:GetItemInSlot(i):GetCooldownTimeRemaining() 
    end
  end

  return savetable
end

nil SetAbilitiesCooldowns(hUnit, table) - устанавливает значение кд айтемов и абилок юнита из сохраненной таблицы.

Код:
function SetAbilitiesCooldowns(unit, settable)
  local abilities = unit:GetAbilityCount() - 1
  if not settable or not unit then return end
  for i = 0, abilities do
    if unit:GetAbilityByIndex(i) then
      unit:GetAbilityByIndex(i):StartCooldown(settable[i])
      if settable[i] == 0 then 
        unit:GetAbilityByIndex(i):EndCooldown() 
      end
    end
  end

  if settable.items then
    for item, cooldown in pairs(settable.items) do
      if item and IsValidEntity(item) then
        item:EndCooldown() 
        item:StartCooldown(cooldown) 
      end
    end
  end
end

Так как использовать кучу демедж фильтров не тру(да и они могут не работать вообще если их несколько), а лайфстил от магии сделать нужно, то я запилил такую вот штуку.
В ваш демедж фильтр
Код:
if (damagetype_const > 1 or skill_name ~= "") then
		local callback_data = {
				caster 		= attacker,
				target 		= victim, 
				skill_name 	= skill_name,
				damage 		= damage,
				damage_type = damagetype_const,
			}
		MagicLifesteal:GlobalListen(callback_data)
	end
И как отдельную библиотеку, которую подключите:
Код:
MagicLifesteal = class({})

local disabled_lifesteal_skills = {
	["necrolyte_heartstopper_aura"] = 1,
	["item_blade_mail"]				= 1,
}

function MagicLifesteal:GlobalListen( keys )
	local caster 		= keys.caster
	local target 		= keys.target
	local damage 		= keys.damage
	local skill_name 	= keys.skill_name
 
 	if disabled_lifesteal_skills[skill_name] then return end

 	if target:IsIllusion() then return end

	local lifesteal_pct = 0;
	if target == caster then return end
	if caster:HasModifier("modifier_skeleton_king_reincarnation_scepter_active") then return end
	
	if target:IsHero() then lifesteal_pct = MagicLifesteal:_GetUnitMagicLifesteal_toHero(caster) / 100
	else lifesteal_pct = MagicLifesteal:_GetUnitMagicLifesteal_toCreep(caster) / 100 end

	if lifesteal_pct == 0 then return end

	local particle_lifesteal = "particles/items3_fx/octarine_core_lifesteal.vpcf"
	local lifesteal_fx = ParticleManager:CreateParticle(particle_lifesteal, PATTACH_ABSORIGIN_FOLLOW, caster)
	ParticleManager:SetParticleControl(lifesteal_fx, 0, caster:GetAbsOrigin())

	if damage*lifesteal_pct < 1 or damage*lifesteal_pct > caster:GetHealth() or damage*lifesteal_pct > 1000000 then return end

	caster:Heal(damage*lifesteal_pct , caster)
end

function MagicLifesteal:_GetUnitMagicLifesteal_toCreep(unit)
	local total_lifesteal = 0;
	if not unit:HasInventory() then return 0 end
	
	for item_name, lifesteal_data in pairs(self.items) do
		if unit:HasItemInInventory(item_name) then
			local item = MagicLifesteal:_FindItemInInventory(unit, item_name)

			if (lifesteal_data.creep) then
				local amount = item:GetSpecialValueFor(lifesteal_data.creep)
				if amount > total_lifesteal then total_lifesteal = amount end
			end

			if(lifesteal_data.all) then
				local amount = item:GetSpecialValueFor(lifesteal_data.all)
				if amount > total_lifesteal then total_lifesteal = amount end
			end
		end
	end

	for ability_name, lifesteal_data in pairs(self.abilities) do
		if unit:HasAbility(item_name) then

			local ability = unit:FindAbilityByName(ability_name)

			if (lifesteal_data.creep) then
				local amount = ability:GetSpecialValueFor(lifesteal_data.creep)
				if amount > total_lifesteal then total_lifesteal = amount end
			end

			if(lifesteal_data.all) then
				local amount = ability:GetSpecialValueFor(lifesteal_data.all)
				if amount > total_lifesteal then total_lifesteal = amount end
			end

		end
	end
	return total_lifesteal;
end

function MagicLifesteal:_GetUnitMagicLifesteal_toHero(unit)
	local total_lifesteal = 0;
	if unit or not unit:HasInventory() then return 0 end
	for item_name, lifesteal_data in pairs(self.items) do
		if unit:HasItemInInventory(item_name) then
			local item = MagicLifesteal:_FindItemInInventory(unit, item_name)

			if (lifesteal_data.hero) then
				local amount = item:GetSpecialValueFor(lifesteal_data.hero)
				if amount > total_lifesteal then total_lifesteal = amount end
			end

			if(lifesteal_data.all) then
				local amount = item:GetSpecialValueFor(lifesteal_data.all)
				if amount > total_lifesteal then total_lifesteal = amount end
			end
		end
	end

	for ability_name, lifesteal_data in pairs(self.abilities) do
		if unit:HasAbility(item_name) then

			local ability = unit:FindAbilityByName(ability_name)

			if (lifesteal_data.hero) then
				local amount = ability:GetSpecialValueFor(lifesteal_data.hero)
				if amount > total_lifesteal then total_lifesteal = amount end
			end

			if(lifesteal_data.all) then
				local amount = ability:GetSpecialValueFor(lifesteal_data.all)
				if amount > total_lifesteal then total_lifesteal = amount end
			end

		end
	end
	return total_lifesteal;
end

function MagicLifesteal:_FindItemInInventory(unit, item_name)
	for i = 0, 5 do
		local item = unit:GetItemInSlot(i) 
		if item and item:GetName() == item_name then
			return item;
		end
	end
end

function MagicLifesteal:RegisterLifestealAbility( ability_name, all_lifesteal)
	self.abilities[ability_name] = self.abilities[ability_name] or {}
	self.abilities[ability_name].all = all_lifesteal;
end

function MagicLifesteal:RegisterLifestealAbility( ability_name, hero_lifesteal, creep_lifesteal)
	self.abilities[ability_name] = self.abilities[ability_name] or {};
	self.abilities[ability_name].hero = hero_lifesteal;
	self.abilities[ability_name].creep = creep_lifesteal;
end

function MagicLifesteal:RegisterLifestealItem(item_name, all_lifesteal)
	self.items[item_name] = self.items[item_name] or {};
	self.items[item_name].all = all_lifesteal;
end

function MagicLifesteal:RegisterLifestealItem(item_name, hero_lifesteal, creep_lifesteal)
	self.items[item_name] = self.items[item_name] or {};
	self.items[item_name].hero = hero_lifesteal;
	self.items[item_name].creep = creep_lifesteal;
end

function MagicLifesteal:_init()
	_G._MagicLifesteal = {}
	_G._MagicLifesteal.main = function( keys ) MagicLifesteal:GlobalListen( keys ); end

	self.items = {}
	self.abilities = {}
	--MagicLifesteal:RegisterLifestealItem("item_octarine_core", "hero_lifesteal", "creep_lifesteal")
	MagicLifesteal:RegisterLifestealItem("item_octarine_core_2", "hero_lifesteal", "creep_lifesteal")

end

MagicLifesteal:_init()
Что бы добавить ваши айтемы можно закинуть в этой же библиотеке в _init функцию или вообще куда угодно и когда угодно.
MagicLifesteal:RegisterLifestealItem(item_name, lifesteal_hero_key, lifesteal_creep_key)
либо
MagicLifesteal:RegisterLifestealItem(item_name, total_lifesteal_key)
lifesteal_hero_key, lifesteal_creep_key, total_lifesteal_key - ключевые слова из AbilitySpecial из датадривена для этого предмета.

Для лайфстила с абилок есть две другие функции, работающие по сути так же:
MagicLifesteal:RegisterLifestealAbility( ability_name, hero_lifesteal_key, creep_lifesteal_key)
MagicLifesteal:RegisterLifestealAbility( ability_name, all_lifesteal_key)


Ну и если вдруг не нужно лайфстилить с некоторых скиллов, в начале библиотеки есть табличка запрещенных на лайфстил скиллов(ибо лайфстилит с ЛЮБОЙ абилки, или с ЛЮБОГО типа урона не физического при атаке с руки).
 
Последнее редактирование модератором:

Adam Smith

Друзья CG
4 Окт 2014
473
2
Re: Полезные API для ваших кастомок (26.07.2016 обновлено)

[quote author=Se7eN link=topic=1006.msg5441#msg5441 date=1469529067]
Здесь будут размещены готовые и проверенные APIшки, которые вы сможете подключить к своему моду и не париться за них, так как они 100% рабочие.
API - какая-нибудь функция, которая расширяет ваши возможности.
Допустим в стандартном API от Valve нет функции ResetAllAbilityCooldowns() которая бы перезарядила полностью кулдауны героя на предметах и способностях. Или допустим нет такой функции, которая перед дуэлью сохраняла его позицию, хп, ману, кулдауны, а затем после дуэли возвращала эти значение.
Авторские права соблюдены, я выкладываю только те API, которые нам предоставили на GitHub'e или свои лично.

Предупреждение: это не тема для вопросов "как вставить их к себе?", поскольку если вы не умеете вставлять эти функции, то лучше сначала научиться их писать. Этот топик для экономии времени.

ResetAllAbilitiesCooldown(unit) - перезаряжает способности героя и все его предметы.

Код:
function ResetAllAbilitiesCooldown(table unit, bool refresh_items) 
	local abilities = unit:GetAbilityCount()
	for i = 0, abilities-1 do
		local ability = unit:GetAbilityByIndex(i)
		if ability and not ability:IsCooldownReady() then
			ability:EndCooldown()
		end
	end
	if unit:HasInventory() and refresh_items then
		for i = 0, 5 do
			local item = unit:GetItemInSlot(i)
			if item and not item:IsCooldownReady() then
			item:EndCooldown()
			end
		end
	end
end
[/quote]
Брат, всем пофиг на авторские права, у меня вон украли код абилки, воложили прямо на форуме и у МЕНЯ начали спрашивать как она работает
 
Последнее редактирование модератором:

Илья

Друзья CG
25 Сен 2015
2,348
41
Re: Полезные API для ваших кастомок (26.07.2016 обновлено)

Хаххаха, о каких авторских правах идет речь? Кто-то из русскоязычных моддеров патентует свою интеллектуальную собственность? :D

Тему плюсую, сам подобное задвигал, но только разными топиками. Я обычно готовые функции выкладываю с приставкой в теме "Кодим функции".
 
Последнее редактирование модератором:

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Re: Полезные API для ваших кастомок (26.07.2016 обновлено)

Хаххаха, о каких авторских правах идет речь? Кто-то из русскоязычных моддеров патентует свою интеллектуальную собственность? :D

Тему плюсую, сам подобное задвигал, но только разными топиками. Я обычно готовые функции выкладываю с приставкой в теме.
Авторские права не нужны.
Кто знает тот поймет
U can use all files and all code in ur projects. Fuck copyright bro ;)
Good luck.
 
Последнее редактирование модератором:

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Для тех кому DeepPrintTable мешает с его 'излишним' описанием структуры таблицы.
И для тех кто хочет задать вопрос 'как вывести ключи и значения из таблицы, я не понимать!'
Код:
function PrintKeys( keys )
	if not keys or type(keys) ~= "table" then print("PrintKeys error, expected table, got " .. type(keys) ); return; end

	for key, value in pairs(keys) do print(key, value) end
end
 
Последнее редактирование модератором:

Se7eN

Друзья CG
22 Ноя 2014
334
18
Код:
function RemoveItemByName(hero, item_name)
local hendl = ""
 for i=0,5 do
 hendl = hero:GetItemInSlot(i)
  if hendl and hendl:GetName() == item_name then
  hero:RemoveItem(hendl)
  end
 end
end
Удаляет у героя определенный предмет по названию. Если после RemoveItem поставить break, то удаляться будет всего 1 предмет. Если использовать функцию как в оригинале, то удалятся все похожие предметы. (Допустим в 4 слотах будут лежать зельки - все пропадут)
 
Последнее редактирование модератором:

Илья

Друзья CG
25 Сен 2015
2,348
41
Есть огромный косяк в этой функции - заряды и стаки, ты их не учитываешь.
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
[quote author=Se7eN link=topic=1006.msg6674#msg6674 date=1477650577]
Код:
function RemoveItemByName(hero, item_name)
local hendl = ""
  for i=0,5 do
  hendl = hero:GetItemInSlot(i)
    if hendl and hendl:GetName() == item_name then
    hero:RemoveItem(hendl)
    end
  end
end
Удаляет у героя определенный предмет по названию. Если после RemoveItem поставить break, то удаляться будет всего 1 предмет. Если использовать функцию как в оригинале, то удалятся все похожие предметы. (Допустим в 4 слотах будут лежать зельки - все пропадут)
[/quote]
Handle, КАРЛ, HANDLE.
Вместо удаления через RemoveItem используй UTIL_Remove, ибо первая не удаляет объект из игры, и он останется висеть мертвым грузом, и вот вообще не факт что мусорщик его удалит.
 
Последнее редактирование модератором:

Se7eN

Друзья CG
22 Ноя 2014
334
18
Скрипт работает отлично, претензии не приняты.
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Скрипт работает отлично, претензии не приняты.
180px-Indian.jpg
 
Последнее редактирование модератором:

ZLOY

Администратор
Команда форума
27 Июн 2016
953
182
UTIL_Remove когда-то вызывал проблемы с поднятием новых предметов, после удаления ним.
 

ZLOY

Администратор
Команда форума
27 Июн 2016
953
182
Ты не понял.
Если удалить из инвентаря предмет с помощью UTIL_Remove, то слот остается как-бы занятым и со временем герой не сможет поднимать предметы. Возможно это пофиксили уже.
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Ты не понял.
Если удалить из инвентаря предмет с помощью UTIL_Remove, то слот остается как-бы занятым и со временем герой не сможет поднимать предметы. Возможно это пофиксили уже.
А, ты про ограничение на количество шмоток.
Так прикол в том что этот счетчик шмоток привязан не к инвентарю, а к количеству предметом которыми игрок владеет, и вот RemoveItem уберет предмет из инвентаря, но оставит предмет в игре.
И видимо баг с тем что счетчик не убавлялся при удалении через UTIL_Remove пофиксили, ибо у меня уже давно он удаляет предметы без каких либо проблем.
А еще есть RemoveSelf(), тоже неплохая альтернатива.
 
Последнее редактирование модератором:

ZLOY

Администратор
Команда форума
27 Июн 2016
953
182
Самое интересное все функции удаляют предметы из игры одинаково. Только что сам протестировал.
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Самое интересное все функции удаляют предметы из игры одинаково. Только что сам протестировал.
Хм, странно. Я когда тестил RemoveItem он убирал лишь из инвентаря, а после я добавлял его же через AddItem.
ValveMagic
 
Последнее редактирование модератором:

gameizeazy

Активный
10 Июн 2016
116
0
...\dota_addons\trolodota\scripts\vscripts\addon_game_mode.lua: ...ta_addons\trolodota\scripts\vscripts\addon_game_mode.lua:26: ')' expected near 'unit'
Код:
--[[
Overthrow Game Mode
]]
function ResetAllAbilitiesCooldown(table unit, bool refresh_items)
	local abilities = unit:GetAbilityCount()
	for i = 0, abilities-1 do
		local ability = unit:GetAbilityByIndex(i)
		if ability and not ability:IsCooldownReady() then
			ability:EndCooldown()
		end
	end
	if unit:HasInventory() and refresh_items then
		for i = 0, 5 do
			local item = unit:GetItemInSlot(i)
			if item and not item:IsCooldownReady() then
			item:EndCooldown()
			end
		end
	end
_G.nNEUTRAL_TEAM = 4
_G.nCOUNTDOWNTIMER = 901
Ну и что ??? Неробит, даже пока не где не применял............................
 

CryDeS

Друзья CG
14 Июл 2015
1,210
11
Ну и что ??? Неробит, даже пока не где не применял............................
Судя по твоей догадливости и навыкам, у тебя ничего не выйдет.
Код:
function ResetAllAbilitiesCooldown(unit, refresh_items)
 
Последнее редактирование модератором:
Реклама: