• 🏆 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 (again)

Status
Not open for further replies.
Level 8
Joined
Jul 28, 2008
Messages
211
I made a spell:

JASS:
scope Spell initializer Init

native UnitAlive takes unit u returns boolean

globals

    private timer TIMER = CreateTimer()
    private boolexpr b
    private group G = CreateGroup()
    
    private constant integer DUMMY_ID = 'h000'
    private constant integer SPELL_ID = 'A000'
    private constant real RADIUS = 100.00
    private constant real PERIOD = 0.035
    private constant real DURATION = 10.00
    private constant attacktype ATTACK_TYPE = ATTACK_TYPE_CHAOS
    private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
    private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS

endglobals

private function GroupFilter takes nothing returns boolean
    return (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) == false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false) and UnitAlive(GetFilterUnit())
endfunction

private function Damage takes integer level returns real
    return I2R(level * 50 + 50)
endfunction

private struct Spells

    static integer Total = 0
    static Spells array ar
    
    unit caster
    unit array dummy [4]
    integer level
    real duration = 0
    real array angle [4]

    static method Loop takes nothing returns nothing
        local integer i = 0
        local integer count = 0
        local unit temp
        local real x
        local real y
        local Spells s
        loop
            exitwhen i >= Spells.Total
            set s = Spells.ar[i]
            if s.duration >= DURATION then
                set s.caster = null
                call KillUnit(s.dummy[0])
                call KillUnit(s.dummy[1])
                call KillUnit(s.dummy[2])
                call KillUnit(s.dummy[3])
                set s.dummy[0] = null
                set s.dummy[1] = null
                set s.dummy[2] = null
                set s.dummy[3] = null
                call s.destroy()
                set Spells.Total = Spells.Total - 1
                set Spells.ar[i] = Spells.ar[Spells.Total]
                set i = i - 1
            else
                set s.duration = s.duration + PERIOD
                loop
                    exitwhen count >= 4
                    set x = GetUnitX(s.caster) + 150 * Cos(s.angle[count] * bj_DEGTORAD)
                    set y = GetUnitY(s.caster) + 150 * Sin(s.angle[count] * bj_DEGTORAD)
                    set s.angle[count] = s.angle[count] + 7.5
                    call SetUnitX(s.dummy[count], x)
                    call SetUnitY(s.dummy[count], y)
                    call GroupEnumUnitsInRange(G, x, y, RADIUS, b)
                    loop
                        set temp = FirstOfGroup(G)
                        exitwhen temp == null
                        if IsUnitEnemy(temp, GetOwningPlayer(s.caster)) and s.dummy[count] != null then
                            call UnitDamageTarget(s.caster, temp, Damage(s.level), false, true, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                            call KillUnit(s.dummy[count])
                            set s.dummy[count] = null
                        endif
                        call GroupRemoveUnit(G, temp)
                        if s.dummy[0] == null and s.dummy[1] == null and s.dummy[2] == null and s.dummy[3] == null then
                            set s.caster = null
                            call s.destroy()
                        endif
                    endloop
                    set count = count + 1
                endloop
            endif
            set i = i + 1
        endloop
        if Spells.Total == 0 then
            call PauseTimer(TIMER)
        endif
    endmethod
    
    static method Create takes unit caster returns nothing
        local Spells s = Spells.allocate()
        set s.caster = caster
        set s.level = GetUnitAbilityLevel(caster, SPELL_ID)
        //1
        set s.dummy[0] = CreateUnit(GetOwningPlayer(caster), DUMMY_ID, GetUnitX(caster), GetUnitY(caster), 0)
        set s.angle[0] = 0
        //2
        set s.dummy[1] = CreateUnit(GetOwningPlayer(caster), DUMMY_ID, GetUnitX(caster), GetUnitY(caster), 0)
        set s.angle[1] = 90
        //3
        set s.dummy[2] = CreateUnit(GetOwningPlayer(caster), DUMMY_ID, GetUnitX(caster), GetUnitY(caster), 0)
        set s.angle[2] = 180
        //4
        set s.dummy[3] = CreateUnit(GetOwningPlayer(caster), DUMMY_ID, GetUnitX(caster), GetUnitY(caster), 0)
        set s.angle[3] = 270
        if Spells.Total == 0 then
            call TimerStart(TIMER, PERIOD, true, function Spells.Loop)
        endif
        set Spells.ar[Spells.Total] = s
        set Spells.Total = Spells.Total + 1
    endmethod
    
endstruct

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

private function Act takes nothing returns nothing
    call Spells.Create(GetTriggerUnit())
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddAction(t, function Act)
    call TriggerAddCondition(t, Condition(function Cond))
    
    set b = Filter(function GroupFilter)
endfunction

endscope

The it should create 4 rocks that circle around the caster and damage enemy units they hit (they explode too).
Now, the spell works, but when I cast it 2 times with a same unit (while the effect is still on), the rocks all appear on the ground where the caster is standing, and they don't move. Sometimes they DO start moving after the rocks that are on the caster explode. But only sometimes.
So what's causing this to happen? And is there anything that could be changed to make the spell more efficient?
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
The only thing I can see right now is that you forgot this:
JASS:
call s.destroy()
set Spells.Total = Spells.Total - 1
set Spells.ar[i] = Spells.ar[Spells.Total]
set i = i - 1
In this part:
JASS:
                   loop
                        set temp = FirstOfGroup(G)
                        exitwhen temp == null
                        if IsUnitEnemy(temp, GetOwningPlayer(s.caster)) and s.dummy[count] != null then
                            call UnitDamageTarget(s.caster, temp, Damage(s.level), false, true, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
                            call KillUnit(s.dummy[count])
                            set s.dummy[count] = null
                        endif
                        call GroupRemoveUnit(G, temp)
                        if s.dummy[0] == null and s.dummy[1] == null and s.dummy[2] == null and s.dummy[3] == null then
                            set s.caster = null
                            call s.destroy() //INSERT HERE
                        endif
                    endloop
 

Rmx

Rmx

Level 19
Joined
Aug 27, 2007
Messages
1,164
Your mistaken, when you cast the spell again, the First 4 dummys created will be placed instantly on the hero stand position and the others should maybe rotate, becoz those dummys are not LOCALIZED, they are global as i can see in your trigger :S

JASS:
 unit array dummy [4]
Maybe the array [4] is the problem :S
 
Add
JASS:
set count = 0
after the dummy loop.
JASS:
                        endif
                    endloop
                    set count = count + 1
                endloop
                set count = 0
Because after the first 4 dummys were reached the count integer would be increased and then be count=4. But there is no dummy[4]. So it only worked for the first index.
s[0] - count = 0
s[0] - count = 1
s[0] - count = 2
s[0] - count = 3
s[1] - count = 4 EXIT >= 4
s[2] - count = 4 EXIT >= 4
etc.
If you get what i mean.
 
Status
Not open for further replies.
Top