• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Magic Missile spell

Status
Not open for further replies.
Level 2
Joined
Oct 26, 2014
Messages
13
JASS:
//check nonstructure, alive, and enemy for ug
function EnemyCheck takes nothing returns boolean
    if ( IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) then
    return false
    endif
    if (not ( IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())))) then
    return false
    endif
    if ( not (IsUnitAliveBJ(GetFilterUnit()))) then
    return false
    endif
    return true
endfunction

//actions
function TriggerAct takes nothing returns nothing
    local unit c
    local unit ta
    local location l1
    local location l2
    local player p
    local unit t2
    local unit t3
    local integer n
    local unit b1
    local unit b2
    local unit b3
    local unit b4
    local unit b5
    local unit b6
    local unit b7
    local group g
    local location l3
//declared variables
    if (not(GetSpellAbilityID() == 'A000')) then
    return
    endif
    set c = GetSpellAbilityUnit()
    set ta = GetSpellTargetUnit()
    set p = GetOwningPlayer(GetTriggerUnit())
    set l1 = GetUnitLoc(c)
    set l2 = GetUnitLoc(ta)
    set n = GetUnitAbilityLevelSwapped('A000', c)
    set g = GetUnitsInRangeOfLocMatching(250.00, l2, Condition(function EnemyCheck))
    set t2 = GroupPickRandomUnit(g)
    set t3 = GroupPickRandomUnit(g)
    call DestroyGroup(g)
    set g = null
    set l3 = PolarProjectionBJ(l1, 75.00, ( GetUnitFacing(c) + GetRandomReal(-45.00, 45.00) ))
//main variables set
//following creates dummy units to cast individual missiles
    call CreateNUnitsAtLocFacingLocBJ( 1, 'h000', p, l3, l2 )
    set b1 = GetLastCreatedUnit()
    set l3 = PolarProjectionBJ(l1, 75.00, ( GetUnitFacing(c) + GetRandomReal(-45.00, 45.00) ))
    call CreateNUnitsAtLocFacingLocBJ( 1, 'h000', p, l3, l2 )
    set b2 = GetLastCreatedUnit()
    set l3 = PolarProjectionBJ(l1, 75.00, ( GetUnitFacing(c) + GetRandomReal(-45.00, 45.00) ))
    call CreateNUnitsAtLocFacingLocBJ( 1, 'h000', p, l3, l2 )
    set b3 = GetLastCreatedUnit()
    set l3 = PolarProjectionBJ(l1, 75.00, ( GetUnitFacing(c) + GetRandomReal(-45.00, 45.00) ))
    call CreateNUnitsAtLocFacingLocBJ( 1, 'h000', p, l3, l2 )
    set b4 = GetLastCreatedUnit()
    set l3 = PolarProjectionBJ(l1, 75.00, ( GetUnitFacing(c) + GetRandomReal(-45.00, 45.00) ))
    call CreateNUnitsAtLocFacingLocBJ( 1, 'h000', p, l3, l2 )
    set b5 = GetLastCreatedUnit()
    set l3 = PolarProjectionBJ(l1, 75.00, ( GetUnitFacing(c) + GetRandomReal(-45.00, 45.00) ))
    call CreateNUnitsAtLocFacingLocBJ( 1, 'h000', p, l3, l2 )
    set b6 = GetLastCreatedUnit()
    set l3 = PolarProjectionBJ(l1, 75.00, ( GetUnitFacing(c) + GetRandomReal(-45.00, 45.00) ))
    call CreateNUnitsAtLocFacingLocBJ( 1, 'h000', p, l3, l2 )
    set b7 = GetLastCreatedUnit()
    call RemoveLocation(l3)
    set l3 = null
//following issues first 3 to cast
    call IssueTargetOrderBJ( b1, "thunderbolt", ta )
    call TriggerSleepAction( 0.10 )
    call IssueTargetOrderBJ( b2, "thunderbolt", t2 )
    call TriggerSleepAction( 0.10 )
    call IssueTargetOrderBJ( b3, "thunderbolt", t3 )
    call TriggerSleepAction( 0.10 )
