• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Chain Fire (V 1.00)

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.




Learn
Learn Chain Fire [Level 1]
Learn Chain Fire [Level 2]
Learn Chain Fire [Level 3]
Releases a fire stream at a target unit which jumps through multiple target dealing fire damage to each unit it hits.

Level 1 - 50 fire damage and 4 jumps with 15% damage reduction per jump.
Level 2 - 75 fire damage and 6 jumps with 10% damage reduction per jump.
Level 3 - 100 fire damage and 8 jumps with 5% damage reduction per jump.

Normal
Chain Fire - [Level 1]
Releases a fire stream at a target enemy unit which jumps through 4 units dealing to the first target 50 fire damage which is reduced by 15% for every next target it hits.

Chain Fire - [Level 2]
Releases a fire stream at a target enemy unit which jumps through 6 units dealing to the first target 75 fire damage which is reduced by 10% for every next target it hits.

Chain Fire - [Level 3]
Releases a fire stream at a target enemy unit which jumps through 8 units dealing to the first target 100 fire damage which is reduced by 5% for every next target it hits.





Lots of people who helped me






V 1.00
- Release 3:00 PM 3/29/2012


-PM me or post for any inquiry/problem(s)

-Credit when use.

The spell is pasted below.
JASS:
// Chain Fire Version 1.00

scope ChainFire initializer Init_ChainFire

globals
    private constant integer ABILTY_ID = 'A000'
    private constant integer CHFIRE_ID = 'c000'
    private constant timer   cf_timer  = CreateTimer()
    private constant real CF_TIMER_INTERVAL = 0.01
    private constant real    STEP_DIST = 16.00
    private constant real    CHEK_DIST = 24.00
    private constant real    IB        = 64.00
    private constant real    K         = 40.00
    private integer index = 0
    private integer array temp_dat

    private hashtable unit_flag = InitHashtable()
//====================================================================================================
//                                           User-edit data                                         //
//====================================================================================================
    // Targets:
        private constant boolean GROUND    = TRUE           // TRUE/FALSE  to  include/exclude  ground units
        private constant boolean FLYING    = TRUE           // TRUE/FALSE  to  include/exclude  flying units
        private constant boolean MECHANIC  = FALSE          // TRUE/FALSE  to  include/exclude  mechanical units
        private constant boolean STRUCTURE = FALSE          // TRUE/FALSE  to  include/exclude  structure units

    // Damage Variables:
        private constant boolean D_TABLE        = FALSE     // TRUE/FALSE to use Table/Formula
        // Table:
        private constant real array Damage                  // set the values in the function named "Spell_Data_Table"
        // Formula:
        private constant real D_CF     = 25.00              // changes 'ConstantFactor'
        private constant real D_LF     = 25.00              // changes 'AbilityLevelFactor'
        private constant real D_PLF    = 0                  // changes 'PrevLevelFactor'

    // Area of Effect Variables:
        private constant boolean R_TABLE        = FALSE     // TRUE/FALSE to use Table/Formula
        // Table:
        private constant real array Area                    // set the values in the function named "Spell_Data_Table"
        // Formula:
        private constant real R_CF     = 500.0              // changes 'ConstantFactor'
        private constant real R_LF     = 0                  // changes 'AbilityLevelFactor'
        private constant real R_PLF    = 0                  // changes 'PrevLevelFactor'

    // Damage Reduction per Jump Variables:
        private constant boolean N_TABLE        = TRUE      // TRUE/FALSE to use Table/Formula
        // Table:
        private constant real array DmgRed                  // set the values in the function named "Spell_Data_Table"
        // Formula:
        private constant real N_CF     =  0.2               // changes 'ConstantFactor'
        private constant real N_LF     = -0.05              // changes 'AbilityLevelFactor'
        private constant real N_PLF    =  0                 // changes 'PrevLevelFactor'

    // Jumps Variables:
        private constant boolean J_TABLE        = FALSE     // TRUE/FALSE to use Table/Formula
        // Table:
        private constant integer array Jumps                // set the values in the function named "Spell_Data_Table"
        // Formula:
        private constant integer J_CF  = 2                  // changes 'ConstantFactor'
        private constant integer J_LF  = 2                  // changes 'AbilityLevelFactor'
        private constant integer J_PLF = 0                  // changes 'PrevLevelFactor'

    private constant attacktype ATKTYPE = ATTACK_TYPE_NORMAL    // Spell Attack Type
    private constant damagetype DMGTYPE = DAMAGE_TYPE_FIRE      // Fire Damage Type
