HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Stumped on a few JASS problems

08-17-2008, 08:20 AM#1
Karawasa
I'm having some difficulties because this spell as it is now requires locals to be passed to another function. We all know this doesn't work. For the local real(power) and the local integer(towerChainCount) to work I need to change them to globals. I was afraid of global overlap though because of the callback timer at the end. Not sure if that fear is justified or not, but without doubt the local unit array(towerChain) would not work as a global because it gets called back later.

Here is the part in question(problems commented out):

Collapse JASS:
private function TowerForGroup takes nothing returns nothing
    //set power = power * power
    //set towerChainCount = towerChainCount + 1
    //set towerChain[towerChainCount] = GetEnumUnit()
    set TowerValues[GetUnitIndex(GetEnumUnit())] = 1
endfunction

And here is the entire code:

Collapse JASS:
//======================================================================
// Prism Tower
//======================================================================

scope Prism

//=======================
// Configuration Header
//=======================
globals
    private constant integer TOWERID_1 = 'h000' //This is the id of the actual Prism Tower. (LINK MODE)
    private constant integer TOWERID_2 = 'h000' //This is the id of the actual Prism Tower. (LINK MODE)
    private constant integer PWRUPID = 'A000' //This is the id of the power up ability in the object editor.
    private constant real RANGE = 1000.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 = 50.0 //This is how much damage a powering up tower does.
    private constant real DAMAGE2 = 50.0 //This is how much damage a powering up tower does.
    private constant real BASE1 = 50.0 //This is how much damage an attacking tower does normally.
    private constant real BASE2 = 50.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 = 2.0 //This is the cooldown of the Prism Tower's attack.
    private constant string ORDERSTRING = "chainlightning" //This is the Order String of the effect ability.
endglobals
//=======================
// End Config Header
//=======================
globals
    private unit CurrentTower = null
    private integer array TowerValues
    private group EmptyGroup = CreateGroup()
endglobals

type TowerChainArray extends unit array[100]

private struct CleanupData
    TowerChainArray data
    integer size
endstruct

private function CleanUp takes integer tag returns boolean
    local TowerChainArray towerChain = CleanupData(tag).data
    local integer i = CleanupData(tag).size

    call CleanupData.destroy(CleanupData(tag))

    loop
        exitwhen i < 0

        call UnitRemoveAbility(towerChain[i], PWRUPID)
        set TowerValues[GetUnitIndex(towerChain[i])] = 0

        set towerChain[i] = null

        set i = i - 1
    endloop

    return false
endfunction

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

private function TowerForGroup takes nothing returns nothing
    //set power = power * power
    //set towerChainCount = towerChainCount + 1
    //set towerChain[towerChainCount] = GetEnumUnit()
    set TowerValues[GetUnitIndex(GetEnumUnit())] = 1
endfunction

function Trig_Prism_Actions takes nothing returns nothing
    local real x = GetUnitX(GetEventDamageSource())
    local real y = GetUnitY(GetEventDamageSource())
    local real x1
    local real y1

    local real power = EXPONENT
    local real bonus
    local real dam

    local integer towerChainCount = 0
    local TowerChainArray towerChain = TowerChainArray.create()

    local integer i

    local unit attacker = GetEventDamageSource()

    local CleanupData cleanupData
    
    //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

    //Get available towers and add them to the array.
    set CurrentTower = attacker
    set TowerValues[GetUnitIndex(CurrentTower)] = 1
    set towerChain[0] = CurrentTower
    
    set x = GetUnitX(CurrentTower)
    set y = GetUnitY(CurrentTower)
    
    call GroupClear(EmptyGroup)
    if GetUnitTypeId(attacker)==TOWER_GOLEM then
        call GroupEnumUnitsInRange(EmptyGroup, x, y, RANGE, Condition(function TowerFilter1))
    elseif GetUnitTypeId(attacker)==TOWER_ABOMINATION then
        call GroupEnumUnitsInRange(EmptyGroup, x, y, RANGE, Condition(function TowerFilter2))
    endif
    
    call ForGroup(EmptyGroup,function TowerForGroup)
