• 🏆 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] Spell Help Required

Status
Not open for further replies.
Level 7
Joined
Jul 9, 2008
Messages
253
Hello everybody, I got a problem with a spell. There are no errors this time, it's just that the damaging doesn't work.

Trigger:

JASS:
// Spell ID //

constant function Lightning_Generator_ID takes nothing returns integer
    return 'A002'
endfunction

// Dummy ID //

constant function Lightning_Generator_Dummy takes nothing returns integer
    return 'o001'
endfunction

// Damage Constant // 

constant function Lightning_Generator_Constant_Damage takes nothing returns real
    return 10.
endfunction

// Power Factor //

constant function Lightning_Generator_Power_Factor takes nothing returns real
    return 0.3
endfunction 

// Area of Effect //

constant function Lightning_Generator_Area takes nothing returns real
    return 300.
endfunction

// Effect //

constant function Lightning_Generator_Effect takes nothing returns string
    return "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl"
endfunction

// Filter //

function Lightning_Generator_EnemyFilter takes nothing returns boolean
    return IsPlayerEnemy( GetOwningPlayer( GetFilterUnit() ) , GetOwningPlayer( GetTriggerUnit() ) ) == true and GetUnitState( GetFilterUnit() , UNIT_STATE_LIFE ) > 0.405
endfunction

function Lightning_Generator_Expire takes nothing returns nothing
    local timer t = GetExpiredTimer()        
    local unit dummy = LoadUnitHandle( udg_Lightning_Hashtable , GetHandleId( t ) , 1 )
    local real amount = LoadReal( udg_Lightning_Hashtable , GetHandleId( t ) , 2 )
    local player p = GetOwningPlayer( dummy )
    local real x = GetUnitX( dummy )
    local real y = GetUnitY( dummy )
    local real count = LoadReal( udg_Lightning_Hashtable , GetHandleId( t ) , 3 ) + 0.9 
    local unit u
    local group g = CreateGroup()
    //
    if count >= 4.55 then
        set count = 0
        call SaveReal( udg_Lightning_Hashtable , GetHandleId( t ) , 3 , count )
        call KillUnit( dummy )
        call DestroyTimer( t )
        call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl" , x , y ) )
    else
        call SaveReal( udg_Lightning_Hashtable , GetHandleId( t ) , 3 , count )
        call BJDebugMsg( "lol" )
        //
        //=============================================================// 
        //=============================================================//
        call GroupEnumUnitsInRange( g , x , y , Lightning_Generator_Area() , Condition( function Lightning_Generator_EnemyFilter ) )
        loop
            set u = FirstOfGroup( g )
            exitwhen u == null
                //
                call UnitDamageTarget( dummy , u , amount , true , false , ATTACK_TYPE_NORMAL , DAMAGE_TYPE_UNKNOWN , WEAPON_TYPE_WHOKNOWS )
                //
            call GroupRemoveUnit( g , u )
            set u = null
        endloop
        //=============================================================//  
        //=============================================================// 
        //
    endif
    //
    call DestroyGroup( g )
    //
    set t = null
    set dummy = null
    set p = null
    set g = null
endfunction

function Trig_Lightning_Generator_Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local unit caster = GetTriggerUnit()
    local real tx = GetSpellTargetX()
    local real ty = GetSpellTargetY()
    local real amount = Lightning_Generator_Constant_Damage() + ( Lightning_Generator_Power_Factor() * udg_Power )
    local unit dummy
    local player p = GetOwningPlayer( caster )
    local real angle = GetUnitFacing( caster )
    //
    set dummy = CreateUnit( p , Lightning_Generator_Dummy() , tx , ty , angle )
    call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl" , tx , ty ) )
    call SetUnitX( dummy , tx )
    call SetUnitY( dummy , ty )
    call AddSpecialEffectTarget( Lightning_Generator_Effect() , dummy , "chest" )
    //
    call SaveUnitHandle( udg_Lightning_Hashtable , GetHandleId( t ) , 1 , dummy )
    call SaveReal( udg_Lightning_Hashtable , GetHandleId( t ) , 2 , amount )
    //
    call TimerStart( t , 0.9 , true , function Lightning_Generator_Expire )
    //
    set caster = null
    set dummy = null
    set t = null
    set p = null