endglobals

    private function Spell_Data_Table takes nothing returns nothing
        // If your spell is more than 3 levels just add Damage[]/Range[]/Jumps[] under its appropriate place
        // Remember that if you don't add this line the Damage/Range/Jumps will be 0 for level 4+
        // Damage Table
        set  Damage[1] = 50.0
        set  Damage[2] = 100.0
        set  Damage[3] = 200.0
        // Range Table
        set    Area[1] = 500.0
        set    Area[2] = 500.0
        set    Area[3] = 500.0
        // Jumps Table
        set   Jumps[1] = 4
        set   Jumps[2] = 6
        set   Jumps[3] = 8
        // Damage Reduction Per Jump Table
        set  DmgRed[1] = 0.15
        set  DmgRed[2] = 0.10
        set  DmgRed[3] = 0.05

//====================================================================================================
//                                           End of User-edit data                                  //
//====================================================================================================
    endfunction

private function CF_Damage takes integer al returns real
    local real prevDmg
    if D_TABLE then
        return Damage[al]
    else
        if al == 1 then
            set prevDmg = 0
        else
            set prevDmg = CF_Damage(al - 1)
        endif
        return D_CF + D_LF * al + D_PLF * prevDmg
    endif
endfunction

private function CF_Area takes integer al returns real
    local real prevArea
    if R_TABLE then
        return Area[al]
    else
        if al == 1 then
            set prevArea = 0
        else
            set prevArea = CF_Area(al - 1)
        endif
        return R_CF + R_LF * al + R_PLF * prevArea
    endif
endfunction

private function CF_Jump takes integer al returns integer
    local integer prevJump
    if J_TABLE then
        return Jumps[al]
    else
        if al == 1 then
            set prevJump = 0
        else
            set prevJump = CF_Jump(al - 1)
        endif
        return J_CF + J_LF * al + J_PLF * prevJump
    endif
endfunction

private function CF_DamagReductionPerJump takes integer al returns real
    local real prevDr
    if N_TABLE then
        return DmgRed[al]
    else
        if al == 1 then
            set prevDr = 0
        else
            set prevDr = CF_DamagReductionPerJump(al - 1)
        endif
        return N_CF + N_LF * al + N_PLF * prevDr
    endif
endfunction

private function IsTargetAllowed takes unit u returns boolean

    if IsUnitType(u,UNIT_TYPE_MAGIC_IMMUNE)                  or/*
    */(not FLYING    and IsUnitType(u,UNIT_TYPE_FLYING))     or/*
    */(not GROUND    and IsUnitType(u,UNIT_TYPE_GROUND))     or/*
    */(not MECHANIC  and IsUnitType(u,UNIT_TYPE_MECHANICAL)) or/*
    */(not STRUCTURE and IsUnitType(u,UNIT_TYPE_STRUCTURE)) then
    return false
    endif

return true
endfunction

private function GetNearestUnit takes player owner, unit source, real radius, integer dat returns unit
    local group g = CreateGroup()
    local group temp_g = CreateGroup()
    local real locX = GetUnitX(source)
    local real locY = GetUnitY(source)
    local real dx
    local real dy
    local unit ref_u
    local unit any_u
    local unit temp_u
    local real dist_ref_u
    local real dist_any_u


    call GroupEnumUnitsInRange(temp_g,locX,locY,radius,null)
    //call GroupRemoveUnit(temp_g,source)

    loop
        set temp_u = FirstOfGroup(temp_g)
        exitwhen temp_u == null

        if temp_u != LoadUnitHandle(unit_flag,dat,GetHandleId(temp_u)) and/*
        */ not(IsUnitType(temp_u,UNIT_TYPE_DEAD))                      and/*
        */     IsUnitEnemy(temp_u,owner)                               and/*
        */     IsTargetAllowed(temp_u)                                 then
            call GroupAddUnit(g,temp_u)
        endif

        call GroupRemoveUnit(temp_g,temp_u)
    endloop
    call DestroyGroup(temp_g)

    set ref_u = FirstOfGroup(g)
    call GroupRemoveUnit(g,ref_u)

    loop
        set any_u = FirstOfGroup(g)
        exitwhen any_u == null
        set dx = GetUnitX(ref_u) - locX
        set dy = GetUnitY(ref_u) - locY
        set dist_ref_u = SquareRoot(dx*dx + dy*dy)
        set dx = GetUnitX(any_u) - locX
        set dy = GetUnitY(any_u) - locY
        set dist_any_u = SquareRoot(dx*dx + dy*dy)

        if dist_ref_u > dist_any_u then
            set ref_u = any_u
        endif

        call GroupRemoveUnit(g,any_u)

    endloop

    call DestroyGroup(g)
    return ref_u