//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[i - 1])

        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 cleanupData = CleanupData.create()
    set cleanupData.data = towerChain
    set cleanupData.size = towerChainCount

    set attacker = null
    
    call TimedEvent(COOLDOWN, integer(cleanupData), Callback.CleanUp)
endfunction

//==== 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

endscope

//==============================
//  Credit to grim001 for TimedEvent library.
//==============================
library TimedEvent initializer Init

globals
 //***   Configuration   ***
 private integer NumberOfTimers = 100
 //*** End Configuration ***

 private integer array TAGS
 private Callback array CALLBACKS
 private timer array TIMERS
 private integer N = 0
endglobals

function interface Callback takes integer tag returns boolean

private function H2I takes handle h returns integer
    return h
    return 0
endfunction

private function TimedEventExpires takes nothing returns nothing
 local timer t = GetExpiredTimer()
 local integer i = H2I(t)-0x100000
    if not CALLBACKS[i].evaluate(TAGS[i]) then
        call PauseTimer(t)
        set N = N + 1
        set TIMERS[N] = t
    endif
endfunction

function TimedEvent takes real delay, integer tag, Callback callback returns nothing
 local timer t
 local integer i
    if N == 0 then
        call BJDebugMsg("TimedEvent Error: Maximum numbers of timers ("+I2S(NumberOfTimers)+") exceeded")
        return
    else
        set t = TIMERS[N]
        set N = N-1
    endif
    set i = H2I(t)-0x100000
    set TAGS[i] = tag
    set CALLBACKS[i] = callback
    call TimerStart(t, delay, true, function TimedEventExpires)
endfunction

private function Init takes nothing returns nothing
 loop
     set TIMERS[N] = CreateTimer()
     exitwhen N == NumberOfTimers-1
     set N = N + 1
 endloop
endfunction

endlibrary

What to do?

I get the feeling that this code could be further optimized. I also wonder if there is a better way of handling things than the timed event library and the callback function.

Thanks in advance for your help.
08-17-2008, 09:53 AM#2
Ammorth
Use globals. As long as the callback function:

Collapse JASS:
private function TowerForGroup takes nothing returns nothing
    //set power = power * power
    //set towerChainCount = towerChainCount + 1
    //set towerChain[towerChainCount] = GetEnumUnit()
    set TowerValues[GetUnitIndex(GetEnumUnit())] = 1
endfunction

doesn't cause any new triggers to fire (some event happens, like a unit is created, a unit casts a spell, etc.) then your globals will stay the same.

Right now, if you were to uncomment the forgroup function and use globals to transfer values, it will work properly. Just make sure after the forgroup, to set them back to locals

Collapse JASS:
//======================================================================
// Prism Tower
//======================================================================

scope Prism

//=======================
// Configuration Header
//=======================
globals
    private constant integer TOWERID_1 = 'h000' //This is the id of the actual Prism Tower. (LINK MODE)
    private constant integer TOWERID_2 = 'h000' //This is the id of the actual Prism Tower. (LINK MODE)
    private constant integer PWRUPID = 'A000' //This is the id of the power up ability in the object editor.
    private constant real RANGE = 1000.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 = 50.0 //This is how much damage a powering up tower does.
    private constant real DAMAGE2 = 50.0 //This is how much damage a powering up tower does.
    private constant real BASE1 = 50.0 //This is how much damage an attacking tower does normally.
    private constant real BASE2 = 50.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 = 2.0 //This is the cooldown of the Prism Tower's attack.
    private constant string ORDERSTRING = "chainlightning" //This is the Order String of the effect ability.
endglobals
//=======================
// End Config Header
//=======================

// moved above global block so we don't have to use keywords for declaration of global
type TowerChainArray extends unit array[100]

