HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Execution problem with a vJASS spell

10-30-2008, 08:02 PM#1
Karawasa
This spell is meant to create a link network amongst particular towers. There are two forms, attacking mode/link mode. When an attacker attacks, it searches for links in a certain radius and gets a damage bonus based on number found.

The problem is that apparently it randomly stops firing. Once the glitch occurs I can't get the trigger to fire again. I could sell the towers and make new ones, and still the attacking ones will not draw from links. There is no apparent cause for why this happens, far as I know.

I'd appreciate if you guys could take a look at the code, and be kind enough to point out any problems or optimizations.

Collapse JASS:
scope Prism

//=======================
globals
    private constant integer TOWERID_1 = 'n022' //This is the id of the actual Prism Tower. (LINK MODE)
    private constant integer TOWERID_2 = 'n02C' //This is the id of the actual Prism Tower. (LINK MODE)
    //private constant integer PWRUPID = 'A046' //This is the id of the power up ability in the object editor.
    private constant real RANGE = 700.0 //This is the range of the tower - it will be used to determine how far the towers will look for support towers.
    private constant real DAMAGE1 = 3000.0 //This is how much damage a powering up tower does.
    private constant real DAMAGE2 = 15000.0 //This is how much damage a powering up tower does.
    private constant real BASE1 = 6000.0 //This is how much damage an attacking tower does normally.
    private constant real BASE2 = 30000.0 //This is how much damage an attacking tower does normally.
    //private constant real EXPONENT = 1.05 //This determines the factor that each tower adds to the damage of the shot.
    private constant real COOLDOWN = 0.33 //This is the cooldown of the Prism Tower's attack.
    //private constant string ORDERSTRING = "spiritlink" //This is the Order String of the effect ability.
endglobals
//=======================

//=======================
type UnitArray extends unit array[500]

globals
    private unit CurrentTower = null
    private integer array TowerValues
    private UnitArray tempArray
    private group mainP = CreateGroup()
    private timer Tprism = CreateTimer()
    private integer Total = 0
    private Prism_data array structArray
    //private real tempPower
    private integer tempCount
endglobals
//=======================

//=======================================================================================
//needed struct
struct Prism_data
    UnitArray towers
    integer size
   
    method Start_Prism takes UnitArray chain, integer count returns nothing
        set .towers = chain
        set .size = count
    endmethod
    
    method onDestroy takes nothing returns nothing
        loop
            exitwhen .size < 0
            //call UnitRemoveAbility(towerChain[i], PWRUPID)
            set TowerValues[GetUnitIndex(.towers[.size])] = TowerValues[GetUnitIndex(.towers[.size])] - 1

            set .towers[.size] = null

            set .size = .size - 1
        endloop
    endmethod
endstruct 

//movement and effects
function Prism_Go takes nothing returns nothing
    local integer i = 1
    local Prism_data dat
   
    loop
        exitwhen i > Total
        set dat = structArray[i]
       
        call dat.destroy()
        set structArray[i] = structArray[Total]
        set Total = Total - 1
    endloop
   
    if Total==0 then
        call PauseTimer(Tprism)
    endif
    //call Msg("Run",Player(0))
endfunction

private function TowerFilter1 takes nothing returns boolean
    return GetOwningPlayer(GetFilterUnit()) == GetOwningPlayer(GetEventDamageSource()) and GetUnitTypeId(GetFilterUnit()) == TOWERID_1 and TowerValues[GetUnitIndex(GetFilterUnit())] < 3 and GetUnitCurrentOrder(GetFilterUnit()) == OrderId("none") and GetFilterUnit() != CurrentTower and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction

private function TowerFilter2 takes nothing returns boolean
    return GetOwningPlayer(GetFilterUnit()) == GetOwningPlayer(GetEventDamageSource()) and GetUnitTypeId(GetFilterUnit()) == TOWERID_2 and TowerValues[GetUnitIndex(GetFilterUnit())] < 3 and GetUnitCurrentOrder(GetFilterUnit()) == OrderId("none") and GetFilterUnit() != CurrentTower and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction

private function TowerForGroup takes nothing returns nothing
    // use our globals here
    //set tempPower = tempPower * EXPONENT
    set tempCount = tempCount + 1
    set tempArray[tempCount] = GetEnumUnit()
    set TowerValues[GetUnitIndex(GetEnumUnit())] = TowerValues[GetUnitIndex(GetEnumUnit())] + 1
endfunction

