[Log in / Register]
| News | Chat | Pastebin | Donations | Tutorials | Rules | Forums |
| Maps | Skins | Icons | Models | Spells | Tools | Jass | Packs | Hosted Projects | Starcraft II Modding | Starcraft II Resources | Galaxy Wiki |
(Keeps Hive Alive)
Go Back   The Hive Workshop > Spells


Reply
 
Thread Tools
The Hive Workshop Spells:
LeBlanc the Deceiver Spellpack v1.2
Images
Highslide JS
Details
Uploaded:04:47, 30th Sep 2012
Last Updated:16:15, 4th Oct 2012
Keywords:LeBlanc, LeBlanc the Deciever, Deciever, League of Legends, LoL, RiotGames, Arcane, AoS, Aeon of Strife, Sigil of Silence, Distortion, Ethereal Chains
Type:Pack
Category:vJASS

LeBlanc the Deceiver Spellpack v1.2

by Lambdadelta (aka Siraraz and BlackRose)

Last updated: 13/10/2012

Introduction
This spellpack includes the champion, LeBlanc the Deceiver, from the League of Legends and her abilities: Sigil of Silence, Distortion, Ethereal Chains and Mimic. It does not include Mirror Image due to the complex nature of the illusion.
Notes
Don't mind the relatively dull visuals, I couldn't think of the best way to match the effects from League of Legends. There may be a few bugs here and there, I haven't tested it fully. Also, the way I managed Mimic's varying mana cost and cooldown was by triggering them. It would be horrendous to have 15 levels for the mimic-abilities. I also haven't fully commented everything and documented either. Feedback is appreciated.
Description of Spells
Sigil of Silence

LeBlanc projects an orb towards her target, dealing magic damage and marking the target for 3.5 seconds. If the target takes damage from one of LeBlanc's abilities, the mark will trigger, dealing magic damage and silencing the target for 2 seconds.
Distortion

LeBlanc rapidly dashes to a target location, dealing magic damage to units near the location. In the following 3 seconds, she can activate Distortion again to blink back to her starting location.
Ethereal Chains

LeBlanc flings illusionary chains in a line towards a target location. If it hits an enemy unit, it will deal initial magic damage and leash to it, slowing their movement speed by 25% while the leash remains. If the target remains leashed after 2 seconds, the target takes additional magic damage and is rooted for a few seconds.
Mimic

LeBlanc casts the previous spell she cast. The mimicked spell deals significantly increased damage.

Descriptions were taken directly from http://leagueoflegends.wikia.com/wik...c_the_Deceiver.
Coding Details
Requirements:
Script:

Constants

Jass:
library LeBlanc

globals
    public constant integer SIGIL_ID = 'A000'
    public constant integer DISTORTION_ID = 'A001'
    public constant integer ETHEREAL_CHAINS_ID = 'A002'
    public constant integer MIMIC_ID = 'A00G'
   
    public constant integer MIMIC_SIGIL_ID = 'A00A'
    public constant integer MIMIC_DISTORTION_ID = 'A00E'
    public constant integer MIMIC_ETHEREAL_CHAINS_ID = 'A00B'
endglobals

endlibrary

Sigil of Silence
Jass:
 scope SigilOfSilence initializer OnInit

//************************************************************************************************
//* Sigil of Silence
//* ----------------
//* - LeBlanc projects an orb towards her target, dealing magic damage
//*   and marking the target for 3.5 seconds. If the target takes damage
//*   from one of LeBlanc's abilities, the mark will trigger, dealing magic
//*   damage and silencing the target for 2 seconds.
//*
//* Requirements:
//* - SpellEffectEvent
//* - xecast
//* - xemissile
//* - xedamage
//* - Table
//* - ARGB
//*
//* - LeBlanc
//* - Mimic
//*
//* ----------------------------------------------------------------------------------------------
//*                                    CALIBRATION SECTION
//* ----------------------------------------------------------------------------------------------
    globals
        // ABILITY RAWCODES
        // ----------------
       
        // Sigil of Silence id and mimic'd Sigil
        private constant integer SIGIL_ID = LeBlanc_SIGIL_ID
        private constant integer MIMIC_SIGIL_ID = LeBlanc_MIMIC_SIGIL_ID
       
        // Silence id and order string
        private constant integer SILENCE_ID = 'A009'
        private constant string SILENCE_ORDER = "soulburn"
       
        // Mark of Sigil id and order string
        private constant integer MARK_ID = 'A008'
        private constant string MARK_ORDER = "cripple"
       
        // Mark of Sigil buff id
        private constant integer MARK_BUFF_ID = 'B001'
       
        // VISUALS
        // =---------------
       
        // The projectile model and the scale of it
        private constant string ORB_MODEL_PATH = "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdx"
        private constant real ORB_MODEL_SCALE = 2.50
       
        // Projectile colour and mimic'd orb version colour
        private constant integer ORB_COLOUR = 0xFFFFFFFF // RGB: 255/255/255
        private constant integer ORB_MIMIC_COLOUR = 0xFFC840FF // RGB: 200/64/255
       
        // STATS
        // =---------------
        private constant integer MAX_ABILITY_LEVEL = 5  // Maximum level of Sigil of Silence; must update for Mimic to work
        private constant real ORB_MOVESPEED = 1500.     // The movespeed of projectile in Warcraft units/second
        private constant real ORB_MOVE_ARC = 0.00       // The arc of projectile trajectory
        private constant real ORB_HEIGHT_OFFSET = 45.   // The distance of  projectile from the ground
    endglobals
   
    //
    // The primary damage dealt by the orb.
    // Default: 70/110/150/190/230
    private function SpellDamage takes integer level returns real
        return 40. * level + 30
    endfunction
   
    //
    // The secondary damage dealt when the mark
    // is activated by another spell.
    // Default: 20/40/60/80/100
    private function SecondaryDamage takes integer level returns real
        return 20. * level
    endfunction

    // Ignore this part:
    globals
        private xedamage DamageOptions // Used for damage purposes
        private Table MarkTable // Used for tracking units with the Mark of Sigil buff
    endglobals
   
    //
    // Setup the damage properties of the spell
    //
    private function SetupDamageOptions takes nothing returns nothing
        set DamageOptions.atype = ATTACK_TYPE_NORMAL
        set DamageOptions.dtype = DAMAGE_TYPE_FIRE
        set DamageOptions.wtype = null
        set DamageOptions.damageSelf = true
        set DamageOptions.damageAllies = true
        set DamageOptions.damageNeutral = true
    endfunction