endfunction

// Spell Condition //

function Trig_Lightning_Generator_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == Lightning_Generator_ID()
endfunction

//===========================================================================
function InitTrig_Construct_Lightning_Generator takes nothing returns nothing
    local trigger t = CreateTrigger( )
    set udg_Lightning_Hashtable = InitHashtable()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t , Condition( function Trig_Lightning_Generator_Conditions ) )
    call TriggerAddAction( t , function Trig_Lightning_Generator_Actions )
    set t = null
endfunction

The green part doesn't work, help would be great.

Thanks in advance, Quetzalcotl
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Shouldn't the unit be nulles out of the loop?
Now that I look at it further, I don't even know why there is a loop. I would just do:

JASS:
call GroupEnumUnitsInRange( g , x , y , Lightning_Generator_Area() , Condition( function Lightning_Generator_EnemyFilter ) )
    set u = FirstOfGroup( g )
    call UnitDamageTarget( dummy , u , 50. , true , false , ATTACK_TYPE_NORMAL , DAMAGE_TYPE_UNKNOWN , WEAPON_TYPE_WHOKNOWS )
    call GroupRemoveUnit( g , u )

EDIT 2: I found the problem! Insted of writing an amount in the damage, you wrote "Amount". LOL! I Replaced it with 50. but you can change it to the value you want.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,191
call UnitDamageTarget( dummy , u , amount , true , false , ATTACK_TYPE_NORMAL , DAMAGE_TYPE_UNKNOWN , WEAPON_TYPE_WHOKNOWS )

Both booleans must be false. Blizzard never implimented them thus why GUI can not use them. Setting them to anything other than false will cause serious problems.
 
Shouldn't the unit be nulles out of the loop?

This is most likely the problem. Since the loop exits when u == null, it will only damage one unit. Remove that and the loop should work fine. Unless you wanted it to only damage one unit.

call UnitDamageTarget( dummy , u , amount , true , false , ATTACK_TYPE_NORMAL , DAMAGE_TYPE_UNKNOWN , WEAPON_TYPE_WHOKNOWS )

Both booleans must be false. Blizzard never implimented them thus why GUI can not use them. Setting them to anything other than false will cause serious problems.

I am not sure about long-term effects, but on testing with footmen it seemed to work fine in all 3 situations. Although, I didn't test it with an actual ranged unit like the parameter implies. :grin:

Anyway, you might be a bit mistaken considering it uses this:
JASS:
function UnitDamageTargetBJ takes unit whichUnit, unit target, real amount, attacktype whichAttack, damagetype whichDamage returns boolean
    return UnitDamageTarget(whichUnit, target, amount, true, false, whichAttack, whichDamage, WEAPON_TYPE_WHOKNOWS)
endfunction

From the blizzard.j. It sets the first to true, and the second to false. And considering there are many spells that use that and the fact that majority of spell makers use GUI, I think it should work fine. =D

If it is not that and it is a hashtable problem, use this:
JASS:
function Lightning_Generator_Expire takes nothing returns nothing
    local timer t = GetExpiredTimer()        
    local unit dummy = LoadUnitHandle( udg_Lightning_Hashtable , GetHandleId( t ) , 1 )
    local real amount = LoadReal( udg_Lightning_Hashtable , GetHandleId( t ) , 2 )
    local player p = GetOwningPlayer( dummy )
    local real x = GetUnitX( dummy )
    local real y = GetUnitY( dummy )
    local real count = LoadReal( udg_Lightning_Hashtable , GetHandleId( t ) , 3 ) + 0.9 
    local unit u
    local group g = CreateGroup()
    
    call BJDebugMsg("Dummy: "+GetUnitName(dummy))
    call BJDebugMsg("Amount: "+R2S(amount))
    call BJDebugMsg("Count: "+R2S(count))