globals
    private unit CurrentTower = null
    private integer array TowerValues
    private group EmptyGroup = CreateGroup()

// the temp globals which we will use to transfer data
    private TowerChainArray tempArray
    private real tempPower
    private integer tempCount
    
endglobals



private struct CleanupData
    TowerChainArray data
    integer size
endstruct

private function CleanUp takes integer tag returns boolean
    local TowerChainArray towerChain = CleanupData(tag).data
    local integer i = CleanupData(tag).size

    call CleanupData.destroy(CleanupData(tag))

    loop
        exitwhen i < 0

        call UnitRemoveAbility(towerChain[i], PWRUPID)
        set TowerValues[GetUnitIndex(towerChain[i])] = 0

        set towerChain[i] = null

        set i = i - 1
    endloop

    return false
endfunction

private function TowerFilter1 takes nothing returns boolean
    return GetOwningPlayer(GetFilterUnit()) == GetOwningPlayer(GetEventDamageSource()) and GetUnitTypeId(GetFilterUnit()) == TOWERID_1 and TowerValues[GetUnitIndex(GetFilterUnit())] != 1 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())] != 1 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 * tempPower
    set tempCount = tempCount + 1
    set tempArray[tempCount] = GetEnumUnit()
    set TowerValues[GetUnitIndex(GetEnumUnit())] = 1
endfunction