//* ----------------------------------------------------------------------------------------------
//                                    END OF CALIBRATION
//* ----------------------------------------------------------------------------------------------
   
    // -------------------------------------------------------------------
    // Methods accessible from outside. These are used to active the mark
    // placed by Sigil of Silence. Putting
    //      SigilOfSilence_MarkBuff.fire(caster, target)
    // will check if the target has the buff and removes, silences and
    // damages if it does.
    //
    public struct MarkBuff extends array
        static method fire takes unit sourceUnit, unit targetUnit returns nothing
            local xecast xc
            local integer level
           
            // The targeted unit does have the Mark of Sigil
            if GetUnitAbilityLevel(targetUnit, MARK_BUFF_ID) > 0 then
                // Remove the mark and deal damage
                set level = MarkTable[GetHandleId(targetUnit)]
                call UnitRemoveAbility(targetUnit, MARK_BUFF_ID)
                set MarkTable[GetHandleId(targetUnit)] = 0
               
                if level > MAX_ABILITY_LEVEL then
                    set level = level - 5
                    call DamageOptions.damageTarget(sourceUnit, targetUnit, SecondaryDamage(level) * Mimic_DamageIncrease(GetUnitAbilityLevel(sourceUnit, LeBlanc_MIMIC_ID)))
                else
                    call DamageOptions.damageTarget(sourceUnit, targetUnit, SecondaryDamage(level))
                endif
               
                // Silence target
                set xc = xecast.createA()
                set xc.abilityid = SILENCE_ID
                set xc.orderstring = SILENCE_ORDER
                set xc.owningplayer = GetOwningPlayer(sourceUnit)
                set xc.level = level
                call xc.castOnTarget(targetUnit)
            endif
        endmethod
    endstruct
   
    // Uses xehomingmissile to provide the motion functionality
    private struct SigilMain extends xehomingmissile
   
        unit caster             // Caster of spell
        unit target             // Target unit of spell
        integer level           // Level of spell at time of cast
        player owningPlayer     // Owner of caster at time of cast
        boolean isMimic = false // Determines whether instance was a Mimic
       
        private method onDestroy takes nothing returns nothing
            set .caster = null
            set .target = null
        endmethod
       
        static method create takes unit caster, unit target returns thistype
            local real x = GetUnitX(caster)
            local real y = GetUnitY(caster)
            local real z = GetUnitFlyHeight(caster) + ORB_HEIGHT_OFFSET
            local SigilMain this = SigilMain.allocate(x, y, z, target, ORB_HEIGHT_OFFSET)
           
            set .caster = caster
            set .target = target
            set .owningPlayer = GetTriggerPlayer()
            set .level = GetUnitAbilityLevel(caster, SIGIL_ID)

            set .fxpath = ORB_MODEL_PATH
            set .scale = ORB_MODEL_SCALE
           
            // Comparing spell id to check whether instance is a Mimic-version
            if GetSpellAbilityId() == MIMIC_SIGIL_ID then
                set .isMimic = true
                call .ARGBrecolor(ORB_MIMIC_COLOUR)
            else
                call .ARGBrecolor(ORB_COLOUR)
            endif

            call .launch(ORB_MOVESPEED, ORB_MOVE_ARC)
            return this
        endmethod
       
        // make mimic sigil apply mark as well as silence
        private method onHit takes nothing returns nothing
            local xecast xc = xecast.createA()
           
            // Check for Mark of Sigil buff
            call MarkBuff.fire(.caster, .target)
           
            // Apply Mark of Sigil buff
            set xc.abilityid = MARK_ID
           
            set xc.orderstring = MARK_ORDER
            set xc.owningplayer = .owningPlayer
            set xc.level = .level
            call xc.castOnTarget(.target)

            // Apply extra Mimic-damage
            if .isMimic then
                set MarkTable[GetHandleId(.target)] = .level + MAX_ABILITY_LEVEL
                call DamageOptions.damageTarget(.caster, .target, SpellDamage(.level) * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID)))
            else
                call DamageOptions.damageTarget(.caster, .target, SpellDamage(.level))
                 set MarkTable[GetHandleId(.target)] = .level
            endif
        endmethod
   
    endstruct
   
    private function OnSpellEffect takes nothing returns nothing
        call SigilMain.create(GetTriggerUnit(), GetSpellTargetUnit())
    endfunction

    private function OnInit takes nothing returns nothing
        // Register when spell and mimic-spell goes into effect
        call RegisterSpellEffectEvent(SIGIL_ID, function OnSpellEffect)
        call RegisterSpellEffectEvent(MIMIC_SIGIL_ID, function OnSpellEffect)
       
        // Create mark table and damage properties
        set MarkTable = Table.create()
        set DamageOptions = xedamage.create()
       
        // Run damage setup
        call SetupDamageOptions()
    endfunction

endscope

Distortion

Jass:
scope Distortion initializer OnInit

    globals
        // OBJECT RAWCODES
        // ---------------
       
        // Distortion and mimic-Distortion id
        private constant integer DISTORTION_ID = LeBlanc_DISTORTION_ID
        private constant integer MIMIC_DISTORTION_ID = LeBlanc_MIMIC_DISTORTION_ID
       
        // Return and mimic-Return id
        private constant integer RETURN_ID = 'A004'
        private constant integer MIMIC_RETURN_ID = 'A005'
       
        // Dummy unit id
        private constant integer DUMMY_ID = 'e001'
       
        // STATS
        // ---------------
       
        // IMPORTANT: You must update this variable to match your Distortion otherwise it will not work.
        private constant integer MAX_ABILITY_LEVEL = 5
       
        // Speed in Warcraft III units/second that caster moves at
        private constant real DASH_SPEED = 1250.
       
        // Time allowed for caster to return back to starting point
        private constant real RETURN_DURATION = 3.0
       
        // Whether return is permitted (it will just be a charge-spell if false)
        private constant boolean ALLOW_RETURN = true
       
        // Radius for area of effect circle to deal damage
        private constant real DISTORTION_DAMAGE_RADIUS = 250.
       
        // VISUALS
        // ---------------
       
        // The distance in Warcraft III units between each afterimage of the caster
        private constant real AFTERIMAGE_SPACING = 60.
        private constant playercolor AFTERIMAGE_COLOUR = PLAYER_COLOR_ORANGE
        private constant playercolor MIMIC_AFTERIMAGE_COLOUR = PLAYER_COLOR_PURPLE
        private constant integer AFTERIMAGE_ALPHA = 128 // Slightly lucent
       
        // The effect created when an afterimage is created
        private constant string AFTERIMAGE_SPAWN_EFFECT = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdx"
        private constant string AFTERIMAGE_SPAWN_EFFECT_ATTACHMENT = "origin"
       
        // The model path for the marker of the starting point
        private constant string DISTORT_ORIGIN_MARKER = "Buildings\\Other\\CircleOfPower\\CircleOfPower.mdx"
       
        // Player colours of marker
        private constant playercolor MARKER_COLOUR = PLAYER_COLOR_YELLOW
        private constant playercolor MIMIC_MARKER_COLOUR = PLAYER_COLOR_PURPLE
       
        // Effect created at the end of the charge
        private constant string DISTORT_CHARGE_EFFECT = "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathMissile.mdx"
        private constant string DISTORT_CHARGE_EFFECT_ATTACHMENT = "chest"
       
        // Effect created at the start-market point on return point
        private constant string DISTORT_EFFECT_ORIGIN = "Abilities\\Spells\\Undead\\FreezingBreath\\FreezingBreathMissile.mdx"
       
        // Effect created at the position of caster before returning to start
        private constant string DISTORT_EFFECT_CASTER = "Objects\\Spawnmodels\\NightElf\\NEDeathSmall\\NEDeathSmall.mdx"
    endglobals
   
    private keyword Distortion
    globals
        private Table ReturnTable
        private Table MimicReturnTable
        private xedamage DamageOptions
    endglobals

    private function UnitFilter takes unit whichUnit, Distortion dat returns boolean
        return IsUnitEnemy(whichUnit, dat.owningPlayer) and not IsUnitType(whichUnit, UNIT_TYPE_DEAD) and /*
        */
not IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE)
    endfunction

    //
    // Damage dealt to units at the end of Distortion
    // Default: 85/125/165/205/245
    private function SpellDamage takes integer level returns real
        return 40. * level + 45.
    endfunction
   
    //
    // Setup the damage properties of the spell/visual effect
    //
    private function SetupDamageOptions takes nothing returns nothing
        set DamageOptions.atype = ATTACK_TYPE_NORMAL
        set DamageOptions.dtype = DAMAGE_TYPE_FIRE
        set DamageOptions.wtype = null
        call DamageOptions.useSpecialEffect("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdx","origin")
    endfunction

    private struct Distortion
        boolean isMimic
        boolean added
   
        unit caster
        player owningPlayer
        integer level
        integer ticks
       
        xefx returnfx = 0
        real returnX
        real returnY
        real targX
        real targY
       
        real angle
        real cos
        real sin
        real speed
        real dist = 0.
       
        timer timer
        group trail
       
        private static Distortion Temp
       
        private method destroy takes nothing returns nothing
            call ReleaseGroup(.trail)
            set .caster = null
            set .timer = null
            set .trail = null
            static if ALLOW_RETURN then
                call .returnfx.destroy()
            endif
        endmethod
       
        method returnStart takes nothing returns nothing
            call ForGroup(.trail, function Distortion.DestroyTrail)
       
            call DestroyEffect(AddSpecialEffect(DISTORT_EFFECT_CASTER, GetUnitX(.caster), GetUnitY(.caster)))
            call DestroyEffect(AddSpecialEffect(DISTORT_EFFECT_ORIGIN, .returnX, .returnY))
            if .isMimic then
                call UnitRemoveAbility(.caster, MIMIC_RETURN_ID)
                call SetUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID, .level)
            else
                call UnitRemoveAbility(.caster, RETURN_ID)  
                call SetUnitAbilityLevel(.caster, DISTORTION_ID, .level)
            endif
           
            call PauseUnit(.caster, true)
            call IssueImmediateOrder(.caster, "stop")
            call PauseUnit(.caster, false)
           
            call SetUnitX(.caster, .returnX)
            call SetUnitY(.caster, .returnY)
           
            call ReleaseTimer(.timer)
            call .destroy()
        endmethod
       
        private static method removeReturn takes nothing returns nothing
            local Distortion this = GetTimerData(GetExpiredTimer())
           
            if .isMimic then
                call UnitRemoveAbility(.caster, MIMIC_RETURN_ID)
                call SetUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID, .level)
            else
                call UnitRemoveAbility(.caster, RETURN_ID)  
                call SetUnitAbilityLevel(.caster, DISTORTION_ID, .level)
            endif
           
            call ReleaseTimer(GetExpiredTimer())
            call .destroy()
        endmethod
       
        private method endCharge takes nothing returns nothing
            local unit u
            local real dmg = SpellDamage(.level)
                       
            call ForGroup(.trail, function Distortion.DestroyTrail)
            call DestroyEffect(AddSpecialEffectTarget(DISTORT_CHARGE_EFFECT, .caster, DISTORT_CHARGE_EFFECT_ATTACHMENT))
            if .isMimic then
                set dmg = dmg * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID))
            endif
            call GroupEnumUnitsInArea(ENUM_GROUP, GetUnitX(.caster), GetUnitY(.caster), DISTORTION_DAMAGE_RADIUS, null)
            loop
                set u = FirstOfGroup(ENUM_GROUP)
                exitwhen u == null
                call GroupRemoveUnit(ENUM_GROUP, u)
                if UnitFilter(u, this) then
                    call SigilOfSilence_MarkBuff.fire(.caster, u)
                    call DamageOptions.damageTarget(.caster, u, dmg)
                endif
            endloop
        endmethod
               
        private static method DestroyTrail takes nothing returns nothing
            call RemoveUnit(GetEnumUnit())
        endmethod
               
        private static method timerCallback takes nothing returns nothing
            local Distortion this = GetTimerData(GetExpiredTimer())
            local unit u
            local real tx = GetUnitX(.caster) + .cos
            local real ty = GetUnitY(.caster) + .sin
            local real dx = .targX - tx
            local real dy = .targY - ty
           
            call SetUnitX(.caster, tx)
            call SetUnitY(.caster, ty)

            set .dist = .dist + .speed
            if .dist >= AFTERIMAGE_SPACING then
                set .dist = 0.
                set u = CreateUnit(.owningPlayer, DUMMY_ID, tx, ty, .angle)
                call SetUnitVertexColor(u, 255, 255, 255, AFTERIMAGE_ALPHA)
                if .isMimic then
                    call SetUnitColor(u, MIMIC_AFTERIMAGE_COLOUR)
                else
                    call SetUnitColor(u, AFTERIMAGE_COLOUR)
                endif
                call GroupAddUnit(.trail, u)
                call SetUnitX(u, tx)
                call SetUnitY(u, ty)
                call DestroyEffect(AddSpecialEffectTarget(AFTERIMAGE_SPAWN_EFFECT, u, AFTERIMAGE_SPAWN_EFFECT_ATTACHMENT))
            endif  
           
            static if ALLOW_RETURN then
                if not .added  then
                    set .added = true
                    if not .isMimic then
                        call UnitAddAbility(.caster, RETURN_ID)
                        call SetUnitAbilityLevel(.caster, DISTORTION_ID, MAX_ABILITY_LEVEL)
                        call IncUnitAbilityLevel(.caster, DISTORTION_ID)
                        set .returnfx.teamcolor = MARKER_COLOUR
                    else
                        call UnitAddAbility(.caster, MIMIC_RETURN_ID)
                        call SetUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID, MAX_ABILITY_LEVEL)
                        call IncUnitAbilityLevel(.caster, MIMIC_DISTORTION_ID)
                        set .returnfx.teamcolor = MIMIC_MARKER_COLOUR
                    endif
                endif
            endif
           
            if .ticks == 0 then
                call .endCharge()
                call PauseTimer(.timer)
                static if ALLOW_RETURN then
                    call TimerStart(.timer, RETURN_DURATION - (.ticks * XE_ANIMATION_PERIOD), false, function Distortion.removeReturn)
                endif
            else
                set .ticks = .ticks - 1
            endif

           
            set u = null
        endmethod
       
        static method create takes unit caster returns thistype
            local Distortion this = Distortion.allocate()
            local real dx
            local real dy
            local real dist
       
            // Setup spell variables
            set .caster = caster
            set .level = GetUnitAbilityLevel(caster, DISTORTION_ID)
            set .owningPlayer = GetTriggerPlayer()
           
            // Setup point coordinates
            set .returnX = GetUnitX(caster)
            set .returnY = GetUnitY(caster)
            set .targX = GetSpellTargetX()
            set .targY = GetSpellTargetY()
            set dx = .targX - .returnX
            set dy = .targY - .returnY
           
            // Do math to find distance/angle
            set dist = SquareRoot((dx * dx) + (dy * dy))
            set .angle = Atan2(dy, dx) * bj_RADTODEG
            set .speed = DASH_SPEED * XE_ANIMATION_PERIOD
            set .cos = .speed * Cos(.angle * bj_DEGTORAD)
            set .sin = .speed * Sin(.angle * bj_DEGTORAD)
            set .ticks = R2I(dist / .speed)
           
            set .isMimic = GetSpellAbilityId() == MIMIC_DISTORTION_ID
            static if ALLOW_RETURN then
                set .added = false
                set .returnfx = xefx.create(.returnX, .returnY, .angle)
                set .returnfx.fxpath = DISTORT_ORIGIN_MARKER
                set .returnfx.scale = 0.75
                call DestroyEffect(AddSpecialEffect(DISTORT_EFFECT_ORIGIN, .returnX, .returnY))
                if .isMimic then
                    set MimicReturnTable[GetHandleId(.caster)] = this
                else
                    set ReturnTable[GetHandleId(.caster)] = this
                endif
            endif
           
            set .trail = NewGroup()
            set .timer = NewTimerEx(this)
            call TimerStart(.timer, XE_ANIMATION_PERIOD, true, function Distortion.timerCallback)
            return this
        endmethod
       
    endstruct

    private function SpellEffectDistortion takes nothing returns nothing
        call Distortion.create(GetTriggerUnit())
    endfunction
   
    private function SpellEffectReturn takes nothing returns nothing
        if GetSpellAbilityId() == RETURN_ID then
            call Distortion(ReturnTable[GetHandleId(GetTriggerUnit())]).returnStart()
        elseif GetSpellAbilityId() == MIMIC_RETURN_ID then
            call Distortion(MimicReturnTable[GetHandleId(GetTriggerUnit())]).returnStart()
        endif
    endfunction
   
    private function OnInit takes nothing returns nothing
        // Register when spell and mimic-spell goes into effect
        call RegisterSpellEffectEvent(DISTORTION_ID, function SpellEffectDistortion)
        call RegisterSpellEffectEvent(MIMIC_DISTORTION_ID, function SpellEffectDistortion)
       
        // Register when return-Distortion is activated
        static if ALLOW_RETURN then
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST, function SpellEffectReturn)
       
            //call RegisterSpellEffectEvent(RETURN_ID, function SpellEffectReturn)
            //call RegisterSpellEffectEvent(MIMIC_RETURN_ID, function SpellEffectReturn)
            set ReturnTable = Table.create()
            set MimicReturnTable = Table.create()
        endif

        // Setup damage options
        set DamageOptions = xedamage.create()
        call SetupDamageOptions()
    endfunction

endscope

Ethereal Chains

Jass:
 scope EtherealChains initializer OnInit