//issues additional 2 to cast if spell is level 2
    if (n>=2) then
    call IssueTargetOrderBJ( b4, "thunderbolt", ta )
    call TriggerSleepAction( 0.10 )
    call IssueTargetOrderBJ( b5, "thunderbolt", t2 )
    call TriggerSleepAction( 0.10 )
    endif
//orders last 2 to cast if spell is level 3
    if (n==3) then
    call IssueTargetOrderBJ( b6, "thunderbolt", ta )
    call TriggerSleepAction( 0.10 )
    call IssueTargetOrderBJ( b7, "thunderbolt", t3 )
    endif
//wait to allow all orders to complete
    call TriggerSleepAction( 0.75 ) 
//removes dummies from game  
    call RemoveUnit( b1 )
    call RemoveUnit( b2 )
    call RemoveUnit( b3 )
    call RemoveUnit( b4 )
    call RemoveUnit( b5 )
    call RemoveUnit( b6 )
    call RemoveUnit( b7 )
//null and leakproofing
    set b1 = null
    set b2 = null
    set b3 = null
    set b4 = null
    set b5 = null
    set b6 = null
    set b7 = null
    set c = null
    set ta = null
    call RemoveLocation(l1)
    set l1 = null
    call RemoveLocation(l2)
    set l2 = null
    set t2 = null
    set t3 = null
endfunction

//condition
function Con takes nothing returns boolean
    return ( GetSpellAbilityId() == 'A000' )
endfunction

//initialize trigger and create local instance
function InitTrig_MagicMissile takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Con ) )
    call TriggerAddAction( t, function TriggerAct )
    set t = null
endfunction

That's the code for my magic missile spell, works exactly as planned in game (3 missiles if level 1, 5 if 2, 7 if 3, selects targets semi-randomly.), just wondering if someone with more experience with jass can give me a couple pointers on streamlining it, and look it over for leaks?
 
Last edited:
Idk if it leaks atm, but...

1) Replace the BJs with natives.
2) Combine trigger action and trigger condition. Just put the actions into the condition function.
3) Store responses into a variable, if you use it twice or more often. (example: "GetUnitFacing(c)" should be stored into a real variable)
4) Watch your indention: (if statements)
JASS:
if (condition) then
action1
// bad
action2
endif

if (condition) then
    action1
    // good (more readable)
    action2
endif


It is not very readable at the moment. Do you really need so many variables? Try to minimize it. Try to use loops to make code more compact.
 
Level 29
Joined
Mar 10, 2009
Messages
5,016
This >>> if (not(GetSpellAbilityID() == 'A000')) then, is really useless coz the spell will not fire if the condition is not met...

Locations should be replaced by coordinates...

Use loops for your creation of units, 1 local unit is enough...

TriggerSleepAction is bad for jass coz a function can run for itself when fired then you code in 'real' jass, use timers instead...

You can use this native function and put it on your map header;
JASS:
native UnitAlive takes unit u returns boolean

therefore:
JASS:
function EnemyCheck takes nothing returns boolean
    return UnitAlive(GetFilterUnit()) and not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())
endfunction
 
Level 2
Joined
Oct 26, 2014
Messages
13
I've been reading a ton of different tutorials today. Going through my 'Elementalist' spells and cleaning them up, and converting to proper JASS. Having trouble converting my global heavy Thunder Blossoms spell into a working JASS form, though...struggling with timers and how to use them properly.
 
Level 2
Joined
Oct 26, 2014
Messages
13
So, I've made a mess of this, here is where I'm at now. I'm not using hashtables correctly, I presume. The spell got a little more complex because instead of spawning the missile caster dummies right at the caster, it now creates a line up to seven of them perpendicular to the caster's facing, 100.0 in front of him.

So, question, how do I fix the usage of hashtables in this? I thought they made sense to me, but I guess not. Or maybe I have parent/child mixed up in my head. I don't know, right now. Honestly, haven't been able to sleep for about 2 days and this stuff is starting to not make sense at all to me. I'll try to understand any reply though.