function Trig_Prism_Actions takes nothing returns nothing
    local real x = GetUnitX(GetEventDamageSource())
    local real y = GetUnitY(GetEventDamageSource())
    local real x1
    local real y1

    local real power = EXPONENT
    local real bonus
    local real dam

    local integer towerChainCount = 0
    local TowerChainArray towerChain = TowerChainArray.create()

    local integer i

    local unit attacker = GetEventDamageSource()

    local CleanupData cleanupData
    
    //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

    //Get available towers and add them to the array.
    set CurrentTower = attacker
    set TowerValues[GetUnitIndex(CurrentTower)] = 1
    set towerChain[0] = CurrentTower
    
    set x = GetUnitX(CurrentTower)
    set y = GetUnitY(CurrentTower)
    
    call GroupClear(EmptyGroup)
    if GetUnitTypeId(attacker)==TOWER_GOLEM then
        call GroupEnumUnitsInRange(EmptyGroup, x, y, RANGE, Condition(function TowerFilter1))
    elseif GetUnitTypeId(attacker)==TOWER_ABOMINATION then
        call GroupEnumUnitsInRange(EmptyGroup, 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(EmptyGroup,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[i - 1])

        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 cleanupData = CleanupData.create()
    set cleanupData.data = towerChain
    set cleanupData.size = towerChainCount

    set attacker = null
    
    call TimedEvent(COOLDOWN, integer(cleanupData), Callback.CleanUp)
endfunction

//==== 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

endscope

//==============================
//  Credit to grim001 for TimedEvent library.
//==============================
library TimedEvent initializer Init

globals
 //***   Configuration   ***
 private integer NumberOfTimers = 100
 //*** End Configuration ***

 private integer array TAGS
 private Callback array CALLBACKS
 private timer array TIMERS
 private integer N = 0
endglobals

function interface Callback takes integer tag returns boolean

private function H2I takes handle h returns integer
    return h
    return 0
endfunction

private function TimedEventExpires takes nothing returns nothing
 local timer t = GetExpiredTimer()
 local integer i = H2I(t)-0x100000
    if not CALLBACKS[i].evaluate(TAGS[i]) then
        call PauseTimer(t)
        set N = N + 1
        set TIMERS[N] = t
    endif
endfunction

function TimedEvent takes real delay, integer tag, Callback callback returns nothing
 local timer t
 local integer i
    if N == 0 then
        call BJDebugMsg("TimedEvent Error: Maximum numbers of timers ("+I2S(NumberOfTimers)+") exceeded")
        return
    else
        set t = TIMERS[N]
        set N = N-1
    endif
    set i = H2I(t)-0x100000
    set TAGS[i] = tag
    set CALLBACKS[i] = callback
    call TimerStart(t, delay, true, function TimedEventExpires)
endfunction

private function Init takes nothing returns nothing
 loop
     set TIMERS[N] = CreateTimer()
     exitwhen N == NumberOfTimers-1
     set N = N + 1
 endloop
endfunction

endlibrary
08-18-2008, 04:52 AM#3
Karawasa
Thanks for the help Ammorth.
08-18-2008, 07:42 AM#4
Karawasa
I'm running into an odd problem with the damage calculation.

Collapse JASS:
//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.)

With:

BASE1 = 4000
DAMAGE1 = 800
towerChainCount = 5
power = 1.05*1.05*1.05*1.05*1.05 = 1.27
bonus = 1

With these values I am getting 20000+ damage per attack with 5 "Links" out. It should be around 9000-10000.
08-18-2008, 08:01 AM#5
darkwulfv
Quote:
power = 1.05*1.05*1.05*1.05*1.05 = 1.34
Wrong, it equals ~1.276

Also, armor types could be interfering with the DAMAGE_TYPE/ATTACK_TYPE constants, but that's only a guess.

How much is "Damage2"?

Maybe you made a typo with your constants (Damage1) and it's 8000 instead of 800? Just another guess.
08-18-2008, 08:20 AM#6
Karawasa
Quote:
Originally Posted by darkwulfv
Wrong, it equals ~1.276

Also, armor types could be interfering with the DAMAGE_TYPE/ATTACK_TYPE constants, but that's only a guess.

How much is "Damage2"?

Maybe you made a typo with your constants (Damage1) and it's 8000 instead of 800? Just another guess.

Post edited.

Armor types not a factor for levels I tested it with. Damage2 is 4000. Damage1 is 800.

Still clueless :(.
08-18-2008, 08:28 AM#7
darkwulfv
Well, if for some reason Damage2 is getting mixed up with Damage1 somehow, then it would equal well over 20000.

Maybe your TOWER_GOLEM and TOWER_ABOMINATION constants have mixed up values?
08-18-2008, 08:42 AM#8
Karawasa
Collapse JASS:
//======================================================================
// Prism Tower
//======================================================================

scope Prism

//=======================
// Configuration Header
//=======================
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 = 800.0 //This is how much damage a powering up tower does.
    private constant real DAMAGE2 = 4000.0 //This is how much damage a powering up tower does.
    private constant real BASE1 = 4000.0 //This is how much damage an attacking tower does normally.
    private constant real BASE2 = 20000.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.2 //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
//=======================
// End Config Header
//=======================

// moved above global block so we don't have to use keywords for declaration of global
type TowerChainArray extends unit array[100]

globals
    private unit CurrentTower = null
    private integer array TowerValues
    private group EmptyGroup = CreateGroup()

// the temp globals which we will use to transfer data
    private TowerChainArray tempArray
    private real tempPower
    private integer tempCount
    
endglobals



private struct CleanupData
    TowerChainArray data
    integer size
endstruct

private function CleanUp takes integer tag returns boolean
    local TowerChainArray towerChain = CleanupData(tag).data
    local integer i = CleanupData(tag).size

    call CleanupData.destroy(CleanupData(tag))

    loop
        exitwhen i < 0

        call UnitRemoveAbility(towerChain[i], PWRUPID)
        set TowerValues[GetUnitIndex(towerChain[i])] = 0

        set towerChain[i] = null

        set i = i - 1
    endloop

    return false
endfunction

private function TowerFilter1 takes nothing returns boolean
    return GetOwningPlayer(GetFilterUnit()) == GetOwningPlayer(GetEventDamageSource()) and GetUnitTypeId(GetFilterUnit()) == TOWERID_1 and TowerValues[GetUnitIndex(GetFilterUnit())] != 1 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())] != 1 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 * tempPower
    set tempCount = tempCount + 1
    set tempArray[tempCount] = GetEnumUnit()
    set TowerValues[GetUnitIndex(GetEnumUnit())] = 1