/************************************************************************************************
 * Ethereal Chains
 * ---------------
 * - LeBlanc flings illusionary chains in a line towards a target location. If it hits an enemy
 *   unit, it will deal initial magic damage and leash to it, slowing their movement speed by 25%
 *   while the leash remains. If the target remains leashed after 2 seconds, the target takes
 *   additional magic damage and is rooted for a few seconds.
 *
 * Requirements:
 * - GroupUtils
 * - SimError
 * - SpellEffectEvent
 * - Table
 * - TimerUtils
 * - xecast, xedamage
 *
 * - LeBlanc
 * - Mimic
 *
 * ----------------------------------------------------------------------------------------------
 *                                    CALIBRATION SECTION
 * --------------------------------------------------------------------------------------------*/

    globals
        // ABILITY RAWCODES
        // ----------------
        // Ethereal Chains and mimic id
        private constant integer SPELL_ID = LeBlanc_ETHEREAL_CHAINS_ID
        private constant integer MIMIC_SPELL_ID = LeBlanc_MIMIC_ETHEREAL_CHAINS_ID
       
        // Slow effect placer id, buff id and order string
        private constant integer SLOW_ID = 'A00C'
        private constant integer SLOW_BUFF_ID = 'B002'
        private constant string SLOW_ORDERSTRING = "slow"
       
        // Snare effect placer id and order string id
        private constant integer SNARE_ID = 'A00F'
        private constant string SNARE_ORDERSTRING = "entanglingroots"
       
        // STATS
        // ----------------
       
        // Time of leash to remain until snare effect
        private constant real LEASH_DURATION = 2.
       
        // Speed leash extends outwards in Warcraft III units/second
        private constant real PROJECT_SPEED = 1250.
       
        // VISUALS
        // ----------------
       
/*      Lightning ID's (thanks to PurgeandFire111):

        Chain Lightning - Primary   = "CLPB"
        Chain Lightning - Secondary = "CLSB"
        Drain                       = "DRAB"
        Drain Life                  = "DRAL"
        Drain Mana                  = "DRAM"
        Finger of Death             = "AFOD"
        Forked Lightning            = "FORK"
        Healing Wave - Primary      = "HWPB"
        Healing Wave - Secondary    = "HWSB"
        Lightning Attack            = "CHIM"
        Magic Leash                 = "LEAS"
        Mana Burn                   = "MBUR"
        Mana Flare                  = "MFPB"
        Spirit Link                 = "SPLK"
*/

        private constant string LIGHTNING_CODE = "LEAS"
       
        // Colour values of lightning
        private constant real LIGHTNING_RED = 1.0
        private constant real LIGHTNING_GREEN = 1.0
        private constant real LIGHTNING_BLUE = 0.0
       
        // Colour values of lightning for Mimic-Ethereal Chains
        private constant real LIGHTNING_RED_MIMIC = 1.0
        private constant real LIGHTNING_GREEN_MIMIC = 0.0
        private constant real LIGHTNING_BLUE_MIMIC = 1.0
        private constant real LIGHTNING_HEIGHT_OFFSET = 60.
       
        private constant real LEASH_COLLISION_RADIUS = 128.
    endglobals
   
    // Ignore this section
    private keyword Chains
    globals
        private xedamage DamageOptions
        private Table LeashTable
    endglobals
   
    private function UnitFilter takes unit whichUnit, Chains whichChain returns boolean
        return IsUnitEnemy(whichUnit, whichChain.owningPlayer) and not IsUnitType(whichUnit, UNIT_TYPE_DEAD) and /*
        */
not IsUnitType(whichUnit, UNIT_TYPE_STRUCTURE)
    endfunction
   
    private constant function ChainMaxRange takes integer level returns real
        return 1000.
    endfunction
   
    // Initial damage dealt when the chain lands on a target.
    // Default: 40/65/90/115/140
    private constant function InitialDamage takes integer level returns real
        return 25. * level + 15
    endfunction
   
    // The damage dealt when the chain remains on a target for the required duration.
    // Default: 40/65/90/115/140
    private constant function DelayedDamage takes integer level returns real
        return 25. * level + 15
    endfunction
   
    //
    // Setup the damage properties of the spell
    //
    private function SetupDamageOptions takes nothing returns nothing
        set DamageOptions.atype = ATTACK_TYPE_NORMAL
        set DamageOptions.dtype = DAMAGE_TYPE_FIRE
        set DamageOptions.wtype = null
        set DamageOptions.damageAllies = true
        set DamageOptions.damageNeutral = true
    endfunction
   