//starts the effects
function Trig_Prism_Actions takes nothing returns nothing
    local real x
    local real y

    //local real power = EXPONENT
    local real speed
    local real bonus
    local real dam
    local real time

    local integer towerChainCount = 0
    local integer i

    local unit attacker = GetEventDamageSource()
    local UnitArray towerChain = UnitArray.create()
    
    local Prism_data dat
    
    //Fire Up bonus damage
    if GetUnitAbilityLevel(attacker, 'B00A') > 0 then
        set bonus = 1.25
    elseif GetUnitAbilityLevel(attacker, 'B00J') > 0 then
        set bonus = 1.5
    elseif GetUnitAbilityLevel(attacker, 'B00K') > 0 then
        set bonus = 3.0
    else
        set bonus = 1.0
    endif
    
    //Spring Forward bonus speed
    if GetUnitAbilityLevel(attacker, 'B007') > 0 then
        set speed = 1.25
    elseif GetUnitAbilityLevel(attacker, 'B00V') > 0 then
        set speed = 1.5
    elseif GetUnitAbilityLevel(attacker, 'B00W') > 0 then
        set speed = 3.0
    else
        set speed = 1.0
    endif
    
    //Get available towers and add them to the array.
    set CurrentTower = attacker
    set TowerValues[GetUnitIndex(CurrentTower)] = TowerValues[GetUnitIndex(CurrentTower)] + 1
    set towerChain[0] = CurrentTower
    
    set x = GetUnitX(CurrentTower)
    set y = GetUnitY(CurrentTower)
    
    call GroupClear(mainP)
    if GetUnitTypeId(attacker)==TOWER_GOLEM then
        call GroupEnumUnitsInRange(mainP, x, y, RANGE, Condition(function TowerFilter1))
    elseif GetUnitTypeId(attacker)==TOWER_ABOMINATION then
        call GroupEnumUnitsInRange(mainP, x, y, RANGE, Condition(function TowerFilter2))
    endif
    
// Set out temp globals to their values before we call the ForGroup()
    set tempArray = towerChain
    //set tempPower = power
    set tempCount = towerChainCount

// now we can use these globals in the forgroup
    call ForGroup(mainP,function TowerForGroup)

// no we setback each local we will use with the global from the group
    set towerChainCount = tempCount
    set towerChain = tempArray // I don't think this is needed since the array reference never changes, only the values in it
   //set power = tempPower

//Go through each tower, starting at the end, add the power up ability and order it to fire.
    set i = towerChainCount
    loop
        exitwhen i == 0
        //call UnitAddAbility(towerChain[i], PWRUPID)
        //call IssueTargetOrder(towerChain[i], ORDERSTRING, towerChain[0])
        call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\ManaFlare\\ManaFlareBoltImpact.mdl",attacker,"chest"))
        if GetUnitTypeId(attacker)==TOWER_GOLEM then
            call TextTagUnit("+" + I2S(R2I(DAMAGE1)),attacker,255,0,0,255,.01,1.)
        elseif GetUnitTypeId(attacker)==TOWER_ABOMINATION then
            call TextTagUnit("+" + I2S(R2I(DAMAGE2)),attacker,255,0,0,255,.01,1.)
        endif
        set i = i - 1
    endloop

//Add the power up damage, checking for additional towers and making sure the unit is not out of range.
    if GetUnitTypeId(attacker)==TOWER_GOLEM then
        set dam = BASE1 + (DAMAGE1 * towerChainCount) //* power
    elseif GetUnitTypeId(attacker)==TOWER_ABOMINATION then
        set dam = BASE2 + (DAMAGE2 * towerChainCount) //* power
    endif

    set dam = dam*bonus
    
    call UnitDamageTarget(attacker, GetTriggerUnit(), dam, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
    call TextTagUnit(I2S(R2I(dam)),GetTriggerUnit(),255,0,0,200,.03,2.)

    set time = COOLDOWN/speed
    
    set dat = Prism_data.create()
    call dat.Start_Prism(towerChain,towerChainCount)
       
    set Total = Total + 1
    set structArray[Total] = dat 
    if Total==1 then
        call TimerStart(Tprism,time,false,function Prism_Go)
    endif
   
    set attacker = null
endfunction

endscope
//==== Init Trigger Prism ====
function InitTrig_Prism takes nothing returns nothing     
    call ORBEngine_RegisterOrb(TOWER_GOLEM, function Trig_Prism_Actions, "TOWER_GOLEM: Prism")
    call ORBEngine_RegisterOrb(TOWER_ABOMINATION, function Trig_Prism_Actions, "TOWER_ABOMINATION: Prism")
endfunction
10-31-2008, 06:19 AM#2
Karawasa
This doesn't happen right away, but a few seconds after they start attacking for the first time.

Also, after awhile the trigger stops working.

See http://www.wc3campaigns.net/showthread.php?t=102785.
Attached Images
File type: jpgerror.jpg (607.5 KB)