JASS:
function EnemyChecker takes nothing returns boolean
    return (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0) and not (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) and (IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())))
endfunction

function PickTargets takes nothing returns nothing
    local group g
    local location loc
    local unit u
call DisplayTextToForce( GetPlayersAll(), "Pick Targets Block" )
    set loc = GetUnitLoc(GetSpellTargetUnit())
    set g = GetUnitsInRangeOfLocMatching(250.00, loc, Condition(function EnemyChecker))
    set u = GroupPickRandomUnit(g)
    call SaveUnitHandle(udg_MM, 9, 9, u)
    call SaveUnitHandle(udg_MM, 12, 12, u)
    set u = GroupPickRandomUnit(g)
    call SaveUnitHandle(udg_MM, 10, 10, u)
    call SaveUnitHandle(udg_MM, 14, 14, u)
    call RemoveLocation(loc)
    call DestroyGroup(g)
    set loc = null
    set g = null
    set u = null
endfunction

function SpawnCasters takes nothing returns nothing
    local real cx
    local real cy
    local real sx
    local real sy
    local real cface
    local real face
    local real fx
    local real fy
    local real d
    local integer i
    local unit u
call DisplayTextToForce( GetPlayersAll(), "Caster Spawn Fired" )
    set i = LoadInteger(udg_MM,0,3)
    set cx = GetUnitX(GetTriggerUnit())
    set cy = GetUnitY(GetTriggerUnit())
    set cface = GetUnitFacing(GetTriggerUnit())
    if(i==1)or(i==3)or(i==5)or(i==7) then
        set d = SquareRoot((10000)+(625*i*i))
        set face = cface+Acos(100/d)
        set fx = (cx+(d*Cos(face*bj_DEGTORAD)))
        set fy = (cy+(d*Sin(face*bj_DEGTORAD)))
        call CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h000', fx, fy, cface)
        set u = GetLastCreatedUnit()
        call SaveUnitHandle(udg_MM,i,i,u)
    endif
    if(i==2)or(i==4)or(i==6) then
        set d = SquareRoot((10000)+(((625*i*i)-(1250*i))+625))
        set face = cface-Acos(100/d)
        set fx = (cx+(d*Cos(face*bj_DEGTORAD)))
        set fy = (cy+(d*Sin(face*bj_DEGTORAD)))
        call CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h000', fx, fy, cface)
        set u = GetLastCreatedUnit()
        call SaveUnitHandle(udg_MM,i,i,u)
    endif
    set u=null
    set i=i+1
    call SaveInteger(udg_MM,0,3,i)
endfunction

function KillCast takes nothing returns nothing
    local unit c
    local integer i
call DisplayTextToForce( GetPlayersAll(), "KillCast Block Fired" )
    set i=LoadInteger(udg_MM,0,2)
    set c=LoadUnitHandle(udg_MM,i,i)
    call RemoveUnit(c)
    set c=null
    set i=i+1
    call SaveInteger(udg_MM,0,2,i)
endfunction 

function CastMis takes nothing returns nothing
    local integer m
    local integer c
    local unit a
    local unit t
call DisplayTextToForce( GetPlayersAll(), "Fired CastMis Block" )
    set m=LoadInteger(udg_MM,0,1)
    set c=LoadInteger(udg_MM,0,2)
    if (c<=m) then
        set a=LoadUnitHandle(udg_MM,c,c)
        set t=LoadUnitHandle(udg_MM,(c+7),(c+7))
        call IssueTargetOrder(a, "thunderbolt", t)
        set a=null
        set t=null
    endif
    set c=c+1
    call SaveInteger(udg_MM,0,1,m)
    call SaveInteger(udg_MM,0,2,c)
endfunction

function Timers takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local integer i
    local integer s
