NeuroToxin
New Member
- Reaction score
- 46
Okay, heres my library.
Being as friendly as the Soul-Keeper is, Souls are attracted to him. Whenever a unit dies within range of the Soul-Keeper, it will float around him, ready to be sacrificed to his need.
Level 1 - Maximum of 15 Souls
Level 2 - Maximum of 20 Souls
Level 3 - Maximum of 25 Souls
Level 4 - Maximum of 30 Souls
And my spell using that library
The Soul Master sends out his souls to a targeted location, when they reach said location, they explode, creating a portal for the Soul Master. The Soul Master then disappears through the portal, leaving an image of himself behind. The force of him disappearing deals area damage.
Level 1: Deals 75 damage in 100 AOE. Image deals 30% damage, takes 600%.
Level 2: Deals 150 damage in 150 AOE. Image deals 30% damage, takes 600%.
Level 3: Deals 225 damage in 200 AOE. Image deals 30% damage, takes 600%.
Level 4: Deals 300 damage in 250 AOE. Image deals 30% damage, takes 600%.
Images Last 60 Seconds
Range: Unlimited
SoulCost: 2 Souls per 200 range, and 2 for the Image.
The illusion doesn't work, I'm using the right OrderId I'm sure.
And
My dummy units don't follow my unit thats hid, which is a problem. Does hiding the unit remove its existence temporarily? and If so, how would I be able to counter that?
Being as friendly as the Soul-Keeper is, Souls are attracted to him. Whenever a unit dies within range of the Soul-Keeper, it will float around him, ready to be sacrificed to his need.
Level 1 - Maximum of 15 Souls
Level 2 - Maximum of 20 Souls
Level 3 - Maximum of 25 Souls
Level 4 - Maximum of 30 Souls
JASS:
library SoulsCreate initializer Init requires KT
//==========================================================================================
//=======================================SETUP=============================================
//==========================================================================================
globals
//The ability Code for the Spell
private constant integer ABILITY_CODE = 039;A003039;
//The Dummy ID For the spell
private constant integer DUMMY_CODE = 039;n000039;
//The speed of the circling (Note that 4 is actually a pretty average speed)
private constant real SPEED = 8
//The effect to be played on the corpses that are getting they're souls taken.
private constant string EFFECT_ON_CORPSE = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdx"
endglobals
//==========================================================================================
//=====================================ENDSETUP===========================================
//==========================================================================================
private function CIRCLE_RADIUS takes integer lvl returns real
return 150 + (lvl * 0.)
endfunction
//==========================================================================================
//Just an FYI, RADIUS, is the radius at which a soul can be acquired, CIRCLE_RADIUS, is the radius
//at which the souls will circle the caster.
//==========================================================================================
private function RADIUS takes integer lvl returns real
return 500 + (lvl * 100.)
endfunction
//==========================================================================================
private function MAXSOULS takes integer lvl returns real
return 15 + (lvl * 5.)
endfunction
//==========================================================================================
globals
group array CirclingUnits[30]
private integer CustomValue = 0
private group Casters = CreateGroup()
real array Count[30]
endglobals
//==========================================================================================
private function DeadUnits takes nothing returns boolean
if IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) then
call DestroyEffect( AddSpecialEffect( EFFECT_ON_CORPSE, GetUnitX(GetFilterUnit()), GetUnitY(GetFilterUnit())))
return true
endif
return false
endfunction
//==========================================================================================
private function GroupEnum takes group g, unit u, real x, real y, real radius returns group
call GroupEnumUnitsInRange(g, x, y, radius, Condition(function DeadUnits))
return g
endfunction
//==========================================================================================
private function AddtoCircle takes unit u, unit c returns nothing
if IsUnitInGroup(u, CirclingUnits[GetUnitUserData(c)]) == false then
call GroupAddUnit(CirclingUnits[GetUnitUserData(c)], u)
endif
endfunction
//==========================================================================================
struct Souls
unit Caster
unit Dummy
real angle
static boolean Circling = false
endstruct
//==========================================================================================
private function MovingSouls takes nothing returns boolean
local Souls s = KT_GetData()
local real dummyx = GetUnitX(s.Dummy)
local real dummyy = GetUnitY(s.Dummy)
local real casterx = GetUnitX(s.Caster)
local real castery = GetUnitY(s.Caster)
local real offsetx
local real offsety
local real dx = dummyx - casterx
local real dy = dummyy - castery
local real distance = SquareRoot(dx * dx + dy * dy)
local integer level = GetUnitAbilityLevel(s.Caster, ABILITY_CODE)
local real maxsouls = MAXSOULS(level)
local real circleradius = CIRCLE_RADIUS(level)
local boolean outsidecircle = (distance > circleradius)
local real angle
if Souls.Circling == true then
call s.destroy()
elseif outsidecircle and IsUnitInGroup(s.Dummy, CirclingUnits[GetUnitUserData(s.Caster)]) == false then
set angle = Atan2(castery - dummyy, casterx - dummyx)
set offsetx = dummyx + 20 * Cos(angle)
set offsety = dummyy + 20 * Sin(angle)
call SetUnitX(s.Dummy, offsetx)
call SetUnitY(s.Dummy, offsety)
call SetUnitFacing(s.Dummy, angle)
elseif not outsidecircle or IsUnitInGroup(s.Dummy, CirclingUnits[GetUnitUserData(s.Caster)]) == true then
set s.angle = s.angle + (SPEED * bj_DEGTORAD)
set angle = Atan2(castery - dummyy, casterx - dummyx)
set offsetx = casterx + circleradius * Cos(s.angle)
set offsety = castery + circleradius * Sin(s.angle)
call SetUnitX(s.Dummy, offsetx)
call SetUnitY(s.Dummy, offsety)
call SetUnitFacing(s.Dummy, angle + 90)
call AddtoCircle(s.Dummy, s.Caster)
endif
return false
endfunction
//==========================================================================================
private function UnitInGroup takes unit u returns nothing
if IsUnitInGroup(u, Casters) == false then
call GroupAddUnit(Casters, u)
endif
endfunction
//==========================================================================================
private function CreateStructs takes nothing returns nothing
local Souls s
local unit TUnit = GetTriggerUnit()
local unit DUnit = GetEnumUnit()
local real x1 = GetUnitX(TUnit)
local real x2 = GetUnitX(DUnit)
local real y1 = GetUnitY(TUnit)
local real y2 = GetUnitY(DUnit)
local real maxsouls = MAXSOULS(GetUnitAbilityLevel(TUnit, ABILITY_CODE))
if Count[GetUnitUserData(TUnit)] < maxsouls then
set s = Souls.create()
set s.Caster = TUnit
set s.angle = bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
set s.Dummy = CreateUnit(GetTriggerPlayer(), DUMMY_CODE, GetUnitX(DUnit), GetUnitY(DUnit), s.angle)
call SetUnitFacing(s.Dummy, s.angle)
call SetUnitFlyHeight(s.Dummy, GetRandomReal(50, 300), 50)
call RemoveUnit(DUnit)
set DUnit = null
set TUnit = null
set Count[GetUnitUserData(TUnit)] = Count[GetUnitUserData(TUnit)] + 1
call KT_Add(function MovingSouls, s, .035)
endif
endfunction
//==========================================================================================
private function SetCustomValue takes unit u returns nothing
if IsUnitInGroup(GetTriggerUnit(), Casters) == false then
call SetUnitUserData(u, CustomValue)
set CustomValue = CustomValue + 1
endif
endfunction
//==========================================================================================
private function OnCast takes nothing returns boolean
local group tempgroup
local integer level
local unit caster
local real maxsouls = MAXSOULS(GetUnitAbilityLevel(GetTriggerUnit(), ABILITY_CODE))
if GetSpellAbilityId() == ABILITY_CODE and Count[GetUnitUserData(GetTriggerUnit())] < maxsouls then
set caster = GetTriggerUnit()
set tempgroup = CreateGroup()
set level = GetUnitAbilityLevel(caster, ABILITY_CODE)
call SetCustomValue(caster)
call UnitInGroup(caster)
set tempgroup = GroupEnum(tempgroup, caster, GetUnitX(caster), GetUnitY(caster), RADIUS(level))
call ForGroup(tempgroup, function CreateStructs)
call DestroyGroup(tempgroup)
endif
set tempgroup = null
set caster = null
return false
endfunction
//==========================================================================================
private function Init takes nothing returns nothing
local integer index = 0
local trigger t = CreateTrigger( )
call TriggerAddCondition( t, Condition( function OnCast ) )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
loop
exitwhen index == 30
set CirclingUnits[index] = CreateGroup()
set index = index + 1
endloop
endfunction
endlibrary
And my spell using that library
The Soul Master sends out his souls to a targeted location, when they reach said location, they explode, creating a portal for the Soul Master. The Soul Master then disappears through the portal, leaving an image of himself behind. The force of him disappearing deals area damage.
Level 1: Deals 75 damage in 100 AOE. Image deals 30% damage, takes 600%.
Level 2: Deals 150 damage in 150 AOE. Image deals 30% damage, takes 600%.
Level 3: Deals 225 damage in 200 AOE. Image deals 30% damage, takes 600%.
Level 4: Deals 300 damage in 250 AOE. Image deals 30% damage, takes 600%.
Images Last 60 Seconds
Range: Unlimited
SoulCost: 2 Souls per 200 range, and 2 for the Image.
JASS:
scope SoulMirror initializer Init
globals
//The ability ID for the spell Soul Mirror
private constant integer SPELLID = 039;A001039;
//The spell ID of the Dummyillusion ability
private constant integer ILLUSIONID = 039;A000039;
//The dummy ID for the dummy unit that casts the spell
private constant integer ILLUSION_DUMMY = 039;h000039;
//The distance in which the SOULS_PER_DISTANCE are used. If you travel 750, it will only use one
//soul, it has to be greater than 1000 to use two +
private constant real DISTANCE = 1000
//The amount of souls used per X distance
private constant real SOULS_PER_DISTANCE = 2
//The increase in size of the dummy unit that is selected to carry out the task of the carry.
private constant real INCREASE_SIZE = 200
//The effect to be played at the end when the damage is being dealt.
private constant string EFFECT_ON_HIT = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
//The effect that is played when the caster leaves, along with the HIDE_EFFECT
private constant string LEAVING_EFFECT = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
//The effect played where the damage occurs
private constant string AOE_EFFECT = "Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl"
//The effect to distract the eye while the caster is hid.
private constant string HIDE_EFFECT = "Abilities\\Spells\\Other\\HowlOfTerror\\HowlCaster.mdl"
//The interval at which the timing system will operate
private constant real INTERVAL = 0.03
//The offset each Interval seconds.
private constant integer OFFSET = 25
//The unimportant constants, yet they still need to be here
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
endglobals
private function AOE takes integer lvl returns real
return 100 + (lvl * 50.)
endfunction
private function DAMAGE takes integer lvl returns real
return 75 + (lvl * 75.)
endfunction
globals
//Required for a filter function
player TriggerPlayer
endglobals
private function FilterFunc takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean bool1 = IsUnitType(u, UNIT_TYPE_DEAD) == false
local boolean bool2 = IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) == false
local boolean bool3 = IsUnitType(u, UNIT_TYPE_STRUCTURE) == false
local boolean bool4 = IsUnitAlly(u, TriggerPlayer) == false
return bool1 and bool2 and bool3 and bool4
endfunction
struct SoulMirror
unit Caster
real CasterX
real CasterY
real TargetX
real TargetY
unit Dummy
real DistanceToTarget
real angle
real Totalsouls
static integer structtype
endstruct
private function DamageUnits takes nothing returns nothing
local SoulMirror s = SoulMirror.structtype
local unit p = GetEnumUnit()
local real x = GetUnitX(p)
local real y = GetUnitY(p)
local integer level = GetUnitAbilityLevel(s.Caster, SPELLID)
local real damage = DAMAGE(level)
call UnitDamageTarget(s.Caster, p, damage, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
call DestroyEffect(AddSpecialEffect(EFFECT_ON_HIT, x, y))
set p = null
endfunction
private function MoveUnit takes nothing returns boolean
local SoulMirror s = KT_GetData()
local real DX = GetUnitX(s.Dummy)
local real DY = GetUnitY(s.Dummy)
local real DNewX = DX + OFFSET * Cos(bj_DEGTORAD * s.angle)
local real DNewY = DY + OFFSET * Sin(bj_DEGTORAD * s.angle)
local boolean DistCheck = (s.DistanceToTarget >= 50)
local integer level = GetUnitAbilityLevel(s.Caster, SPELLID)
local real areaofeffect = AOE(level)
local group tempgroup
//Checking distance between the points.
if DistCheck then
//If it's true, then we set the dummy position closer to the targeted spot
call SetUnitX(s.Dummy, DNewX)
call SetUnitY(s.Dummy, DNewY)
call DestroyEffect(AddSpecialEffect(LEAVING_EFFECT, DNewX, DNewY))
call SetUnitFacing(s.Dummy, s.angle)
set s.DistanceToTarget = s.DistanceToTarget - OFFSET
else
//If it's not true, then we create the effects and initialize the group.
//First, we make the group to check around the casters initial casting to damage them.
set TriggerPlayer = GetOwningPlayer(s.Caster)
set tempgroup = CreateGroup()
call GroupEnumUnitsInRange(tempgroup, s.CasterX, s.CasterY, areaofeffect, Condition(function FilterFunc))
if CountUnitsInGroup(tempgroup) > 0 then
//If there are any units around the initial spot, then we damage them, else we destroy the instance
//We also unhide the caster now, and create an effect to show the unhiding.
set SoulMirror.structtype = s
call ForGroup(tempgroup, function DamageUnits)
endif
call SetUnitX(s.Caster, s.TargetX)
call SetUnitY(s.Caster, s.TargetY)
call DestroyEffect(AddSpecialEffect(HIDE_EFFECT, GetUnitX(s.Caster), GetUnitY(s.Caster)))
//Then we check the target coordinates to damage the units there too. Nifty huh.
call DestroyGroup(tempgroup)
set tempgroup = CreateGroup()
call GroupEnumUnitsInRange(tempgroup, s.TargetX, s.TargetY, areaofeffect, Condition(function FilterFunc))
call ShowUnit(s.Caster, true)
if CountUnitsInGroup(tempgroup) > 0 then
//If there are any units around the initial spot, then we damage them, else we destroy the instance
//We also unhide the caster now, and create an effect to show the unhiding.
set SoulMirror.structtype = s
call ForGroup(tempgroup, function DamageUnits)
endif
call DestroyGroup(tempgroup)
call RemoveUnit(s.Dummy)
call s.destroy()
return true
endif
return false
endfunction
private function RemoveUnits takes nothing returns nothing
local unit p = GetEnumUnit()
call GroupRemoveUnit(CirclingUnits[GetUnitUserData(GetTriggerUnit())], p)
call RemoveUnit(p)
set p = null
endfunction
private function OnCast takes nothing returns boolean
local SoulMirror s
local boolean cond = (CountUnitsInGroup(CirclingUnits[GetUnitUserData(GetTriggerUnit())]) > 0)
local real X
local real Y
local integer count
local real DistX
local real DistY
local real Tempreal
local group tempgroup
//The unit (It's called G because the function is GetLastCreatedUnit())
local unit G
if GetSpellAbilityId() == SPELLID and cond then
set s = SoulMirror.create()
set s.Caster = GetTriggerUnit()
set s.TargetX = GetSpellTargetX()
set s.TargetY = GetSpellTargetY()
set X = GetUnitX(GetTriggerUnit())
set Y = GetUnitY(GetTriggerUnit())
set DistX = s.TargetX - X
set DistY = s.TargetY - Y
set Tempreal = SquareRoot(DistX * DistX + DistY * DistY)
set s.DistanceToTarget = Tempreal
set count = CountUnitsInGroup(CirclingUnits[GetUnitUserData(GetTriggerUnit())])
set s.Totalsouls = ((s.DistanceToTarget / DISTANCE) / SOULS_PER_DISTANCE)
//Setting the spell target coordinates and souls needed.
set s.Dummy = GroupPickRandomUnit(CirclingUnits[GetUnitUserData(s.Caster)])
set Count[GetUnitUserData(s.Caster)] = Count[GetUnitUserData(s.Caster)] - 1
call GroupRemoveUnit(CirclingUnits[GetUnitUserData(s.Caster)], s.Dummy)
set Y = GetUnitY(s.Dummy)
set X = GetUnitX(s.Dummy)
set s.CasterX = GetUnitX(s.Caster)
set s.CasterY = GetUnitY(s.Caster)
set s.angle = bj_RADTODEG * Atan2(s.TargetY - s.CasterY, s.TargetX - s.CasterX)
//Hide the caster and create an effect to make it look cool and trick the eye
//We also are making the illusion here
set G = CreateUnit(GetTriggerPlayer(), ILLUSION_DUMMY, s.CasterX, s.CasterY, 270)
call UnitAddAbility(G, ILLUSIONID)
call SetUnitAbilityLevel(G, ILLUSIONID, GetUnitAbilityLevel(s.Caster, SPELLID))
call IssueTargetOrderById(G, 852274, GetTriggerUnit())
call UnitRemoveAbility(G, ILLUSIONID)
call DestroyEffect(AddSpecialEffect(LEAVING_EFFECT, GetUnitX(s.Caster), GetUnitY(s.Caster)))
call DestroyEffect(AddSpecialEffect(HIDE_EFFECT, GetUnitX(s.Caster), GetUnitY(s.Caster)))
call ShowUnit(s.Caster, false)
//Picking, and destroying the struct in which the unit was associated with before
call SetUnitScale(s.Dummy, 300 * 0.01, 300 * 0.01, 300 * 0.01)
//Making the unit stick out a bit.
set Souls.Circling = true
if CountUnitsInGroup(CirclingUnits[GetUnitUserData(GetTriggerUnit())]) < s.Totalsouls then
set s.DistanceToTarget = s.DistanceToTarget - ((s.Totalsouls - count) * (DISTANCE / SOULS_PER_DISTANCE))
call ForGroup(CirclingUnits[GetUnitUserData(GetTriggerUnit())], function RemoveUnits)
set Count[GetUnitUserData(GetTriggerUnit())] = 0
else
set Count[GetUnitUserData(GetTriggerUnit())] = Count[GetUnitUserData(GetTriggerUnit())] - s.Totalsouls
set tempgroup = CreateGroup()
set tempgroup = GetRandomSubGroup(R2I(s.Totalsouls), CirclingUnits[GetUnitUserData(GetTriggerUnit())])
call ForGroup(tempgroup, function RemoveUnits)
endif
//Destroying the struct associated with before, the true creates a separate condition in the
//SoulAcquire trigger in the movement.
call KT_Add( function MoveUnit, s, INTERVAL)
endif
return false
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger t = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( t, Condition(function OnCast) )
endfunction
endscope
The illusion doesn't work, I'm using the right OrderId I'm sure.
And
My dummy units don't follow my unit thats hid, which is a problem. Does hiding the unit remove its existence temporarily? and If so, how would I be able to counter that?