Two Things - Library (Soul Gathering One) and A spell.

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

JASS:

library SoulsCreate initializer Init requires KT
//==========================================================================================
//=======================================SETUP=============================================
//==========================================================================================
    globals
//The ability Code for the Spell
        private constant integer ABILITY_CODE = 'A003'

//The Dummy ID For the spell
        private constant integer DUMMY_CODE = 'n000'
        
//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 = 'A001'
        
        
//The spell ID of the Dummyillusion ability
        private constant integer ILLUSIONID = 'A000'
        
        
//The dummy ID for the dummy unit that casts the spell
        private constant integer ILLUSION_DUMMY = 'h000'
        
        
//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?
 

emjlr3

Change can be a good thing
Reaction score
395
what debugging have you accomplished?
 

NeuroToxin

New Member
Reaction score
46
I've debugged everything, it runs everything, everything works, and I know where the errors are, thats not the problem, the problem is the fact that my caster doesn't get duplicated like it should, and I know how to fix the Circling error.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top