//* ----------------------------------------------------------------------------------------------
//                                    END OF CALIBRATION
//* ----------------------------------------------------------------------------------------------
   
    private struct Chains
   
        // Standard spell-variables
        unit caster
        integer level
        player owningPlayer
        unit target
       
        // Determines whether instance is mimic or not
        boolean isMimic
       
        // Coordinates of leash end/target
        real x1
        real x2
        real y1
        real y2
        real z1
        real z2
       
        // Motion variables
        real speed
        real leashRange
        real dist
        real cos
        real sin
       
        // Leash effect
        lightning lightning
       
        // Motion timer
        timer timer
        real seconds
       
        // Slow/Snare caster
        xecast xc
       
        // Global location used to find the z-coordinate of a point
        private static location TempLocation = Location(0., 0.)
       
        private method destroy takes nothing returns nothing
            if .target != null then
                set LeashTable[GetHandleId(.target)] = LeashTable[GetHandleId(.target)] - 1
                call UnitRemoveAbility(.target, SLOW_BUFF_ID)
                set .target = null
            endif
           
            call DestroyLightning(.lightning)
            call ReleaseTimer(.timer)
           
            set .caster = null
            set .lightning = null
            set .timer = null
            call .deallocate()
        endmethod
       
        private static method timerCallback takes nothing returns nothing
            local Chains this = GetTimerData(GetExpiredTimer())
            local unit u
           
            set .x1 = GetUnitX(.caster)
            set .y1 = GetUnitY(.caster)
            call MoveLocation(Chains.TempLocation, .x1, .y1)
            set .z1 = GetUnitFlyHeight(.caster) + GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
           
            // Chain has a target
            if .target != null then
                set .x2 = GetUnitX(.target)
                set .y2 = GetUnitY(.target)
                call MoveLocation(Chains.TempLocation, .x2, .y2)
                set .z2 = GetUnitFlyHeight(.target) + GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
                set .dist = (.y2 - .y1) * (.y2 - .y1) + (.x2 - .x1) * (.x2 - .x1)
                               
                // Track time target is leashed
                set .seconds = .seconds + XE_ANIMATION_PERIOD
                if .seconds >= LEASH_DURATION then
                    // Remove slow when finished
                    if LeashTable[GetHandleId(.target)] == 1 then
                        call UnitRemoveAbility(.target, SLOW_BUFF_ID)
                    endif
                   
                    // Damage target unit
                    if .isMimic then
                        call DamageOptions.damageTarget(.caster, .target, DelayedDamage(.level) * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID)))
                    else
                        call DamageOptions.damageTarget(.caster, .target, DelayedDamage(.level))
                    endif
                   
                    // Check for Mark of Sigil buff
                    call SigilOfSilence_MarkBuff.fire(.caster, .target)
                   
                    // Snare target unit
                    set .xc.abilityid = SNARE_ID
                    set .xc.level = .level
                    set .xc.orderstring = SNARE_ORDERSTRING
                    set .xc.owningplayer = .owningPlayer
                    call .xc.castOnTarget(.target)
                    call .xc.destroy()
                    call .destroy()
                    return
                else
                // Continuously slow target unit
                    call .xc.castOnTarget(.target)
                endif
               
                // Destroy leash if target out of range or is dead
                if .dist >= .leashRange or IsUnitType(.target, UNIT_TYPE_DEAD) then
                    call .destroy()
                else
                // Update lightning coordinates between two units
                    call MoveLightningEx(.lightning, false, .x1, .y1, .z1, .x2, .y2, .z2)
                endif
            else // No target is found
               
                // Extend end of chain
                set .x2 = .x2 + .cos
                set .y2 = .y2 + .sin
                call MoveLocation(Chains.TempLocation, .x2, .y2)
                set .z2 = GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
               
                // Search for target at end of chain
                call GroupEnumUnitsInArea(ENUM_GROUP, .x2, .y2, LEASH_COLLISION_RADIUS, null)
                loop
                    set u = FirstOfGroup(ENUM_GROUP)
                    exitwhen u == null
                    call GroupRemoveUnit(ENUM_GROUP, u)
                   
                    // Check unit in group matches condition
                    if UnitFilter(u, this) then
                        set .target = u
                        set LeashTable[GetHandleId(.target)] = LeashTable[GetHandleId(.target)] + 1

                        // Deal initial chain damage
                        if .isMimic then
                            call DamageOptions.damageTarget(.caster, .target, InitialDamage(.level) * Mimic_DamageIncrease(GetUnitAbilityLevel(.caster, LeBlanc_MIMIC_ID)))
                        else
                            call DamageOptions.damageTarget(.caster, .target, InitialDamage(.level))
                        endif
                       
                        // Check for Mark of Sigil buff
                        call SigilOfSilence_MarkBuff.fire(.caster, .target)
                       
                        // Apply slow buff
                        set .xc = xecast.create()
                        set .xc.abilityid = SLOW_ID
                        set .xc.level = .level
                        set .xc.orderstring = SLOW_ORDERSTRING
                        set .xc.owningplayer = .owningPlayer
                        call .xc.castOnTarget(.target)
                        exitwhen true
                    endif
                endloop
               
                // Update lightning
                call MoveLightningEx(.lightning, false, .x1, .y1, .z1, .x2, .y2, .z2)
               
                // If chain extends fully then destroy instance
                set .dist = .dist - .speed
                if .dist <= 0. then
                    call .destroy()
                endif
            endif          
        endmethod
       
        static method create takes unit caster returns thistype
            local Chains this = Chains.allocate()
            local real angle
            local real dx
            local real dy
           
            // Setup spell variables
            set .caster = caster
            set .level = GetUnitAbilityLevel(caster, SPELL_ID)
            set .isMimic = GetSpellAbilityId() == MIMIC_SPELL_ID
            set .owningPlayer = GetOwningPlayer(caster)
            set .target = null

            // Assign coordinates of caster position and target position
            set .x1 = GetUnitX(caster)
            set .y1 = GetUnitY(caster)
            set .x2 = .x1
            set .y2 = .y1
               
            // Find angle between cast and target
            set dx = GetSpellTargetX() - .x1
            set dy = GetSpellTargetY() - .y1
            set angle = Atan2(dy, dx)
           
            // Find z-coordinate of caster position
            call MoveLocation(Chains.TempLocation, .x1, .y1)
            set .z1 = GetLocationZ(Chains.TempLocation) + LIGHTNING_HEIGHT_OFFSET
           
            // Create lightning and assign colour based on spell-instance property
            set .lightning = AddLightningEx(LIGHTNING_CODE, false, .x1, .y1, .z1, .x1, .y1, .z1)
            if .isMimic then
                call SetLightningColor(.lightning, LIGHTNING_RED_MIMIC, LIGHTNING_GREEN_MIMIC, LIGHTNING_BLUE_MIMIC, 1.0)
            else
                call SetLightningColor(.lightning, LIGHTNING_RED, LIGHTNING_GREEN, LIGHTNING_BLUE, 1.0)
            endif
           
            set .leashRange = ChainMaxRange(.level) * ChainMaxRange(.level)
            set .dist = ChainMaxRange(.level)
            set .speed = PROJECT_SPEED * XE_ANIMATION_PERIOD
            set .cos = .speed * Cos(angle)
            set .sin = .speed * Sin(angle)
           
            set .seconds = 0.

            set .timer = NewTimerEx(this)
            call TimerStart(.timer, XE_ANIMATION_PERIOD, true, function Chains.timerCallback)
           
            return this
        endmethod
   
    endstruct

    private function OnSpellEffect takes nothing returns nothing
        call Chains.create(GetTriggerUnit())
    endfunction
   
    private function OnInit takes nothing returns nothing
        // Register when spell and mimic-spell goes into effect
        call RegisterSpellEffectEvent(SPELL_ID, function OnSpellEffect)
        call RegisterSpellEffectEvent(MIMIC_SPELL_ID, function OnSpellEffect)
       
        // Create leash table and damage properties
        set LeashTable = Table.create()
        set DamageOptions = xedamage.create()
       
        // Run damage setup
        call SetupDamageOptions()
    endfunction

endscope

Mimic

Jass:
 library Mimic initializer OnInit requires LeBlanc, SpellEffectEvent, SimError

/************************************************************************************************
 * Mimic
 * -----
 * - LeBlanc casts the previous spell she cast. The mimicked spell
 *   deals significantly increased damage.
 *
 * Requirements:
 * - SpellEffectEvent
 * - SimError
 *
 * ----------------------------------------------------------------------------------------------
 *                                    CALIBRATION SECTION
 * --------------------------------------------------------------------------------------------*/


    // The percentage of damage that Mimic spells do.
    // Currently at 1.1/1.25/1.4 times the normal damage.
   
    // The functions is public as it is needed to be accessed from the other
    // spells' code in order to determine how much extra damage is dealt.
    public function DamageIncrease takes integer level returns real
        return 1. + 0.150 * level - 0.050
    endfunction
   
    // Mana cost of the Mimic spells (100/50/0)
    private function ManaCost takes integer level returns integer
        return 150 - 50 * level
    endfunction
   
    // Cooldown of the Mimic spells (40/32/24 seconds)
    private function Cooldown takes integer level returns real
        return 5.//48. - 8. * level
    endfunction
   