call DisplayTextToForce( GetPlayersAll(), "Fired Timers Block" )
    set i = LoadInteger(udg_MM, 0, 2)
    set s = LoadInteger(udg_MM, 0, 3)
    if s<=7 then
        call SaveInteger(udg_MM,0,3,s)
        call SaveInteger(udg_MM,0,2,i)
        call SpawnCasters()
        call TimerStart(t,0.05,false,function Timers)
    else
        if i<=7 then
            call SaveInteger(udg_MM,0,2,i)
            call CastMis()
            call TimerStart(t,0.05,false,function Timers)
        else
            if i<=14 then
                call SaveInteger(udg_MM,0,2,i)
                call TimerStart(t,0.02,false,function Timers)
                call KillCast()
            else
                call PauseTimer(t)
                call DestroyTimer(t)
                set i=0
                loop 
                exitwhen i==15
                    call FlushChildHashtable(udg_MM,i)
                    set i=i+1
                endloop
                call FlushParentHashtable(udg_MM)
                return
            endif
        endif
    endif
endfunction

function Con takes nothing returns nothing
    local timer t
    local integer l
    local integer m
    local unit u
    local integer a = 1
    local integer b = 1
    if ( GetSpellAbilityId() == 'A000' ) then
        call DisplayTextToForce( GetPlayersAll(), "Fired Con Block" )
        set t = CreateTimer()
        set l = GetUnitAbilityLevelSwapped('A000', GetTriggerUnit())
        set m = (l*2)+1
        set u = GetSpellTargetUnit()
        call SaveUnitHandle(udg_MM, 8, 8, u)
        call SaveUnitHandle(udg_MM, 11, 11, u)
        call SaveUnitHandle(udg_MM, 13, 13, u)
        call SaveInteger(udg_MM, 0, 1,m)
        call SaveInteger(udg_MM, 0, 2,a)
        call SaveInteger(udg_MM, 0, 3,b)
        call PickTargets()
        call TimerStart(t,0.,false,function Timers)
        set t = null
        set u = null
    endif
endfunction

//===============================================================

function InitTrig_MagicMissilePrep takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t, function Con )
    set t = null
endfunction
 
Level 12
Joined
Oct 16, 2010
Messages
680
JASS:
call CreateUnit(GetOwningPlayer(GetTriggerUnit()), 'h000', fx, fy, cface)
        set u = GetLastCreatedUnit()