endfunction

function Trig_Prism_Actions takes nothing returns nothing
    local real x = GetUnitX(GetEventDamageSource())
    local real y = GetUnitY(GetEventDamageSource())
    local real x1
    local real y1

    local real power = EXPONENT
    local real bonus
    local real dam

    local integer towerChainCount = 0
    local TowerChainArray towerChain = TowerChainArray.create()

    local integer i

    local unit attacker = GetEventDamageSource()

    local CleanupData cleanupData
    
    //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

    //Get available towers and add them to the array.
    set CurrentTower = attacker
    set TowerValues[GetUnitIndex(CurrentTower)] = 1
    set towerChain[0] = CurrentTower
    
    set x = GetUnitX(CurrentTower)
    set y = GetUnitY(CurrentTower)
    
    call GroupClear(EmptyGroup)
    if GetUnitTypeId(attacker)==TOWER_GOLEM then
        call GroupEnumUnitsInRange(EmptyGroup, x, y, RANGE, Condition(function TowerFilter1))
    elseif GetUnitTypeId(attacker)==TOWER_ABOMINATION then
        call GroupEnumUnitsInRange(EmptyGroup, 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(EmptyGroup,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])

        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 cleanupData = CleanupData.create()
    set cleanupData.data = towerChain
    set cleanupData.size = towerChainCount

    set attacker = null
    
    call TimedEvent(COOLDOWN, integer(cleanupData), Callback.CleanUp)
endfunction

//==== 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

endscope

//==============================
//  Credit to grim001 for TimedEvent library.
//==============================
library TimedEvent initializer Init

globals
 //***   Configuration   ***
 private integer NumberOfTimers = 100
 //*** End Configuration ***

 private integer array TAGS
 private Callback array CALLBACKS
 private timer array TIMERS
 private integer N = 0
endglobals

function interface Callback takes integer tag returns boolean

private function H2I takes handle h returns integer
    return h
    return 0
endfunction

private function TimedEventExpires takes nothing returns nothing
 local timer t = GetExpiredTimer()
 local integer i = H2I(t)-0x100000
    if not CALLBACKS[i].evaluate(TAGS[i]) then
        call PauseTimer(t)
        set N = N + 1
        set TIMERS[N] = t
    endif
endfunction

function TimedEvent takes real delay, integer tag, Callback callback returns nothing
 local timer t
 local integer i
    if N == 0 then
        call BJDebugMsg("TimedEvent Error: Maximum numbers of timers ("+I2S(NumberOfTimers)+") exceeded")
        return
    else
        set t = TIMERS[N]
        set N = N-1
    endif
    set i = H2I(t)-0x100000
    set TAGS[i] = tag
    set CALLBACKS[i] = callback
    call TimerStart(t, delay, true, function TimedEventExpires)
endfunction

private function Init takes nothing returns nothing
 loop
     set TIMERS[N] = CreateTimer()
     exitwhen N == NumberOfTimers-1
     set N = N + 1
 endloop
endfunction

endlibrary

Here is the entire code. The variables are not getting mixed up, as I have tested it. With 5 "Links" near an attacker, I get a damage of about 21000 when it should be 9000.
08-18-2008, 09:11 AM#9
Themerion
Your math is wrong.

Collapse TowerForGroup:
    set tempPower = tempPower * tempPower

Should be:

Collapse TowerForGroup:
set tempPower=tempPower*EXPONENT
08-18-2008, 09:25 AM#10
Karawasa
Quote:
Originally Posted by Themerion
Your math is wrong.

Collapse TowerForGroup:
    set tempPower = tempPower * tempPower

Should be:

Collapse TowerForGroup:
set tempPower=tempPower*EXPONENT

Genius, thank you.