//* ----------------------------------------------------------------------------------------------
//                                    END OF CALIBRATION
//* ----------------------------------------------------------------------------------------------
   
    globals
        private hashtable MimicHT = InitHashtable() // Used to keep track of all data for Mimic
    endglobals
   
    private struct MimicData
        unit caster // Source of Mimic
        boolean cooldown // Determine whether spell is in cooldown or not
        integer level // Current level of Mimic
        integer currSkill // Current mimic-ability
        integer origSkill // Original ability id
        timer timer // Used for tracking cooldown of ability
       
        // Updates the current mimic-ability id based on the argument
        // which must be one of the three origianl abilities
        public method adjustSkillId takes integer spellId returns nothing
            set .origSkill = spellId
            if spellId == LeBlanc_SIGIL_ID then
                set .currSkill = LeBlanc_MIMIC_SIGIL_ID
            elseif spellId == LeBlanc_DISTORTION_ID then
                set .currSkill = LeBlanc_MIMIC_DISTORTION_ID
            elseif spellId == LeBlanc_ETHEREAL_CHAINS_ID then
                set .currSkill = LeBlanc_MIMIC_ETHEREAL_CHAINS_ID
            debug else
            debug    call BJDebugMsg(SCOPE_PREFIX + " - adjustSkillId method: The spell " + GetObjectName(spellId) + " was input as argument and is not recognised.")
            endif
        endmethod
       
        public static method create takes unit whichUnit returns thistype
            local MimicData this = MimicData.allocate()
           
            set .caster = whichUnit
            set .cooldown = false // Spell is not on cooldown initialy
            set .level = GetUnitAbilityLevel(whichUnit, LeBlanc_MIMIC_ID)
           
            // If the unit cast a spell before learning
            // then assign that spell as the mimic spell.
            if HaveSavedInteger(MimicHT, GetHandleId(.caster), StringHash("prevAbil")) then
                call .adjustSkillId(LoadInteger(MimicHT, GetHandleId(.caster), StringHash("prevAbil")))
            else
            // Else assign Sigil of Silence by default
                set .origSkill = LeBlanc_MIMIC_SIGIL_ID
                set .currSkill = LeBlanc_MIMIC_SIGIL_ID
            endif
           
            // Add mimic-ability to unit
            call UnitAddAbility(.caster, .currSkill)
           
            // Attach mimic data to unit
            call SaveInteger(MimicHT, GetHandleId(GetTriggerUnit()), StringHash("MimicData"), this)
           
            return 0
        endmethod
    endstruct

    // Fires when original spell is cast
    private function OnSpellEffect takes nothing returns nothing
        local MimicData dat
        local unit caster = GetTriggerUnit()
        local integer i = GetHandleId(caster)

        // If unit has Mimic data attached:
        if HaveSavedInteger(MimicHT, i, StringHash("MimicData")) then
            set dat = LoadInteger(MimicHT, i, StringHash("MimicData"))
            // Remove current mimic-ability and update current ability mimic'd
            call UnitRemoveAbility(dat.caster, dat.currSkill)
            set i = GetSpellAbilityId()
            call dat.adjustSkillId(i)
            call UnitAddAbility(dat.caster, dat.currSkill)
            call SetUnitAbilityLevel(dat.caster, dat.currSkill, GetUnitAbilityLevel(caster, i))
        else
        // Else merely store the previous ability on the unit so the Mimic ability when it is learnt
        // the first time updates to the correct previous ability
            call SaveInteger(MimicHT, GetHandleId(GetTriggerUnit()), StringHash("prevAbil"), GetSpellAbilityId())
        endif
        set caster = null
    endfunction
       
    // Fires when timer in MimicSpellEffect expires, resets cooldown of Mimic spell
    private function ResetCooldown takes nothing returns nothing
        local MimicData dat = GetTimerData(GetExpiredTimer())
        set dat.cooldown = false
        call ReleaseTimer(dat.timer)
    endfunction

    // Fires when a mimic-ability goes into effect (after cast-event)
    private function MimicSpellEffect takes nothing returns nothing
        local MimicData dat
        local unit caster = GetTriggerUnit()
        local integer hid = GetHandleId(caster)

        // If unit has Mimic data attached:
        if HaveSavedInteger(MimicHT, hid, StringHash("MimicData")) then
            // Set spell off into triggered-cooldown
            set dat = LoadInteger(MimicHT, hid, StringHash("MimicData"))
            set dat.cooldown = true
            set dat.timer = NewTimerEx(dat)
            call TimerStart(dat.timer, Cooldown(dat.level), false, function ResetCooldown)  

            // Deduct mana off caster
            call SetUnitState(caster, UNIT_STATE_MANA, GetUnitState(caster, UNIT_STATE_MANA) - ManaCost(dat.level))
        // Else the unit has no mimic data, meaning a unit has a mimic-ability for some odd reason
        debug else
        debug     call BJDebugMsg(SCOPE_PREFIX + " For some reason another unit has a mimiced ability.")
        endif
        set caster = null
    endfunction
       
    private function MimicSpellCastResponse takes nothing returns nothing
        local MimicData dat
        local unit caster = GetTriggerUnit()
        local integer hid = GetHandleId(caster)
       
        // If unit has Mimic data attached then:
        if HaveSavedInteger(MimicHT, hid, StringHash("MimicData")) then
            set dat = LoadInteger(MimicHT, hid, StringHash("MimicData"))

            // If spell is in triggered-cooldown then simulate error message and stop caster
            if dat.cooldown then
                call PauseUnit(caster, true)
                call SimError(GetTriggerPlayer(), "Mimic is in cooldown (" + I2S(R2I(TimerGetRemaining(dat.timer))) + " seconds left).")
                call IssueImmediateOrder(caster, "stop")
                call PauseUnit(caster, false)
            // Else caster has insufficient mana then simulate not enough mana error message and stop caster
            elseif GetUnitState(caster, UNIT_STATE_MANA) < ManaCost(dat.level) then
                call PauseUnit(caster, true)
                call SimError(GetTriggerPlayer(), "Not enough mana.")
                call IssueImmediateOrder(caster, "stop")
                call PauseUnit(caster, false)
            endif
           
        endif
        set caster = null
    endfunction
   
    // Fires when any of the mimic abilities are cast (before effect-event)
    private function MimicSpellCast takes nothing returns nothing
        local integer spellid = GetSpellAbilityId()
        if spellid == LeBlanc_MIMIC_SIGIL_ID or /*
        */
spellid == LeBlanc_MIMIC_DISTORTION_ID or /*
        */
spellid == LeBlanc_MIMIC_ETHEREAL_CHAINS_ID then
            call MimicSpellCastResponse()
        endif
    endfunction
   
    private function LearnMimicResponse takes nothing returns nothing
        local MimicData dat
        local unit learner = GetLearningUnit()
        local integer hid = GetHandleId(learner)
       
        // If learner unit already has Mimic then update level variable
        if HaveSavedInteger(MimicHT, hid, StringHash("MimicData")) then
            set dat = LoadInteger(MimicHT, hid, StringHash("MimicData"))
            set dat.level = GetUnitAbilityLevel(learner, LeBlanc_MIMIC_ID)
        else
        // Else create a new instance of Mimic struct for unit
            call MimicData.create(learner)
        endif
        set learner = null
    endfunction
   
    // Fired when Mimic is leveled up
    private function OnHeroSkill takes nothing returns nothing
        if GetLearnedSkill() == LeBlanc_MIMIC_ID then
            call LearnMimicResponse()
        endif
    endfunction
   
    private function OnInit takes nothing returns nothing
        // Register when Mimic is leveled
        call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_SKILL, function OnHeroSkill)
       
        // Register when any of the spells are cast (fires before effect event)
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST, function MimicSpellCast)
       
        // Register when original abilities are cast
        call RegisterSpellEffectEvent(LeBlanc_SIGIL_ID, function OnSpellEffect)
        call RegisterSpellEffectEvent(LeBlanc_DISTORTION_ID, function OnSpellEffect)
        call RegisterSpellEffectEvent(LeBlanc_ETHEREAL_CHAINS_ID, function OnSpellEffect)
       
        // Register when mimic abilities are cast
        call RegisterSpellEffectEvent(LeBlanc_MIMIC_SIGIL_ID, function MimicSpellEffect)
        call RegisterSpellEffectEvent(LeBlanc_MIMIC_DISTORTION_ID, function MimicSpellEffect)
        call RegisterSpellEffectEvent(LeBlanc_MIMIC_ETHEREAL_CHAINS_ID, function MimicSpellEffect)
    endfunction

endlibrary
Credits
I'd like to give credit to the following:
  • Magtheridon96 for RegisterPlayerUnitEvent and whose existing works acted as a guideline for how I should do things
  • Bribe for SpellEffectEvent
  • Rising_Dusk for GroupUtils
  • Vexorian, Cohadar and anyone who contribued to JassHelper
  • Cohadar again for the wc3Borderizor tool
  • Vexorian and Anitarf for the xe system
  • Vexorian for TimerUtils, Table, ARGB and SimError
  • PitzerMike and anyone else who contributed to JassNewGenPack
  • SFilip and anyone else who contributed to TESH
  • Halo7568/Krysho for his findings on the exploit with Channel and cooldown preservations.
    More info: http://www.wc3c.net/showpost.php?p=1029039&postcount=86
  • Riot Games for the icons and concept
  • leagueoflegends.wikia.com for the icons
  • _sPy for the holy missile model used in Sigil of Silence
  • Sellenisko for the Alexstrazsa model used for LeBlanc
Changelog
v1.2 (13/10/2012)
  • Fixed a bug with Distortion not ending if distance was zero

v1.1 (04/10/2012)
General
  • Added a message to the tooltip to inform users that cooldown is triggered and not shown
  • Nulled struct members at destruction of instance

Sigil of Silence
  • Targets Allowed change from any to air,ground,enemy,organic,neutral