fail. look up the BJ version of create unit in the functions list. it works as the same but manually sets
bj_lastCreatedUnit = CreateUnit(........
GetLastCreatedUnit() returns bj_lastCreatedUnit

so if u use CreateUnit() then bj_lastCreatedUnit won't save it

proper use:
set u = CreateUnit(........

also save everything that is used twice or more like GetTriggerUnit()

for debugging use BJDebugMsg() its faster and easyer to use

GetUnitAbilityLevelSwapped('A000', GetTriggerUnit())
pls.. replace with native
GetUnitAbilityLevel()

set m = (1*2)+1 ? really? if it is constant than just make it a constant global

set g = GetUnitsInRangeOfLocMatching()--->set g = GroupEnumUnitsInRange()


dig yourself in some hashtable and other jass tutorials
your use of keys doesen't makes any sence
 
Level 2
Joined
Oct 26, 2014
Messages
13
Update on spell: :D

Here's the two triggers related to the spell, now. First is for levels 1-3, second is for it's ultimate variety, level 4.

JASS:
function Wrap takes nothing returns nothing
    call FlushChildHashtable(udg_MM,StringHash("u"))
    call FlushChildHashtable(udg_MM,StringHash("l"))
    call FlushParentHashtable(udg_MM)
endfunction

function KillCast takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local integer i
    if (TimerGetRemaining(t)==0.0) then
        set i=1
        loop
        exitwhen i>7
            call RemoveUnit(LoadUnitHandle(udg_MM,StringHash("u"),StringHash("c"+I2S(i))))
            set i=i+1
        endloop
        call PauseTimer(t)
        call DestroyTimer(t)
        set t=null
        call Wrap()
    endif
endfunction

function CastMis takes nothing returns nothing
    local integer m
    local integer c
    local unit array a
    local unit array t
    local string s
    local timer x=GetExpiredTimer()
    if (TimerGetRemaining(x)!=0.0) then
    return
    endif
    set m=LoadInteger(udg_MM,StringHash("l"),StringHash("m"))
    set c=1
    loop
    exitwhen c>7
        set s=I2S(c)
        set a[c]=LoadUnitHandle(udg_MM,StringHash("u"),StringHash(("c"+s)))
        set t[c]=LoadUnitHandle(udg_MM,StringHash("u"),StringHash(("t"+s)))
        set c=c+1
    endloop
    set c=1
    loop
    exitwhen c>m
        call IssueTargetOrder(a[c], "thunderbolt", t[c])
        set a[c]=null
        set t[c]=null
        set c=c+1
    endloop
    call PauseTimer(x)
    call TimerStart(x,3.0,false, function KillCast)
    set x=null
endfunction

function SpawnCasters takes nothing returns nothing
    local real cx
    local real cy
    local real sx
    local real sy
    local real cf
    local real f
    local real fx
    local real fy
    local real d = 600.0
    local integer t
    local unit u
    local string s
    local timer x=CreateTimer()
    local unit c = GetTriggerUnit()
    set cx = GetUnitX(c)
    set cy = GetUnitY(c)
    set cf = GetUnitFacing(c)
    set sx = (cx-(700*Cos(cf*bj_DEGTORAD)))
    set sy = (cy-(700*Sin(cf*bj_DEGTORAD)))
    set t = 1
    loop
        exitwhen t>7
        set s = I2S(t)
        if ((t==1)or(t==3)or(t==5)or(t==7)) then
            set f = cf+(15*t-15)/2
            set fx = (sx+(d*Cos(f*bj_DEGTORAD)))
            set fy = (sy+(d*Sin(f*bj_DEGTORAD)))
            set u = CreateUnit(GetOwningPlayer(c), 'h000', fx, fy, cf)
            call SaveUnitHandle(udg_MM,StringHash("u"),StringHash(("c"+s)),u)
            set u=null
        endif
        if ((t==2)or(t==4)or(t==6)) then
            set f = cf-(15*t)/2
            set fx = (sx+(d*Cos(f*bj_DEGTORAD)))
            set fy = (sy+(d*Sin(f*bj_DEGTORAD)))
            set u = CreateUnit(GetOwningPlayer(c), 'h000', fx, fy, cf)
            call SaveUnitHandle(udg_MM,StringHash("u"),StringHash(("c"+s)),u)
            set u=null
        endif
        set t=t+1
    endloop
    call TimerStart(x,0.3,false, function CastMis)
endfunction

function EnemyChecker takes nothing returns boolean
    return (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0) and not (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) and (IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())))
endfunction 

function PickTargets takes nothing returns nothing
    local group g=CreateGroup()
    local location loc
    local unit u
    set loc = GetUnitLoc(GetSpellTargetUnit())
    call GroupEnumUnitsInRangeOfLoc(g,loc,250.00,Condition(function EnemyChecker))
    call DestroyBoolExpr(Condition(function EnemyChecker))
    set u = GroupPickRandomUnit(g)
    call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t2"), u)
    call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t5"), u)
    set u = GroupPickRandomUnit(g)
    call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t3"), u)
    call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t7"), u)
    call RemoveLocation(loc)
    call DestroyGroup(g)
    set loc = null
    set g = null
    set u = null
    call SpawnCasters()
endfunction

function Starter takes nothing returns nothing
    local integer m
    local unit u
    local hashtable h
    if ( GetSpellAbilityId() == 'A005' ) then
        set m = GetUnitAbilityLevel(GetTriggerUnit(),'A005')
        if m==4 then
            set u=null
            set h=null
            return
        endif
        set h = InitHashtable()
        set udg_MM = h
        set m = m*2+1
        set u = GetSpellTargetUnit()
        call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t1"), u)
        call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t4"), u)
        call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t6"), u)
        call SaveInteger(udg_MM, StringHash("l"), StringHash("m"),m)
        set u = null
        set h = null
        call PickTargets()
    endif
endfunction

//===============================================================

function InitTrig_MagicMissile takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t, function Starter )
    set t = null
