The following shows several examples of creating units or illusions in DotA 2 modding. This is with regards to server sided modding (custom games in DotA 2). It uses Lua as a language and requires some prior understanding of DotA 2 modding and Lua.
With exception to creating illusions, the code below shows creation of units in a synchronous manner. Take a careful look at the differences. In particular, when creating units, you set both SetControllableByPlayer and SetOwner. However, when creating illusions of heroes, you only set SetControllableByPlayer and SetPlayerID. This is very important as using SetOwner on a hero unit will cause some issues whereas non-hero entities does not have the method SetPlayerID.
Illusions of heroes should be done in an asynchronous manner. This is because the copying of items and abilities takes a longer execution time. Else, you will face latency issues while playing DotA 2. If you want to, you can make creation of both illusions and units asynchronous too.
Creating a unit
local vTargetPosition = self:GetCursorPosition()
local hTreant = CreateUnitByName( "npc_dota_furion_treant", vTargetPosition, true, self:GetCaster(), self:GetCaster():GetPlayerOwner(), self:GetCaster():GetTeamNumber() )
if hTreant ~= nil then
hTreant:SetControllableByPlayer( self:GetCaster():GetPlayerID(), false )
hTreant:SetOwner( self:GetCaster() )
end
Creating a unit with timed lifespan of 5 seconds
modifier_furion_force_of_nature_lua = class({})
function modifier_furion_force_of_nature_lua:OnDestroy()
if IsServer() then
self:GetParent():ForceKill( false )
end
end
--------------------------------------------------------------------------------
function modifier_furion_force_of_nature_lua:DeclareFunctions()
local funcs = {
MODIFIER_PROPERTY_LIFETIME_FRACTION
}
return funcs
end
--------------------------------------------------------------------------------
function modifier_furion_force_of_nature_lua:GetUnitLifetimeFraction( params )
return ( ( self:GetDieTime() - GameRules:GetGameTime() ) / self:GetDuration() )
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local vTargetPosition = self:GetCursorPosition()
local hTreant = CreateUnitByName( "npc_dota_furion_treant", vTargetPosition, true, self:GetCaster(), self:GetCaster():GetPlayerOwner(), self:GetCaster():GetTeamNumber() )
if hTreant ~= nil then
hTreant:SetControllableByPlayer( self:GetCaster():GetPlayerID(), false )
hTreant:SetOwner( self:GetCaster() )
local kv = {
duration = 5 -- Unit will live for 5 seconds
}
hTreant:AddNewModifier( self:GetCaster(), self, "modifier_furion_force_of_nature_lua", kv )
end
Creating an illusion of a hero (asynchronous)
local caster = self:GetCaster()
local unit_name = caster:GetUnitName()
local origin = caster:GetAbsOrigin() + RandomVector(100)
local modifyIllusion = function ( illusion )
illusion:SetControllableByPlayer( caster:GetPlayerID(), false )
illusion:SetPlayerID( caster:GetPlayerID() )
-- Set the unit as an illusion
-- modifier_illusion controls many illusion properties like +Green damage not adding to the unit damage, not being able to cast spells and the team-only blue particle
illusion:AddNewModifier(caster, self:GetAbility(), "modifier_illusion", { duration = 5, outgoing_damage = 0, incoming_damage = 0 })
-- Without MakeIllusion the unit counts as a hero, e.g. if it dies to neutrals it says killed by neutrals, it respawns, etc.
illusion:MakeIllusion()
-- Level Up the unit to the casters level
local casterLevel = self:GetCaster():GetLevel()
for i = 2, casterLevel do
illusion:HeroLevelUp(false)
end
-- Set the skill points to 0 and learn the skills of the caster
illusion:SetAbilityPoints(0)
local maxAbilities = caster:GetAbilityCount() - 1
for ability_id = 0, maxAbilities do
local ability = caster:GetAbilityByIndex(ability_id)
if ability then
local abilityLevel = ability:GetLevel()
if abilityLevel ~= 0 then
local illusionAbility = illusion:GetAbilityByIndex(ability_id)
if illusionAbility then
illusionAbility:SetLevel(abilityLevel)
else
-- Add ability
local abilityName = ability:GetAbilityName()
local newAbility = illusion:AddAbility(abilityName)
newAbility:SetLevel(abilityLevel)
end
end
end
end
-- Recreate the items of the caster
for itemSlot=0,5 do
local item = caster:GetItemInSlot(itemSlot)
if item ~= nil then
local itemName = item:GetName()
local newItem = CreateItem(itemName, illusion, illusion)
illusion:AddItem(newItem)
end
end
end
-- Create unit
CreateUnitByNameAsync(
unit_name, -- szUnitName
origin, -- vLocation,
true, -- bFindClearSpace,
caster, -- hNPCOwner,
caster:GetPlayerOwner(), -- hUnitOwner,
caster:GetTeamNumber(), -- iTeamNumber
modifyIllusion
)