Distortion
  • Fixed a bug in which the afterimages would not be removed
  • Return no longer uses hero cast time (it's now instant)

Mimic-Distortion
  • After-image playercolour is now configurable (purple by default)

v1.0 (30/09/2012)
  • Initial release
Rating - 5.00 (2 votes)
(Hover and click)
Moderator Comments
Recommended
17:19, 30th Sep 2012
Magtheridon96: Approved.
Awesome. The code is very clear and readable, and the documentation is excellent.

Also, lovely description!

This spell is approved and works properly.


Download LeBlanc v1.2.w3x
(409.19 KB, 818 Downloads)

Old 09-30-2012, 12:22 PM   #2 (permalink)
Registered User Cokemonkey11
Blessed Ranger
 
Cokemonkey11's Avatar
 
Join Date: May 2006
Posts: 2,706
Cokemonkey11 is a name known to all (629)
Mega Donor: This user has donated at least $200 to The Hive. 
I read your code and tested the map. Very nicely done. 5* etc.

Quote:
It does not include Mirror Image due to the complex nature of the illusion.
What is complex about it? If you take damage below a certain point you create an illusionary double - there should be a library for that. If not, you're welcome to take a look at the code I use for it:

Jass:
    public function addIllusion takes unit source, real duration returns unit
        local unit dummy=CreateUnit(GetOwningPlayer(source),DUMMYID,GetUnitX(source),GetUnitY(source),270)
        call UnitAddAbility(dummy,ILLUSIONID)
        call UnitAddAbility(dummy,'Aloc')
        call UnitApplyTimedLife(dummy,'BTLF',1.)
        call IssueTargetOrderById(dummy,ILLUSIONORDER,source)
        call UnitApplyTimedLife(lastCreatedIllusion,'BTLF',duration)
        return lastCreatedIllusion
    endfunction

(and then you need to register a condition on EVENT_PLAYER_UNIT_SUMMON to set lastCreatedIllusion)

Jass:
    private function illusionC takes nothing returns boolean
        local unit s=GetSummonedUnit()
        if IsUnitIllusion(s) then
            set lastCreatedIllusion=s
        endif
        set s=null
        return false
    endfunction
__________________

Blessed Ranger microrunnertd DummyUnitStack Orianna LeeSin StructuredDD Shield DamageType
Before writing a detailed response to a vague question, consider writing or referencing a tutorial - it takes just as much time, and improves the quality of the community.
Cokemonkey11 is offline   Reply With Quote
Old 09-30-2012, 12:32 PM   #3 (permalink)
Registered User Lambdadelta
User
 
Lambdadelta's Avatar
 
Join Date: Jul 2009
Posts: 910
Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)
It was more of the fact that the illusion "has 53 + (17 x level) less health" and the "illusion's autoattacks will proc on-hit effects (including damage)". The dynamic health and the illusions ability to do on-hit effects are what made me not want to do it. Having the illusion be summoned isn't difficult at all.

I could do the less health by just setting the health of the illusion to that value instead of adjusting the maximum health I suppose. Do illusions in Warcraft III do the on-hit effects naturally? Or do I have to trigger that aspect somehow?

Hmm, I may very well end up adding Mirror Image. Thanks for the feedback.
Lambdadelta is offline   Reply With Quote
Old 09-30-2012, 12:37 PM   #4 (permalink)
Registered User Cokemonkey11
Blessed Ranger
 
Cokemonkey11's Avatar
 
Join Date: May 2006
Posts: 2,706
Cokemonkey11 is a name known to all (629)
Mega Donor: This user has donated at least $200 to The Hive. 
Quote:
Originally Posted by Lambdadelta View Post
It was more of the fact that the illusion "has 53 + (17 x level) less health" and the "illusion's autoattacks will proc on-hit effects (including damage)". The dynamic health and the illusions ability to do on-hit effects are what made me not want to do it. Having the illusion be summoned isn't difficult at all.
Dynamic health is possible by abusing one bug - I think the common library that people were using to do it is called SetUnitMaxState, but it's not very efficient, and honestly, probably not worth using because of:

Quote:
I could do the less health by just setting the health of the illusion to that value instead of adjusting the maximum health I suppose. Do illusions in Warcraft III do the on-hit effects naturally? Or do I have to trigger that aspect somehow?
I think that might be your best bet in vanilla warcraft 3. Regarding on-hit effects, I think league of legends included that in the description for things like phage, because LeBlanc doesn't have any on-hit effects other than that, besides perhaps her chance to critically strike.
__________________

Blessed Ranger microrunnertd DummyUnitStack Orianna LeeSin StructuredDD Shield DamageType
Before writing a detailed response to a vague question, consider writing or referencing a tutorial - it takes just as much time, and improves the quality of the community.
Cokemonkey11 is offline   Reply With Quote
Old 09-30-2012, 01:05 PM   #5 (permalink)
Registered User gorillabull
uuh
 
gorillabull's Avatar
 
Join Date: Jul 2011
Posts: 1,406
gorillabull is just really nice (337)gorillabull is just really nice (337)gorillabull is just really nice (337)
5/5 incredible originality excellent coding
gorillabull is offline   Reply With Quote
Old 09-30-2012, 03:05 PM   #6 (permalink)
Registered User Magtheridon96
~ Join The Daily Peon ~
 
Magtheridon96's Avatar
 
Join Date: Dec 2008
Posts: 6,364
Magtheridon96 has a reputation beyond repute (2223)Magtheridon96 has a reputation beyond repute (2223)Magtheridon96 has a reputation beyond repute (2223)Magtheridon96 has a reputation beyond repute (2223)Magtheridon96 has a reputation beyond repute (2223)Magtheridon96 has a reputation beyond repute (2223)Magtheridon96 has a reputation beyond repute (2223)
Former Staff Member: This user used to be on the Hive Workshop staff. Merit Badge - Level 1: Great Assistant: Offers the best solution to other users, when all hope fades. Under the shell of assistance, lies a powerful knowledge in the fields. 
Congratulations for being the first person to upload something in vJASS without putting the code in Hidden tags to create an ugly font since I started working here.
__________________
Are you good at 2D animation? You wanna make $ good money $?
PM me.
Magtheridon96 is offline   Reply With Quote
Old 09-30-2012, 08:31 PM   #7 (permalink)
Registered User Luorax
Invasion in Duskwood
 
Luorax's Avatar
 
Join Date: Aug 2009
Posts: 1,355
Luorax is a glorious beacon of light (458)Luorax is a glorious beacon of light (458)Luorax is a glorious beacon of light (458)
Cool pack, once I was thinking of coding all her spells (and Morgana's spells too). One thing though: Distortion's secondary spell should be based on something that doesn't stop the unit's movement, for example Windwalk, Berserk, or Divine Shield. They're also instant (it would make the spells look even more like they do in LoL)

Another suggestion: to show Mimic's cooldown, you could add another of those instant-cast spells, and whenever a mimic'd spell is cast, you'd add it to the hero and order them to cast it. While it's in cooldown, you wouldn't be getting all those mimic spells icons, but this dummy ability will be show on the hero's command cart. It'd be more informal IMO, it took me like 4 minutes to notice the error message.

P.s: I hate xe :S It doesn't matter though as I'm not going to use any spells from public sources.
__________________
Luorax is offline   Reply With Quote
Old 10-01-2012, 03:17 AM   #8 (permalink)
Registered User Lambdadelta
User
 
Lambdadelta's Avatar
 
Join Date: Jul 2009
Posts: 910
Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)
Quote:
Originally Posted by Cokemonkey11 View Post
Dynamic health is possible by abusing one bug - I think the common library that people were using to do it is called SetUnitMaxState, but it's not very efficient, and honestly, probably not worth using because of:
I was thinking of a library that allows adjustment of maximum hp/mp, but I don't think it's worth it on such a small spell.

Quote:
Originally Posted by Cokemonkey11 View Post
I think that might be your best bet in vanilla warcraft 3. Regarding on-hit effects, I think league of legends included that in the description for things like phage, because LeBlanc doesn't have any on-hit effects other than that, besides perhaps her chance to critically strike.
I suppose I'll make Mirror Image as just summoning an illusion and causing her to go invisible for a little bit when she goes x% health.

Quote:
Originally Posted by gorillabull View Post
5/5 incredible originality excellent coding
Thank you :)

Quote:
Originally Posted by Magtheridon96 View Post
Congratulations for being the first person to upload something in vJASS without putting the code in Hidden tags to create an ugly font since I started working here.
Surely can't be the first one to do so? JASS tags have the option to expand/hide, why would there be a need to place them in hidden tags...?

Quote:
Originally Posted by Luorax View Post
Cool pack, once I was thinking of coding all her spells (and Morgana's spells too).
Thank you :) It'd be interesting to see a Morgana spellpack, you should do it :P I may make a Cassiopeia spellpack if I ever get around to it, although there'd be some limitations that I can't get around.