endfunction


JASS:
function MSWrap takes nothing returns nothing
    call FlushChildHashtable(udg_MM,StringHash("u"))
    call FlushChildHashtable(udg_MM,StringHash("l"))
    call FlushParentHashtable(udg_MM)
endfunction

function MSKillCast takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local integer i
    if (TimerGetRemaining(t)==0.0) then
        set i=1
        loop
        exitwhen i>30
            call RemoveUnit(LoadUnitHandle(udg_MM,StringHash("u"),StringHash("c"+I2S(i))))
            set i=i+1
        endloop
        call PauseTimer(t)
        call DestroyTimer(t)
        set t=null
        call MSWrap()
    endif
endfunction

function MSCastMis takes nothing returns nothing
    local integer c
    local unit array a
    local unit array t
    local string s
    local timer x=GetExpiredTimer()
    if (TimerGetRemaining(x)!=0.0) then
    return
    endif
    set c=1
    loop
    exitwhen c>30
        set s=I2S(c)
        set a[c]=LoadUnitHandle(udg_MM,StringHash("u"),StringHash(("c"+s)))
        set t[c]=LoadUnitHandle(udg_MM,StringHash("u"),StringHash(("t"+s)))
        set c=c+1
    endloop
    set c=1
    loop
    exitwhen c>30
        call IssueTargetOrder(a[c], "thunderbolt", t[c])
        set a[c]=null
        set t[c]=null
        set c=c+1
    endloop
    call PauseTimer(x)
    call TimerStart(x,3.0,false, function MSKillCast)
    set x=null
endfunction

function MSSpawnCasters takes nothing returns nothing
    local real cx
    local real cy
    local real sx
    local real sy
    local real cf
    local real f
    local real fx
    local real fy
    local real d = 200.0
    local integer t
    local unit u
    local string s
    local timer x=CreateTimer()
    local unit c = GetTriggerUnit()
    set cx = GetUnitX(c)
    set cy = GetUnitY(c)
    set cf = GetUnitFacing(c)
    set t = 1
    loop
        exitwhen t>30
            set s = I2S(t)
            set f = cf+(12*t-12)
            set fx = (cx+(d*Cos(f*bj_DEGTORAD)))
            set fy = (cy+(d*Sin(f*bj_DEGTORAD)))
            set u = CreateUnit(GetOwningPlayer(c), 'h000', fx, fy, f)
            call SaveUnitHandle(udg_MM,StringHash("u"),StringHash(("c"+s)),u)
            set u=null
            set t=t+1
    endloop
    call TimerStart(x,0.3,false, function MSCastMis)
endfunction

function MSEnemyChecker takes nothing returns boolean
    return (GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0) and not (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)) and (IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit())))
endfunction 

function MSPickTargets takes nothing returns nothing
    local group g=CreateGroup()
    local location loc=GetUnitLoc(GetTriggerUnit())
    local integer i
    local unit u
    call GroupEnumUnitsInRangeOfLoc(g,loc,1200.00,Condition(function MSEnemyChecker))
    call DestroyBoolExpr(Condition(function MSEnemyChecker))
    set i=1
    loop
        exitwhen i>30
        set u = GroupPickRandomUnit(g)
        call SaveUnitHandle(udg_MM, StringHash("u"), StringHash("t"+I2S(i)), u)
        set i=i+1
    endloop
    call RemoveLocation(loc)
    call DestroyGroup(g)
    set loc = null
    set g = null
    set u = null
    call MSSpawnCasters()
endfunction

function MisStormStarter takes nothing returns nothing
    local integer m
    local hashtable h
    if ( GetSpellAbilityId() == 'A005' ) then
        set m = GetUnitAbilityLevel(GetTriggerUnit(),'A005')
        if m<4 then
            set h = null
            return
        endif 
        set h = InitHashtable()
        set udg_MM = h   
        set h = null
        call MSPickTargets()
    endif
endfunction

//===============================================================

function InitTrig_MissileStorm takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( t, function MisStormStarter )
    set t = null