endfunction


private struct data extends array
player  owner
unit    caster
unit    target
unit    cfd // Chain Fire Dummy
real    clx
real    cly
real    face
real    slope
real    stepK // Step Factor
//real    MaxZ
real    B
real    damage
real    areaeffect
real    dr // Damage Reduction (Per Jump)
integer jump

implement Alloc

static method MoveCF takes nothing returns nothing
    local thistype dat
    local integer i = 0
    local real x  // Current X of Chain Fire Missile
    local real y  // Current Y of Chain Fire Missile
    local real v
    local real z
    local real tx // Target X
    local real ty // Target Y
    local real tz // Target Z
    local real dx
    local real dy
    local real dv
    local real dz
    local real rd
    local real dist
    local unit u

    loop // cycle through instances
    exitwhen i >= index

        set dat = temp_dat[i]
        set u  = dat.target
        set x  = GetUnitX(dat.cfd)
        set y  = GetUnitY(dat.cfd)
        set tx = GetUnitX(u)
        set ty = GetUnitY(u)
        set tz = GetUnitFlyHeight(u) + K
        set dx = tx - x
        set dy = ty - y
        set dat.face = Atan2(dy,dx)
        set dist = SquareRoot(dx*dx + dy*dy)

        if dist < CHEK_DIST then
            call UnitDamageTarget(dat.caster, u,dat.damage, false, true, ATKTYPE, DMGTYPE, null)
            call SaveUnitHandle(unit_flag,dat,GetHandleId(u),u)
            set dat.jump = dat.jump - 1
            set dat.damage = dat.damage * ( 1 - dat.dr)
            if dat.jump <= 0 then // end the spell
                set index = index - 1
                set temp_dat[i] = temp_dat[index]
                set i = i - 1
                call KillUnit(dat.cfd)
                set dat.caster = null
                set dat.target = null
                set u = null
                call FlushChildHashtable( unit_flag , dat )

                if index == 0 then
                    call PauseTimer(cf_timer)
                endif

                call dat.deallocate()

            else        // seek the next target
                set dat.target = GetNearestUnit(dat.owner,u,dat.areaeffect,dat)
                if dat.target == null then
                    set dat.jump = 0
                    set index = index - 1
                    set temp_dat[i] = temp_dat[index]
                    set i = i - 1
                    call KillUnit(dat.cfd)
                    set dat.caster = null
                    set dat.target = null
                    set u = null
                    call FlushChildHashtable( unit_flag , dat )

                    if index == 0 then
                        call PauseTimer(cf_timer)
                    endif

                    call dat.deallocate()

                else
                    set dx = GetUnitX(dat.target) - tx
                    set dy = GetUnitY(dat.target) - ty
                    set dv = SquareRoot( dx*dx + dy*dy )
                    set dz = GetUnitFlyHeight(dat.target) - tz
                    set rd = SquareRoot( dv*dv + dz*dz )
                    set dat.clx = tx
                    set dat.cly = ty
                    set dat.B = tz
                    set dat.slope = dz / dv
                    set dat.stepK  = rd / dv
                    set dat.face = Atan2(dy,dx)
                    call SetUnitFacing(dat.cfd,dat.face * bj_RADTODEG)
                endif

            endif

        else
            //set x = x + STEP_DIST * Cos(dat.face)
            //set y = y + STEP_DIST * Sin(dat.face)
            set dx = x - dat.clx
            set dy = y - dat.cly
            set  v = SquareRoot( dx*dx + dy*dy )
            set  z = (dat.slope * v) + dat.B
            call SetUnitX(dat.cfd,x + STEP_DIST * Cos(dat.face) / dat.stepK)
            call SetUnitY(dat.cfd,y + STEP_DIST * Sin(dat.face) / dat.stepK)
            call SetUnitFlyHeight(dat.cfd,z,0.0)
        endif

    set i = i + 1
    endloop

