1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[JASS] Spell only works on the caster

Discussion in 'Triggers & Scripts' started by Saishy, Feb 10, 2009.

  1. Saishy

    Saishy

    Joined:
    Mar 23, 2008
    Messages:
    947
    Resources:
    0
    Resources:
    0
    Spell don't heal

    I have a spell that heals in a area for 10s, but its not working at all.

    AREA NON-CHANNEL HEALING
    Code (vJASS):
    scope SoutenKisshunNC initializer InSoutenKisshunNC

    globals
        private integer RADIUS = 300
    endglobals

    private struct SK
        unit caster
        real heal
        real x
        real y
        integer count
        unit sfx
    endstruct

    globals
        private player tp
    endglobals

    private function SoutenKisshunNC_Conditions takes nothing returns boolean
        return ( GetSpellAbilityId() == 'A04Z' )
    endfunction

    private function SoutenKisshunNC_Group takes nothing returns boolean
        return ( IsUnitEnemy(GetFilterUnit(), tp) != true ) and (GetWidgetLife(GetFilterUnit()) > 0.405)
    endfunction

    private function SoutenKisshunNC_Heal takes nothing returns nothing
        local SK s = GetTimerData(GetExpiredTimer())
        local group hgroup = CreateGroup()
        local unit tu
        if (s.count <= 40)  then
            set tp = GetOwningPlayer(s.caster)
            call GroupEnumUnitsInRange(hgroup, s.x, s.y, RADIUS, Condition(function SoutenKisshunNC_Group))
            loop
                set tu = FirstOfGroup(hgroup)
                exitwhen tu == null
                call SetUnitState(tu, UNIT_STATE_LIFE, GetUnitState(tu, UNIT_STATE_LIFE) + s.heal)
                call GroupRemoveUnit(hgroup, tu)
            endloop
            call DestroyGroup(hgroup)
            set hgroup = null
            set tp = null
            set s.count = s.count + 1
        else
            call ReleaseTimer(GetExpiredTimer())
            call s.destroy()
            call RemoveUnit(s.sfx)
            set s.sfx = null
            set s.caster = null
        endif
    endfunction

    private function SoutenKisshunNC_Actions takes nothing returns nothing
        local SK s = SK.create()
        local timer t = NewTimer()
        local location target = GetSpellTargetLoc()
        set s.x = GetLocationX(target)
        set s.y = GetLocationY(target)
        set s.caster = GetTriggerUnit()
        set s.heal = GetUnitAbilityLevel(s.caster, 'A04R') * 2.5
        set s.sfx = CreateUnit(GetOwningPlayer(s.caster), 'h01A', s.x, s.y, 90)
        call SetUnitScale(s.sfx, 2, 2, 2)
        call SetTimerData(t,s)
        call TimerStart(t, 0.25, true, function SoutenKisshunNC_Heal)
        call RemoveLocation(target)
        set target = null
    endfunction

    //===========================================================================
    function InSoutenKisshunNC takes nothing returns nothing
        local trigger t_SoutenKisshunNC = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t_SoutenKisshunNC, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( t_SoutenKisshunNC, Condition( function SoutenKisshunNC_Conditions ) )
        call TriggerAddAction( t_SoutenKisshunNC, function SoutenKisshunNC_Actions )
        set t_SoutenKisshunNC = null
    endfunction

    endscope


    Thanks in advance!
     
    Last edited: Feb 10, 2009
  2. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    First of all, can I just say that you have some very bad programming practices. All constant numbers should be constant variables declared in your globals block, along with RADIUS, though they should also be constant. Declare a constant variable like this:
    Code (vJASS):
    globals
        ...
        constant <type> <name> = <x>
        ...
    endglobals
    . This makes your code changeable easily if you ever want to revise some of the durations.

    Secondly, it leaks a boolexpr. You can't use a boolexpr just by doing Condition(function <x>) without it leaking, as this creates a boolexpr but doesn't remove it. Obviously this will leak.

    Thirdly, the way you compare values is inefficient. Rather than doing
    IsUnitEnemy(GetFilterUnit(), tp) != true)
    , it's more efficient and easier to type if you simply do
    IsUnitEnemy(!GetFilterUnit(), tp))
    . It does the same thing, just without having to compare anything due to you giving the if statement a straight boolean argument, which makes the if statement twice as efficient.

    And about your problem - try doing all of your loop actions inside the enum function rather than looping through the group and removing the units etc. and store the struct in a temporary global variable to transfer it to the enum function. While this might not solve your problem, try doing everything I've suggested, and if it still doesn't work, post the new code, with the changes, and I'll try to address the problem from there.

    Hope I helped

    Element of Water
     
  3. Saishy

    Saishy

    Joined:
    Mar 23, 2008
    Messages:
    947
    Resources:
    0
    Resources:
    0
    I changed what I understand, but IsUnitEnemy(!GetFilterUnit(), tp)) gave me "Unexpected !"

    Also, to compare I have the channeling version of it working:

    Code (vJASS):
    scope SoutenKisshunUP initializer InSoutenKisshunUP

    private struct SK
        unit caster
        real heal
        real x
        real y
        integer radius
        unit sfx
    endstruct

    globals
        private player tp
    endglobals

    private function SoutenKisshunUP_Conditions takes nothing returns boolean
        return ( GetSpellAbilityId() == 'A04X' ) or ( GetSpellAbilityId() == 'A04Y' )
    endfunction

    private function SoutenKisshunUP_Group takes nothing returns boolean
        return IsUnitAlly(GetFilterUnit(), tp) and (GetWidgetLife(GetFilterUnit()) > 0.405)
    endfunction

    private function SoutenKisshunUP_Heal takes nothing returns nothing
        local SK s = GetTimerData(GetExpiredTimer())
        local group hgroup = CreateGroup()
        local unit tu
        if (GetUnitCurrentOrder(s.caster) == 852063)  then
            set tp = GetOwningPlayer(s.caster)
            call GroupEnumUnitsInRange(hgroup, s.x, s.y, s.radius, Condition(function SoutenKisshunUP_Group))
            loop
                set tu = FirstOfGroup(hgroup)
                exitwhen tu == null
                call SetUnitState(tu, UNIT_STATE_LIFE, GetUnitState(tu, UNIT_STATE_LIFE) + s.heal)
                call GroupRemoveUnit(hgroup, tu)
            endloop
            call DestroyGroup(hgroup)
            set hgroup = null
            set tp = null
        else
            call ReleaseTimer(GetExpiredTimer())
            call s.destroy()
            set s.caster = null
            set s.sfx = null
            set s.caster = null
        endif
    endfunction

    private function SoutenKisshunUP_Actions takes nothing returns nothing
        local SK s = SK.create()
        local timer t = NewTimer()
        local location target = GetSpellTargetLoc()
        set s.x = GetLocationX(target)
        set s.y = GetLocationY(target)
        set s.caster = GetTriggerUnit()
        if ( GetSpellAbilityId() == 'A04X' ) then
            set s.radius = 200
            set s.heal = GetUnitAbilityLevel(s.caster, 'A04X') * 2.5
            set s.sfx = CreateUnit(GetOwningPlayer(s.caster), 'h01A', s.x, s.y, 90)
        else
            set s.radius = 250
            set s.heal = GetUnitAbilityLevel(s.caster, 'A04Y') * 2.5
            set s.sfx = CreateUnit(GetOwningPlayer(s.caster), 'h01A', s.x, s.y, 90)
            call SetUnitScale(s.sfx, 1.5, 1.5, 1.5)
        endif
        call SetUnitAnimation(s.caster, "stand")
        call SetTimerData(t,s)
        call TimerStart(t, 0.25, true, function SoutenKisshunUP_Heal)
        call RemoveLocation(target)
        set target = null
    endfunction

    //===========================================================================
    function InSoutenKisshunUP takes nothing returns nothing
        local trigger t_SoutenKisshunUP = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t_SoutenKisshunUP, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( t_SoutenKisshunUP, Condition( function SoutenKisshunUP_Conditions ) )
        call TriggerAddAction( t_SoutenKisshunUP, function SoutenKisshunUP_Actions )
        set t_SoutenKisshunUP = null
    endfunction

    endscope


    Code (vJASS):
    scope SoutenKisshunNC initializer InSoutenKisshunNC

    globals
        private integer RADIUS = 300
        private integer COUNT = 40
        private real INTERVAL = 0.25
    endglobals

    private struct SK
        unit caster
        real heal
        real x
        real y
        integer count
        unit sfx
    endstruct

    globals
        private player tp
    endglobals

    private function SoutenKisshunNC_Conditions takes nothing returns boolean
        return ( GetSpellAbilityId() == 'A04Z' )
    endfunction

    private function SoutenKisshunNC_Group takes nothing returns boolean
        return IsUnitAlly(GetFilterUnit(), tp) and (GetWidgetLife(GetFilterUnit()) > 0.405)
    endfunction

    private function SoutenKisshunNC_Heal takes nothing returns nothing
        local SK s = GetTimerData(GetExpiredTimer())
        local group hgroup = CreateGroup()
        local unit tu
        if (s.count <= COUNT)  then
            set tp = GetOwningPlayer(s.caster)
            call GroupEnumUnitsInRange(hgroup, s.x, s.y, RADIUS, Condition(function SoutenKisshunNC_Group))
            loop
                set tu = FirstOfGroup(hgroup)
                exitwhen tu == null
                call SetUnitState(tu, UNIT_STATE_LIFE, GetUnitState(tu, UNIT_STATE_LIFE) + s.heal)
                call GroupRemoveUnit(hgroup, tu)
            endloop
            call DestroyGroup(hgroup)
            set hgroup = null
            set tp = null
            set s.count = s.count + 1
            call SetUnitAnimation(s.sfx, "stand")
        else
            call ReleaseTimer(GetExpiredTimer())
            call s.destroy()
            call RemoveUnit(s.sfx)
            set s.sfx = null
            set s.caster = null
        endif
    endfunction

    private function SoutenKisshunNC_Actions takes nothing returns nothing
        local SK s = SK.create()
        local timer t = NewTimer()
        local location target = GetSpellTargetLoc()
        set s.count = 0
        set s.x = GetLocationX(target)
        set s.y = GetLocationY(target)
        set s.caster = GetTriggerUnit()
        set s.heal = GetUnitAbilityLevel(s.caster, 'A04R') * 2.5
        set s.sfx = CreateUnit(GetOwningPlayer(s.caster), 'h01A', s.x, s.y, 0)
        call SetUnitScale(s.sfx, 2, 2, 2)
        call SetTimerData(t,s)
        call TimerStart(t, INTERVAL, true, function SoutenKisshunNC_Heal)
        call RemoveLocation(target)
        set target = null
    endfunction

    //===========================================================================
    function InSoutenKisshunNC takes nothing returns nothing
        local trigger t_SoutenKisshunNC = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ( t_SoutenKisshunNC, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition( t_SoutenKisshunNC, Condition( function SoutenKisshunNC_Conditions ) )
        call TriggerAddAction( t_SoutenKisshunNC, function SoutenKisshunNC_Actions )
        set t_SoutenKisshunNC = null
    endfunction

    endscope


    Obs* Of couse I have bad programming habits, its the first thing bigger than "hello world" I ever programmed...

    Edit: Lol found the error:

    Code (vJASS):
    set s.heal = GetUnitAbilityLevel(s.caster, 'A04Z') * 2.5


    but if you want give me programming tips, feel free to do it xD
     
  4. HINDYhat

    HINDYhat

    Joined:
    Apr 22, 2007
    Messages:
    1,594
    Resources:
    3
    Maps:
    2
    Spells:
    1
    Resources:
    3
    ehm, you can't do ! in Jass. :p

    You can do
     if not IsUnitEnemy(GetFilterUnit(), tp)
    , though. It really doesn't change much, it's more of a habit and doesn't actually change results (noticeably anyway) unless you work with the IsUnitType function, which is fucked up.

    And NO, boolexprs do not leak in this situation. They are actually stored in a sort of table to which the boolexpr will always reference. Destroying them has proven to be pretty damn useless and will cause bugs occasionally. Note that there are some times when you will have to destroy them, but not here anyway.

    And I'm too lazy to actually review your script. lol :p
     
  5. Element of Water

    Element of Water

    Joined:
    Aug 3, 2008
    Messages:
    2,298
    Resources:
    5
    Spells:
    3
    Tutorials:
    1
    JASS:
    1
    Resources:
    5
    Sorry, had my c++ head on kinda. And i put it in the wrong place :p

    Always thought they did... weird. When do they leak then?
     
  6. Saishy

    Saishy

    Joined:
    Mar 23, 2008
    Messages:
    947
    Resources:
    0
    Resources:
    0
    There is one trigger in my map that uses boolexpr variable because vexorian told me it would leak, I don't remember where or if I still have the trigger xD