//Add these functions after the local declarations just as shown here

Be sure it doesn't return null or 0 unless it is supposed to.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,191
Ops, my mistake. Be warned that altering one of them has been known to create a thread crash (like division by 0).

Just to make sure, you have set the hashtable variable to a hashtable right? Almost every problem I see like this it turns out the person forgets to set the hashtable variable to an actual hashtable.
 
Level 7
Joined
Jul 9, 2008
Messages
253
So I haven't got it fixed yet, even though I tried everything you said. The BJDebugMsg showed everything it should show, the dummy, the amount and the count. When I removed the "set u = null" it still didn't work. So I it has to do with the GroupEnum part, because when I create a special effect in the "else" it does work.

So if you guys have more suggestions I will be grateful.

Thanks in advance, Quetzalcotl
 
Level 7
Joined
Jul 9, 2008
Messages
253
The code in the first post is the whole spell :p, and the "else" I was talking about is just the else where the group damaging part is in.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
OK, the problem was, your EnemyFilter was still using the GetTriggerUnit(). Your event was an expired timer, not a TriggerUnit(). I rewrote a lot of the code for shorter script.

Edit: You are using NewGen, right? No one should be coding in JASS without it.

This code won't render without NewGen, so if you're still using WorldEdit, I'll have to re-write a couple things.

JASS:
scope LGenerator initializer Init
globals
    private unit Dummy
    private hashtable Hash    // Replaces udg_Lightning_Hashtable
endglobals
 
// For use with GroupEnumUnitsInRange
private function EnemyFilter takes nothing returns boolean
    local unit u = GetFilterUnit()
    local boolean b = IsUnitEnemy( u , GetOwningPlayer(Dummy) ) and GetUnitState( u , UNIT_STATE_LIFE ) > 0 and IsUnitType( u , UNIT_TYPE_DEAD ) == false
    set u = null
    return b
endfunction
 
// On expiration of timer t
private function Expiry takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer handleId = GetHandleId( t )
    local unit u = LoadUnitHandle( Hash , handleId , 1 )
    local real amount = LoadReal( Hash , handleId , 2 )
    local integer count = LoadInteger( Hash , handleId , 3 ) + 1
    local real x = GetUnitX( u )
    local real y = GetUnitY( u )
    local group g = CreateGroup()
    //
    set Dummy = u
    call GroupEnumUnitsInRange( g , x , y , 300. , Condition( function EnemyFilter ) )
     loop
      set u = FirstOfGroup( g )
       exitwhen u == null
        call UnitDamageTarget( Dummy , u , amount , true , false , ATTACK_TYPE_NORMAL , DAMAGE_TYPE_LIGHTNING , WEAPON_TYPE_WHOKNOWS )
        call GroupRemoveUnit( g , u )
     endloop
    call DestroyGroup( g )
    //
    if count == 5 then
        call DestroyEffect( LoadEffectHandle( Hash , handleId , 4 ) )
        call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl" , x , y ) )
        call KillUnit( Dummy )
        call FlushChildHashtable( Hash , handleId )
        call DestroyTimer( t )
    else
        call RemoveSavedInteger( Hash , handleId , 3 )
        call SaveInteger( Hash , handleId , 3 , count )
    endif
    // 
    set g = null
    set u = null
    set t = null
endfunction
 
// Initial function that defines hashtable values
private function Actions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer handleId = GetHandleId( t )
    local real x = GetSpellTargetX()
    local real y = GetSpellTargetY()
    local unit u = CreateUnit( GetOwningPlayer( GetTriggerUnit() ) , 'o001' , x , y , GetUnitFacing( GetTriggerUnit() ) )
    local effect fx = AddSpecialEffectTarget( "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl" , u , "chest" )
    // 
    call DestroyEffect( AddSpecialEffect( "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl" , x , y ) )
    call SaveUnitHandle( Hash , handleId , 1 , u )
    call SaveReal( Hash , handleId , 2 , 10.+(0.3*udg_Power) )
    call SaveInteger( Hash , handleId , 3 , 0 )
    call SaveEffectHandle( Hash , handleId , 4 , fx )
    call TimerStart( t , 0.9 , true , function Expiry )
    // 
    set fx = null
    set u = null
    set t = null