Quote:
Originally Posted by Luorax View Post
One thing though: Distortion's secondary spell should be based on something that doesn't stop the unit's movement, for example Windwalk, Berserk, or Divine Shield. They're also instant (it would make the spells look even more like they do in LoL)
That's a good point. I'll make this change in the next update. Thanks.

Quote:
Originally Posted by Luorax View Post
Another suggestion: to show Mimic's cooldown, you could add another of those instant-cast spells, and whenever a mimic'd spell is cast, you'd add it to the hero and order them to cast it. While it's in cooldown, you wouldn't be getting all those mimic spells icons, but this dummy ability will be show on the hero's command cart. It'd be more informal IMO, it took me like 4 minutes to notice the error message.
This may also work. I'll try playing around with this idea and see how it turns out.

Quote:
Originally Posted by Luorax View Post
P.s: I hate xe :S It doesn't matter though as I'm not going to use any spells from public sources.
I find xe quite useful as it does so much stuff for you. Plus I'm just lazy so that's why I used it :P That's fair enough, I don't tend to use spells from public sources as well.

Thank-you for the comments everyone :)
Lambdadelta is offline   Reply With Quote
Old 10-01-2012, 02:12 PM   #9 (permalink)
Registered User Robbepop
Mapper - vJasser
 
Robbepop's Avatar
 
Join Date: Mar 2008
Posts: 784
Robbepop is a jewel in the rough (178)
Hiho,

I was testing your abilities because I really like Le Blanc in League of Legends.^^
All in all the are good.
However, I've found some bugs.
1. Mirror Images while teleport spell (W) didn't disappear all the time properly but I don't know why or when.
2. The teleport speed on W is too slow and should be much faster.
3. The range of the E ability is too high imo.
4. You should make the trigger system like in LoL where you can for example target an area which is far away but your hero will still teleport to the direction with maximum distance to that target point. In your map the targeting system will move your hero to the spot so that the hero will always land properly at the target position - however, I think that the other system is much better - so why made it Riot just like that?
5. You are able to target yourself or allies with the Q ability.

That's all I think. =)

Robbepop
Robbepop is offline   Reply With Quote
Old 10-02-2012, 03:51 AM   #10 (permalink)
Registered User Lambdadelta
User
 
Lambdadelta's Avatar
 
Join Date: Jul 2009
Posts: 910
Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)
Quote:
Originally Posted by Robbepop View Post
Hiho,

I was testing your abilities because I really like Le Blanc in League of Legends.^^
All in all the are good.
However, I've found some bugs.
1. Mirror Images while teleport spell (W) didn't disappear all the time properly but I don't know why or when.
2. The teleport speed on W is too slow and should be much faster.
3. The range of the E ability is too high imo.
4. You should make the trigger system like in LoL where you can for example target an area which is far away but your hero will still teleport to the direction with maximum distance to that target point. In your map the targeting system will move your hero to the spot so that the hero will always land properly at the target position - however, I think that the other system is much better - so why made it Riot just like that?
5. You are able to target yourself or allies with the Q ability.

That's all I think. =)

Robbepop
  1. I'll look into this.
  2. I've changed that for the next update. It no longer uses cast point.
  3. All the figures are directly from LoL, so I guess 1000 range in Warcraft III is quite high compared to LoL. You can always change it.
  4. I think LoL does the same. It'll move the hero until it reaches in range. I think Distortion is the same? I might test it out later.
  5. You're quite the observant one :) I had it set to allies for testing purposes, I didn't want the enemies to attack. I could have just made my units Ethereal or something I suppose, oh well. You can always adjust this if you like.

Thanks for the feedback :)

Edit:
Quote:
Another suggestion: to show Mimic's cooldown, you could add another of those instant-cast spells, and whenever a mimic'd spell is cast, you'd add it to the hero and order them to cast it. While it's in cooldown, you wouldn't be getting all those mimic spells icons, but this dummy ability will be show on the hero's command cart. It'd be more informal IMO, it took me like 4 minutes to notice the error message.
This would be fine if it was just Sigil of Silence and Ethereal Chains, but Distortion will cause problems. If you don't return, I could just have a separate ability with a cooldown that's shorter, but if you return earlier the cooldown indicator should be longer to match. I think I may leave it as triggered cooldown for now.

Also, the image doesn't seem to be updating...

Last edited by Lambdadelta; 10-04-2012 at 05:02 AM.
Lambdadelta is offline   Reply With Quote
Old 10-08-2012, 12:55 AM   #11 (permalink)
Registered User FRENGERS
Level 3
 
FRENGERS's Avatar
 
Join Date: Aug 2012
Posts: 947
FRENGERS is a jewel in the rough (217)FRENGERS is a jewel in the rough (217)FRENGERS is a jewel in the rough (217)
Hiho,

Babe you are aMEWzing 5/5 +REPT ;) ;)

FRENGERS
__________________
Level 3/20
Each level need 100 Reputation....
FRENGERS is offline   Reply With Quote
Old 10-10-2012, 08:44 PM   #12 (permalink)
Registered User Maldruzard
Survivor
 
Maldruzard's Avatar
 
Join Date: Aug 2012
Posts: 155
Maldruzard has little to show at this moment (27)Maldruzard has little to show at this moment (27)Maldruzard has little to show at this moment (27)
If you cast Distortion and then cast Mimic Distortion in exactly the same place, LeBlanc shoots off across the map with no controllability, leaving a massive trail of ghost 'blancs :L Only a small bug that I stumbled across!

Other than that, some of the best spells I have even seen in Warcraft III, glad to see some LoL content here :) Planning on making an other packs for LoL characters?
__________________
Maldruzard is offline   Reply With Quote
Old 10-12-2012, 10:39 AM   #13 (permalink)
Registered User Lambdadelta
User
 
Lambdadelta's Avatar
 
Join Date: Jul 2009
Posts: 910
Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)Lambdadelta is a glorious beacon of light (425)
Quote:
Originally Posted by Maldruzard View Post
If you cast Distortion and then cast Mimic Distortion in exactly the same place, LeBlanc shoots off across the map with no controllability, leaving a massive trail of ghost 'blancs :L Only a small bug that I stumbled across!
Interesting. I'll investigate further. Thanks for reporting this.

Edit
I have fixed this now in v1.2.

Quote:
Originally Posted by Maldruzard View Post
Other than that, some of the best spells I have even seen in Warcraft III, glad to see some LoL content here :) Planning on making an other packs for LoL characters?
At the moment, I won't be. I don't know/like too many other champions from LoL (I hardly play it either) :P

Last edited by Lambdadelta; 10-13-2012 at 02:28 AM.
Lambdadelta is offline   Reply With Quote
Old 01-18-2013, 03:49 PM   #14 (permalink)
Registered User Cokemonkey11
Blessed Ranger
 
Cokemonkey11's Avatar
 
Join Date: May 2006
Posts: 2,706
Cokemonkey11 is a name known to all (629)
Mega Donor: This user has donated at least $200 to The Hive. 
Hey! You were my primary motivation for my latest project http://www.hiveworkshop.com/forums/s...llpack-228887/

Cheers mate,
__________________

Blessed Ranger microrunnertd DummyUnitStack Orianna LeeSin StructuredDD Shield DamageType
Before writing a detailed response to a vague question, consider writing or referencing a tutorial - it takes just as much time, and improves the quality of the community.
Cokemonkey11 is offline   Reply With Quote
Old 09-28-2013, 11:20 AM   #15 (permalink)
Registered User ~Nightmare
Join Idealists Challenge!
 
~Nightmare's Avatar
 
Join Date: Jan 2011
Posts: 434
~Nightmare is a jewel in the rough (260)~Nightmare is a jewel in the rough (260)~Nightmare is a jewel in the rough (260)~Nightmare is a jewel in the rough (260)
Now someone could now create a League of Legends map in Warcraft !

with the LoL spells on hive and LoL models Chaos!

GJ guys I appreciate your works!!
__________________
~Nightmare is online now   Reply With Quote
Reply

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


All times are GMT. The time now is 09:50 AM.




Powered by vBulletin
Copyright 2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.5.1 PL2
Copyright © Ralle