endfunction

Also did something in object editor. Deleted the original Magic Missile spell based off of thunderbolt (which had the unwanted effect of instantly stunning the target) and made a similar variety based of off channel. Gave it a 4th level that pulls the MissileStorm trigger instead of of MagicMissile, also changed 4th level to instant cast instead of unit target. So, I now have a fully functioning spell based off of one of my two favorite DnD spells! One thing I was thinking of, also, is created a global integer that can be used to check for a null spot in a hashtable array (to make this spell fully MUI). Due to timer usage prior to Wrap and MSWrap, I think this spell would overwrite important parts of the hash if cast simultaneously. Would that be correct?
 
Last edited:
Level 29
Joined
Mar 10, 2009
Messages
5,016
1) Always use a global hashtable coz it has a limit of 255, in vJass we're using Table
2) Stringhash is slow, use a normal integer to indicate your childID
3) Always use function configurables on top like
JASS:
function NAME_SpellId takes nothing returns integer
   returns 'A005'
endfunction
4) Use coordinates instead of locations and a global group to group and pick units then just remove the unit no need to destroy
JASS:
local unit first
call GroupEnumUnitsInRange(udg_grp, x, y, 250, null)
loop
   set first = FirstOfGroup(udg_grp)
   exitwhen first==null
   if CONDITION HERE then
      //actions here
endif  
call GroupRemoveUnit(udg_grp, first)
endloop
5) Instead of DisplayTextToForce use DisplayTextToPlayer
6) Destroy local timers when not use anymore


There are still many to improve but these are the basics...
 
Level 12
Joined
Oct 16, 2010
Messages
680
set a[c]=LoadUnitHandle(udg_MM,StringHash("u"),StringHash(("c"+s))) set t[c]=LoadUnitHandle(udg_MM,StringHash("u"),StringHash(("t"+s)))

okay.. use hashtable or arrays or groups but use only one of them ... and to give u some clue about making sense in key usage here

example:
JASS:
//define previously a MaxTarget global variable (integer)

    local int i = 0
    call GroupEnumUnitsInRangeOfLoc(g,loc,250.00,Condition(function EnemyChecker))
    call DestroyBoolExpr(Condition(function EnemyChecker))
    loop
        set u = GroupPickRandomUnit(g)
        call SaveUnitHandle(udg_MM,0,i)
        call GroupRemoveUnit(g,u)
        set i = i + 1
        exitwhen i == MaxTarget
    endloop

use same method on casters but use 1 instead of 0 like SaveUnitHandle(udg_MM,1,i)

and later

JASS:
local integer i = 0
loop
    call IssueTargetOrder (LoadUnitHandle(udg_MM,1,i),"thunderbolt",LoadUnitHandle(udg_MM,0,i))
    set i = i+1
    exitwhen i==MaxTarget
endloop

EDIT:
mind that whatever you use (global groups, hashtable , arrays ) this script is not MUI atm.

but can make with ease like this

(before doing anything merge the casterspawn trigger with the target picking trigger)
JASS:
//define previously a MaxTarget global variable (integer)

    local int i = 0
    call GroupEnumUnitsInRangeOfLoc(g,loc,250.00,Condition(function EnemyChecker))
    call DestroyBoolExpr(Condition(function EnemyChecker))
    loop
        set u = GroupPickRandomUnit(g)
        call SaveUnitHandle(udg_MM,GetHandleId(x),i)
        call GroupRemoveUnit(g,u)
        set i = i + 1
        exitwhen i == MaxTarget
    endloop

use same method on casters, but now loop from MaxTarget till MaxTarget*2
JASS:
local int i = MaxTarget
    exitwhen i == MaxTarget*2

JASS:
local integer i = 0
loop
    call IssueTargetOrder (LoadUnitHandle(udg_MM,GetHandleId(t),i+MaxTarget),"thunderbolt",LoadUnitHandle(udg_MM,GetHandleId(t),i))
    set i = i+1
    exitwhen i==MaxTarget
endloop
 
Last edited:
Status
Not open for further replies.
Top