endfunction
 
// Trigger conditions
private constant function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A002'
endfunction
 
// Initializes the scope LGenerator
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger( )
    set Hash = InitHashtable()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t , Condition( function Conditions ) )
    call TriggerAddAction( t , function Actions )
    set t = null
endfunction
endscope
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Just make sure you rename Lightning_Hashtable to LHash.

JASS:
constant function SpellPath takes nothing returns string
    return "Abilities\\Spells\\Human\\Polymorph\\PolyMorphDoneGround.mdl"
endfunction
 
constant function ShieldPath takes nothing returns string
    return "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl"
endfunction
 
constant function LGenConditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A002'
endfunction
 
function LGenExpiry takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId( t )
    local unit u = LoadUnitHandle( udg_LHash , id , 1 )
    local real amount = LoadReal( udg_LHash , id , 2 )
    local integer count = LoadInteger( udg_LHash , id , 3 ) + 1
    local real x = GetUnitX( u )
    local real y = GetUnitY( u )
    local group g = CreateGroup()
    local unit Dummy = u
 
    call GroupEnumUnitsInRange( g , x , y , 300. , null ) )
    loop
        set u = FirstOfGroup( g )
        exitwhen u == null
        call GroupRemoveUnit( g , u )
        if IsUnitEnemy( u , GetOwningPlayer(Dummy) ) and GetUnitState( u , UNIT_STATE_LIFE ) > 0 then
            call UnitDamageTarget( Dummy , u , amount , true , false , ATTACK_TYPE_NORMAL , DAMAGE_TYPE_LIGHTNING , WEAPON_TYPE_WHOKNOWS )
        endif
    endloop
    call DestroyGroup( g )
    if count == 5 then
        call DestroyEffect( LoadEffectHandle( udg_LHash , id , 4 ) )
        call DestroyEffect( AddSpecialEffect( SpellPath() , x , y ) )
        call KillUnit( Dummy )
        call FlushChildHashtable( udg_LHash , id )
        call DestroyTimer( t )
    else
        call SaveInteger( udg_LHash , id , 3 , count )
    endif
 
    set Dummy = null
    set g = null
    set u = null
    set t = null
endfunction
 
function LGenActions takes nothing returns nothing
    local timer t = CreateTimer()
    local integer id = GetHandleId( t )
    local real x = GetSpellTargetX()
    local real y = GetSpellTargetY()
    local unit u = CreateUnit( GetOwningPlayer( GetTriggerUnit() ) , 'o001' , x , y , GetUnitFacing( GetTriggerUnit() ) )
    local effect fx = AddSpecialEffectTarget( ShieldPath() , u , "chest" )
 
    call DestroyEffect( AddSpecialEffect( SpellPath() , x , y ) )
    call SaveUnitHandle( udg_LHash , id , 1 , u )
    call SaveReal( udg_LHash , id , 2 , 10.+(0.3*udg_Power) )
    call SaveInteger( udg_LHash , id , 3 , 0 )
    call SaveEffectHandle( udg_LHash , id , 4 , fx )
    call TimerStart( t , 0.9 , true , function LGenExpiry )
 
    set fx = null
    set u = null
    set t = null
endfunction
 
function InitTrig_LGenerator takes nothing returns nothing
    local trigger t = CreateTrigger( )
    set udg_LHash = InitHashtable()
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t , Condition( function LGenConditions ) )
    call TriggerAddAction( t , function LGenActions )
    set t = null
endfunction
 
Last edited:
Status
Not open for further replies.
Top