endmethod

static method StartCF takes unit caster, unit target returns nothing
    local thistype dat = thistype.allocate()
    local integer al = GetUnitAbilityLevel(caster , ABILTY_ID)
    local real cx // Caster X
    local real cy // Caster Y
    local real cz // Caster Z
    local real tx // Target X
    local real ty // Target Y
    local real tz // Target Z
    local real dx
    local real dy
    local real dv
    local real dz
    local real rd // Real Distance

    set temp_dat[index] = dat
    set dat.caster      = caster
    set dat.target      = target
    set dat.owner       = GetOwningPlayer(caster)
    set cx              = GetUnitX(caster)
    set cy              = GetUnitY(caster)
    set dat.clx         = cx
    set dat.cly         = cy
    set dat.B           = IB
    set cz              = GetUnitFlyHeight(caster) + dat.B
    set tx              = GetUnitX(target)
    set ty              = GetUnitY(target)
    set tz              = GetUnitFlyHeight(target) + K
    set dx              = tx - cx
    set dy              = ty - cy
    set dz              = tz - cz
    set dv              = SquareRoot( dx*dx + dy*dy )
    set rd              = SquareRoot( dv*dv + dz*dz )
    set dat.slope       = dz / dv
    set dat.stepK       = rd / dv
    set dat.face        = Atan2(dy,dx)
    set dat.cfd         = CreateUnit(GetOwningPlayer(caster),CHFIRE_ID,cx,cy,dat.face*bj_RADTODEG)
    call SetUnitFlyHeight(dat.cfd,cz,0.0)
    call SetUnitPathing( dat.cfd, false )

    set dat.damage      = CF_Damage(al)
    set dat.areaeffect  = CF_Area(al)
    set dat.jump        = CF_Jump(al)
    set dat.dr          = CF_DamagReductionPerJump(al)
    //call BJDebugMsg(R2S(dat.dr))

    if index ==0 then
        call TimerStart(cf_timer,CF_TIMER_INTERVAL,true,function thistype.MoveCF)
    endif

set index = index + 1
endmethod

endstruct

private function CF_Actions takes nothing returns nothing

    if GetSpellAbilityId() == ABILTY_ID then
        call data.StartCF(GetTriggerUnit(),GetSpellTargetUnit())
    endif

endfunction

private function Init_ChainFire takes nothing returns nothing
local trigger t = CreateTrigger()

    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction(t,function CF_Actions)
    call Spell_Data_Table()

    //Preload the dummy units to reduce lag on first cast
    call RemoveUnit(CreateUnit(Player(12),CHFIRE_ID,0.,0.,0.))
    call RemoveUnit(CreateUnit(Player(12),CHFIRE_ID,0.,0.,0.))
endfunction

endscope

IMPORTANT: Needs JNGP for customizing it to your needs.

Keywords:
Chainfire, Chain, Fire, Bounce, Bouncing, Jump, Jumping
Contents

Chain Fire (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 6th Apr 2012 Bribe: You are leaking handle IDs. There is almost never a reason to create local groups. This is certainly not one of them. You just need 1 global group created once, maybe...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

6th Apr 2012
Bribe: You are leaking handle IDs.

There is almost never a reason to create local groups. This is certainly not one of them. You just need 1 global group created once, maybe 2 if you don't want to change your code too much.
 
1. Instead of FALSE and TRUE, you could use false and true.
Reasons:
- true and false make it faster.
- Someone could implement an empty Blizzard.j, so those globals wouldn't even exist :p

2.
JASS:
    call RemoveUnit(CreateUnit(Player(12),CHFIRE_ID,0.,0.,0.))
    call RemoveUnit(CreateUnit(Player(12),CHFIRE_ID,0.,0.,0.))

Doing it once would be fine bro :eek:

3. Registering trigger conditions and just returning false at the end of them is a much better solution because conditions are much faster than actions :D (a little above 2.5 times)
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
So basically you made chain lightning. Don't quite understand this one exactly, unless there is something special about the movement or more effects left out of the description.

No offense meant, but why are you frustrating my attempt to make a spell

Bribe said:
You are leaking handle IDs.

How do I get rid of them, aren't those IDs integers ?
 
Top