HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Criticism of summon controller

08-29-2008, 07:07 AM#1
fX_
ok im gonna be implementing some substantial amount of summon-a-guy-follow-me-do-function spells so i made some general system for controlling them. i need criticism so i can fix this before proceeding to make the spells; i don't want to fix this then put in syntax every instance of this in the spells.

Collapse JASS:
library Summon

globals
    private timer gTIM = CreateTimer()
    private real gR_DurationTimer = 0.50
    ///////////////////
    private integer gINT_CountSummon = 0
    private Summon array gSUMMON
endglobals

private struct Summon
    integer intSummonIndex
    unit uSummon
    unit uCaster
    player pOwnerCaster
    ///////////////////
    boolean boolFollow
    boolean boolFormation
    boolean boolFocusFire
    boolean boolSharedDeath
    ///////////////////
    real rMaxOffsetDistance
    real rOffsetAngle //set to a negative value to generate random angles when following.//
    real rOffsetDistance //set to a negative value to generate random distances when following.//
    real rXHome
    real rYHome
    ///////////////////
    string strOrder
    boolexpr boolexprFilterTarget
    
    method Destroy takes nothing returns nothing
        set this.uSummon = null
        set this.uCaster = null
        set this.pOwnerCaster = null
        set this.boolExprFilterTarget = null
        ///////////////////
        set gSUMMON[gINT_CountSummon].intSummonIndex = this.intSummonIndex
        set gSUMMON[this.intSummonIndex] = gSUMMON[gINT_CountSummon]
        set gSUMMON[gINT_CountSummon] = 0
        set gINT_CountSummon = gINT_CountSummon - 1
        if gINT_CountSummon == 0 then
            call PauseTimer(gTIM)
        endif
    endmethod
    
    method Action takes string order, handle target returns nothing
        if target == null then
            call IssueImmediateOrder(this.uSummon, order)
        elseif GetWidgetLife(target) >= 0 or GetWidgetLife(target) <= 0 then
            call IssueTargetOrder(this.uSummon, order, target)
        else
            call IssuePointOrderLoc(this.uSummon, order, target)
        endif
    endfunction
    
    method Move takes real x, real y, real dist, real angle nothing returns nothing
        local real R_OffsetAngle
        local real R_OffsetDistance
        local location LOC_Target
        if dist >= 0.00 then
            set R_OffsetDistance = dist
        else
            set R_OffsetDistance = GetRandomReal(0.00, this.rMaxOffsetDistance)
        endif
        if angle >= 0 then
            set R_OffsetAngle = GetUnitFacing(this.uCaster) - 90.00 + angle
        else
            set R_OffsetAngle = GetRandomReal(0.00, 360.00)
        endif
        set LOC_Target = Location(R_XCaster + R_OffsetDistance * Cos(R_OffsetAngle * bj_DEGTORAD), R_YCaster + R_OffsetDistance * Sin(R_OffsetAngle * bj_DEGTORAD))
        call this.Action("move", LOC_Target)
        call RemoveLocation(LOC_Target)
    endmethod
   
    method Execute takes nothing returns nothing
        local real R_XCaster = GetUnitX(this.uCaster)
        local real R_YCaster = GetUnitY(this.uCaster)
        local real R_OffsetDistance = SquareRoot(Pow(GetUnitY((this.uSummon) - R_XCaster), 2) + Pow((GetUnitX(this.uSummon) - R_YCaster), 2))
        local group UG_Target = CreateGroup()
        local handle HAND_Target
        if GetUnitState(this.uSummon, UNIT_STATE_LIFE) <= 0 or GetOwningPlayer(this.uSummon) != this.pOwnerCaster then
            call this.Destroy()
        elseif GetUnitState(this.uCaster, UNIT_STATE_LIFE) <= 0
            if this.boolSharedDeath then
                call KillUnit(this.uSummon)
            else
                call this.Move(this.rXHome, this.rYHome, 0.00, 0.00)
            endif
        else
            if R_OffsetDistance > this.rMaxOffsetDistanceMove then
                call this.Move(R_XCaster, R_YCaster, this.rOffsetDistance, this.rOffsetAngle)
            elseif OrderId2String(GetUnitCurrentOrder(this.uSummon)) != this.strOrder then
                call GroupEnumUnitsInRange(UG_Target, R_XCaster, R_YCaster, this.rMaxDistanceOffset, this.boolexprFilterTarget)
                set HAND_Target = FirstOfGroup(UG_Target)
                call this.Action(this.strOrder, HAND_Target)
            endif
        endif
        call DestroyGroup(UG_Target)
        set HAND_Target = null
    endmethod
endstruct

private function Callback1 takes nothing returns nothing
    local integer INT_CountSummon = 0
    loop
        set INT_CountSummon = INT_CountSummon + 1
        call gSUMMON[INT_CountSummon].Execute()
        exitwhen INT_CountSummon == gINT_CountSummon
    endloop
endfunction

private function Trig_OrderParity_Actions takes nothing returns nothing
    local unit U_Caster = GetTriggerUnit()
    local integer INT_CountSummon = 0
    local string STR_Order = OrderId2String(GetIssuedOrderId())
    local widget WID_Target = GetOrderTarget()
    loop
        set INT_CountSummon = INT_CountSummon + 1
        if gSUMMON[INT_CountSummon].uCaster == U_Caster then
            if STR_Order == "move" or (STR_Order == "smart" and WID_Target == null) and gSUMMON[INT_CountSummon].boolFormation == TRUE then
                call gSUMMON[INT_CountSummon].Move(GetOrderPointX(), GetOrderPointY(), gSUMMON[INT_CountSummon].rOffsetDistance, gSUMMON[INT_CountSummon].rOffsetAngle)
            elseif (STR_Order == "attack" or (STR_Order == "smart" and IsUnitEnemy(WID_Target, gSUMMON[INT_CountSummon].pOwnerCaster))) and gSUMMON[INT_CountSummon].boolFocusFire == TRUE then
                call gSUMMON[INT_CountSummon].Action("attack", WID_Target)
            endif
        endif
        exitwhen INT_CountSummon == gINT_CountSummon
    endloop
    set STR_Order = null
    set WID_Target = null
    set U_Caster = null
endfunction

//==== Init Trigger OrderParity ====
private function InitTrig_OrderParity takes nothing returns nothing
    local integer INT_CountPlayer = 0
    set gg_trg_OrderParity = CreateTrigger()
    loop
        call TriggerRegisterPlayerUnitEvent(gg_trg_OrderParity, Player(INT_CountPlayer) EVENT_PLAYER_UNIT_ISSUED_ORDER)
        exitwhen INT_CountPlayer == 12
        set INT_CountPlayer = INT_CountPlayer + 1
    endloop
    call TriggerAddAction(gg_trg_OrderParity, function Trig_OrderParity_Actions)
endfunction

//-----------------------//FUNCTIONS//-----------------------//
function SummonCreate takes unit summon, unit caster, boolean follow, boolean form, boolean ff, boolean sharedDeath, real maxDist, real dist, real angle, real x, real y, string order, boolexpr targetFilter returns Summon
    local Summon New = Summon.allocate()
    set gINT_CountSummon = gINT_CountSummon + 1
    set New.intSummonIndex = gINT_CountSummon
    set New.uSummon = summon
    set New.uCaster = caster
    set New.pOwnerCaster = GetOwningPlayer(caster)
    set New.boolFollow = Move
    set New.boolFormation = form
    set New.boolFocusFire = ff
    set New.boolSharedDeath = sharedDeath
    set New.rMaxOffsetDistance = maxDist
    set New.rOffsetDistance = dist
    set New.rOffsetAngle = angle
    set New.rXHome = x
    set New.rYHome = y
    set New.strOrder = order
    set New.boolexprFilterTarget = targetFilter
    return New
    if gINT_CountSummon == 1 then
        call TimerStart(gTIM, gR_DurationTimer, TRUE, function Callback1)
    endif
endfunction

function SummonDestroy takes Summon whichSummon, returns nothing
    call Summon.Destroy()
endfunction

function SummonOrder takes Summon whichSummon, string order, handle target returns nothing
    call whichSummon.Action(order, target)
endfunction

function SummonChangeOwner takes Summon whichSummon, player newOwner returns nothing
    set whichSummon.uCaster = newOwner
    set whichSummon.pOwnerCasterCaster = GetOwningPlayer(newOwner)
endfunction

function SummonChangeFollow takes Summon whichSummon, boolean newFollow returns nothing
    set whichSummon.boolFollow = newFollow
endfunction

function SummonChangeFormation takes Summon whichSummon, boolean newForm returns nothing
    set whichSummon.boolFormation = newForm
endfunction

function SummonSharedDeath takes Summon whichSummon, boolean newDeath returns nothing
    set whichSummon.boolSharedDeath = newDeath
endfunction

function SummonChangeFocusFire takes Summon whichSummon, boolean newFF returns nothing
    set whichSummon.boolFocusFire = newFF
endfunction

function SummonChangeVectors takes Summon whichSummon, real newMaxDist, real newDist, real newAngle, real newHomeX, real newHomeY returns nothing
    set whichSummon.rMaxOffsetDistance = newMaxDist
    set whichSummon.rOffsetDistance = newDist
    set whichSummon.rAngleDistance = newAngle
    set whichSummon.rXHome = newHomeX
    set whichSummon.rYHome = newHomeY
endfunction

function SummonChangeOrder takes Summon whichSummon, string newOrder, boolexpr newFilter returns nothing
    set whichSummon.strOrder = newOrder
    set whichSummon.boolexprFilterTarget = newFilter
endfunction

endlibrary
09-02-2008, 02:11 AM#2
fX_
edit: 2nd post is also a bump from 2nd page btw

changed it a bit. i still need to know if it's ok.

i want to know particularly about this part, w/c is supposed to find a random suitable target loc within the AoE around a certain point:

Collapse JASS:
set R_XQuery = R_XSummon - this.rRangeAoE
            loop
                exitwhen R_XQuery > R_XSummon + this.rRangeAoE
                set R_MaxDistanceOffX = SquareRoot(Pow(this.RangeAoE, 2) - Pow(R_XQuery, 2))
                set R_YQuery = R_YSummon - R_MaxDistanceOffX
                loop
                    exitwhen R_YQuery > RY_Summon + R_MaxDistanceOffX
                    //Evaluate//
                    if this.boolexprFilterOrderTarget(R_XQuery, R_YQuery) then
                        set INT_CountTarget = INT_CountTarget + 1
                        set R_XTarget[INT_CountTarget] = R_XQuery
                        set R_YTarget[INT_CountTarget] = R_YQuery
                    endif
                    set R_XQuery = R_XQuery + gR_DistanceIncrement
                endloop
                set R_XQuery = R_XQuery + gR_DistanceIncrement
            endloop
            set INT_Randomizer = GetRandomReal(1, INT_CountTarget)
            set HAND_Target = Location(R_XTarget[INT_Randomizer], R_YTarget[INT_Randomizer])

Collapse JASS:
library Summon

globals
    private timer gTIM = CreateTimer()
    private constant real gR_DurationTimer = 0.50
    private constant real gR_DistanceIncrement = 100.00
    
    private integer gINT_CountSummon = 0
    private Summon array gSUMMON
    private constant string gSTR_OrderTargetTypeUnit = "unit"
    private constant string gSTR_OrderTargetTypeLocation = "location"
endglobals

private struct Summon
    integer intSummonIndex
    unit uSummon
    unit uCaster
    player pOwnerCaster
    
    boolean boolFollow
    boolean boolFormationFollow
    real rDistanceMove
    real rAngleMove
    real rMaxDistanceMove
    boolean boolGoHome
    real rXHome
    real rYHome
    
    boolean boolFocusAttack
    string strOrderTargetType
    string strOrder
    boolexpr boolexprFilterOrderTarget
    real rRangeAoE
    
    method Destroy takes nothing returns nothing
        set this.uSummon = null
        set this.uCaster = null
        set this.pOwnerCaster = null
        set this.strOrderTargetType = null
        set this.strOrder = null
        set this.boolexprFilterOrderTarget = null
        
        set gSUMMON[gINT_CountSummon].intSummonIndex = this.intSummonIndex
        set gSUMMON[this.intSummonIndex] = gSUMMON[gINT_CountSummon]
        set gSUMMON[gINT_CountSummon] = 0
        set gINT_CountSummon = gINT_CountSummon - 1
        if gINT_CountSummon == 0 then
            call PauseTimer(gTIM)
        endif
    endmethod
    
    private method CheckNotBusy takes Summon whichSummon returns boolean
        return OrderId2String(GetUnitCurrentOrder(whichSummon.uSummon)) != whichSummon.strOrder
    endmethod
    
    static method Order takes Summon whichSummon, string order, handle target returns nothing
        local location LOC_Target
        if target == null then
            call IssueImmediateOrder(whichSummon.uSummon, order)
        elseif GetWidgetLife(target) > 0 then
            call IssueTargetOrder(whichSummon.uSummon, order, target)
        else
            set LOC_Target = target
            IssuePointOrder(whichSummon.uSummon, order, GetLocationX(LOC_Target), GetLocationY(LOC_Target))
        endif
        call RemoveLocation(LOC_Target)
    endmethod
    
    private method Follow takes nothing returns nothing
        local real R_Distance
        local real R_Angle
        local location LOC_Target
        if this.rDistanceMove >= 0.00 then
            set R_Distance = this.rDistanceMove
        else
            set R_Distance = GetRandomReal(0.00, this.rMaxDistanceMove)
        endif
        if this.rAngle >= 0.00 then
            set R_Angle = this.rAngleMove
        else
            set R_Angle = GetRandomReal(0.00, 360.00)
        endif
        set R_Angle = (GetUnitFacing(this.uCaster) - 90.00 + R_Angle) * bj_DEGTORAD
        set LOC_Target = Location(GetUnitX(this.uCaster) + R_Distance * Cos(R_Angle), GetUnitY(this.uCaster) + R_Distance * Sin(R_Angle))
        call Summon.Order(gSUMMON[this.intSummonIndex], "move", LOC_Target)
        call RemoveLocation(LOC_Target)
    endmethod
    
    private method GoHome takes nothing returns nothing
        local location LOC_Target = Location(this.rXHome, this.rYHome)
        call OSummon.rder(gSUMMON[this.intSummonIndex], "move", LOC_Target)
        call RemoveLocation(LOC_Target)
    endmethod

    private method Action takes nothing returns nothing
        local group UG_Target       
        local handle HAND_Target
        local real R_XSummon = GetUnitX(U_Summon)
        local real R_YSummon = GetUnitY(U_Summon)
        local real array R_XTarget
        local real array R_YTarget
        local real R_XQuery
        local real R_YQuery
        local real R_MaxDistanceOffX
        local integer INT_CountTarget
        local integer INT_Randomizer
        if this.strOrderTargetType == gSTR_OrderTargetTypeUnit then
            call GroupEnumUnitsInRange(UG_Target, R_XSummon), R_YSummon, this.rRangeAoE, Filter(function this.boolexprFilterOrderTarget))
            set HAND_Target = FirstOfGroup(UG_Target)
        elseif this.strOrderTargetType == gSTR_OrderTargetTypeLocation then
            set R_XQuery = R_XSummon - this.rRangeAoE
            loop
                exitwhen R_XQuery > R_XSummon + this.rRangeAoE
                set R_MaxDistanceOffX = SquareRoot(Pow(this.RangeAoE, 2) - Pow(R_XQuery, 2))
                set R_YQuery = R_YSummon - R_MaxDistanceOffX
                loop
                    exitwhen R_YQuery > RY_Summon + R_MaxDistanceOffX
                    //Evaluate//
                    if this.boolexprFilterOrderTarget(R_XQuery, R_YQuery) then
                        set INT_CountTarget = INT_CountTarget + 1
                        set R_XTarget[INT_CountTarget] = R_XQuery
                        set R_YTarget[INT_CountTarget] = R_YQuery
                    endif
                    set R_XQuery = R_XQuery + gR_DistanceIncrement
                endloop
                set R_XQuery = R_XQuery + gR_DistanceIncrement
            endloop
            set INT_Randomizer = GetRandomReal(1, INT_CountTarget)
            set HAND_Target = Location(R_XTarget[INT_Randomizer], R_YTarget[INT_Randomizer])
        else
            set HAND_Target = null
        endif
        call Summon.Order(gSUMMON[this.intSummonIndex], this.strOrder, HAND_Target)
        set HAND_Target = null
        call DestroyGroup(UG_Target)
    endmethod
    
    method Execute takes nothing returns nothing
        if GetUnitState(this.uSummon, UNIT_STATE_LIFE) > 0 and GetOwningPlayer(this.uSummon) == this.pOwnerCaster then
            if this.Follow and SquareRoot(Pow(GetUnitY(this.uSummon) - GetUnitY(this.uCaster), 2) + Pow(GetUnitX(this.uSummon) - GetUnitX(this.uCaster), 2)) > this.rMaxDistanceMove then
                if GetUnitState(this.uCaster, UNIT_STATE_LIFE) <= 0 and this.boolGoHome then
                    call this.GoHome()
                else
                    call this.Follow()
                endif
            else
                //If he's not busy, give him something to do.//
                if CheckNotBusy(gSUMMON[this.intSummonIndex]) then
                    call this.Action()
                endif
            endif
        else
            call this.Destroy()
        endif
    endmethod
endstruct

private function Callback1 takes nothing returns nothing
    local integer INT_CountSummon = 0
    loop
        set INT_CountSummon = INT_CountSummon + 1
        call gSUMMON[INT_CountSummon].Execute()
        exitwhen INT_CountSummon == gINT_CountSummon
    endloop
endfunction



//////////////////////////////////////////////////////////////////////
////////====================CONSOLE====================///////////////

function SummonCreate takes unit summon, unit caster, boolean follow, boolean formationFollow, real distanceFollow, real maxDistanceFollow, real angleFollow, boolean goHome, real xHome, real yHome, boolean focusAttack, string targetType, string order, boolexpr targetFilter, real rangeTarget returns Summon
    local Summon New = Summon.allocate()
    set gINT_CountSummon = gINT_CountSummon + 1
    set New.intSummonIndex = gINT_CountSummon
    set New.uSummon = summon
    set New.uCaster = caster
    set New.pOwnerCaster = GetOwningPlayer(caster)
    set New.boolFollow = follow
    set New.boolFormationFollow = formationFollow
    set New.rDistanceMove = distanceFollow
    set New.rAngleMove = angleFollow
    if (not formationFollow and randomMove) or (formationFollow and randomMove and (distanceFollow < 0.00 or angleFollow < 0.00)) then
        set New.boolFormationFollow = FALSE
        if distanceFollow < 0.00 then
            set New.rDistanceMove = -1.00
        endif
        if angleFollow < 0.00 then
            set New.rAngleMove = -1.00
        endif
    endif
    set New.rMaxDistanceMove = maxDistanceFollow
    set New.boolGoHome = goHome
    set New.rXHome = xHome
    set new.rYHome = yHome
    set New.boolAttack = attack
    set New.boolFocusAttack = focusAttack
    if targetType == gSTR_OrderTargetTypeUnit or targetType == gSTR_OrderTargetTypeLocation then
        set New.strOrderTargetType = targetType
    else
        set New.strOrderTargetType = null
    endif
    set New.strOrder = order
    set New.boolexprFilterOrderTarget = targetFilter
    set New.rRangeAoE = rangeTarget
    return New
    if gINT_CountSummon == 1 then
        call TimerStart(gTIM, gR_DurationTimer, TRUE, function Callback1)
    endif
endfunction

function SummonCreateMove takes unit summon, unit caster, boolean formationFollow, boolean randomMove, real distanceFollow, real maxDistanceFollow, real angleFollow returns Summon
    local Summon New = Summon.allocate()
    set gINT_CountSummon = gINT_CountSummon + 1
    set New.intSummonIndex = gINT_CountSummon
    set New.uSummon = summon
    set New.uCaster = caster
    set New.pOwnerCaster = GetOwningPlayer(caster)
    set New.boolFollow = TRUE
    set New.boolFormationFollow = formationFollow
    set New.rDistanceMove = distanceFollow
    set New.rAngleMove = angleFollow
    if (not formationFollow and randomMove) or (formationFollow and randomMove and (distanceFollow < 0.00 or angleFollow < 0.00)) then
        set New.boolFormationFollow = FALSE
        if distanceFollow < 0.00 then
            set New.rDistanceMove = -1.00
        endif
        if angleFollow < 0.00 then
            set New.rAngleMove = -1.00
        endif
    endif
    set New.rMaxDistanceMove = maxDistanceFollow
    set New.boolGoHome = FALSE
    set New.rXHome = 0.00
    set new.rYHome = 0.00
    set New.boolFocusAttack = FALSE
    set New.strOrderTargetType = null
    set New.strOrder = null
    set New.boolexprFilterOrderTarget = null
    set New.rRangeAoE = 0.00
    return New
    if gINT_CountSummon == 1 then
        call TimerStart(gTIM, gR_DurationTimer, TRUE, function Callback1)
    endif
endfunction

function SummonCreateOrder takes unit summon, unit caster, boolean focusAttack, string targetType, string order, boolexpr targetFilter, real rangeTarget returns Summon
    local Summon New = Summon.allocate()
    set gINT_CountSummon = gINT_CountSummon + 1
    set New.intSummonIndex = gINT_CountSummon
    set New.uSummon = summon
    set New.uCaster = caster
    set New.pOwnerCaster = GetOwningPlayer(caster)
    set New.boolFollow = FALSE
    set New.boolFormationFollow = FALSE
    set New.rDistanceMove = 0.00
    set New.rAngleMove = 0.00
    set New.rMaxDistanceMove = 0.00
    set New.boolFocusAttack = focusAttack
    if targetType == gSTR_OrderTargetTypeUnit or targetType == gSTR_OrderTargetTypeLocation then
        set New.strOrderTargetType = targetType
    else
        set New.strOrderTargetType = null
    endif
    set New.strOrder = order
    set New.boolexprFilterOrderTarget = targetFilter
    set New.rRangeAoE = rangeTarget
    return New
    if gINT_CountSummon == 1 then
        call TimerStart(gTIM, gR_DurationTimer, TRUE, function Callback1)
    endif
endfunction

function SummonDestroy takes Summon whichSummon, returns nothing
    call whichSummon.Destroy()
endfunction

function SummonFind takes unit summonUnit returns Summon
    local integer INT_CountSummon = 0
    loop
        set INT_CountSummon = INT_CountSummon + 1
        if gSUMMON[INT_CountSummon].uSummon == summonUnit then
            return gSUMMON[INT_CountSummon]
        endif
        exitwhen INT_CountSummon == gINT_CountSummon
    endloop
    return 0
endfunction

function SummonOrder takes Summon whichSummon, string order, handle target returns nothing
    call Summon.Order(whichSummon, order, target)
endfunction

function SummonChangeProperty takes Summon whichSummon, unit newSummon, unit newCaster returns nothing
    set whichSummon.uSummon = newSummon
    set whichSummon.uCaster = newCaster
    set whichSummon.pOwnerCaster = GetOwningPlayer(newCaster)
endfunction

function SummonChangeMove takes Summon whichSummon, boolean randomMove, boolean newFollow, boolean newFormation, real newDistance, real newAngle, real newMaxDistance, boolean newGoHome, real newXHome, real newYHome returns nothing
    set whichSummon.boolFollow = newFollow
    set whichSummon.boolFormationFollow = newFormation
    set whichSummon.rDistanceMove = newDistance
    set whichSummon.rAngleMove = newAngle
    if (not newFormation and randomMove) or (newFormationFollow and randomMove and (newDistance < 0.00 or newAngle < 0.00)) then
        set whichSummon.boolFormationFollow = FALSE
        if newDistance < 0.00 then
            set whichSummon.rDistanceMove = -1.00
        endif
        if newAngle < 0.00 then
            set whichSummon.rAngleMove = -1.00
        endif
    endif    
    set whichSummon.rMaxDistanceMove = newMaxDistance
    set whichSummon.boolGoHome = newGoHome
    set whichSummon.rXGoHome = newXHome
    set whichSummon.rYGoHome = newYHome
endfunction

function SummonChangeOrder takes Summon whichSummon, string newTargetType, string newOrder, boolexpr newTargetFilter, real newRange, boolean newFocusAttack returns nothing
    set whichSummon.strOrderTargetType = newTargetType
    set whichSummon.strOrder = newOrder
    set whichSummon.boolexprFilterOrderTarget = newTargetFilter
    set whichSummon.rRangeAoE = newRange
    set whichSummon.boolFocusAttack = newFocusAttack
endfunction

endlibrary

answers??
09-03-2008, 01:18 PM#3
Anitarf
Quote:
Originally Posted by fX_
i want to know particularly about this part, w/c is supposed to find a random suitable target loc within the AoE around a certain point:
Could you explain what makes the location suitable?
09-04-2008, 07:49 AM#4
fX_
specs prescribed in the boolexprFilterOrderTarget member, w/c should evaluate the coords by expressions concerning coords.

ex. for an aoe spell, evaluate if there are enemies in range of (x1, y1)

boolexprFilterOrderTarget(x1,y1)

call groupenumunitsinrange(enum group, x1, y1, range, filter isunitenemy)
u = firstofgroup(enumgroup)
if u != null then
return true
else
return false
endif



something like that
09-04-2008, 07:41 PM#5
Anitarf
Collapse JASS:
                    ...
                    endif
                    set R_XQuery = R_XQuery + gR_DistanceIncrement
                endloop
                set R_XQuery = R_XQuery + gR_DistanceIncrement
                ...
I take it the first line is supposed to be Y, not X.

Anyway, this grid search seems very unoptimized. You sample the entire area and create a list of acceptable locations and then pick one at random. There are many better ways of doing this.

One is to simply pick points at random and use the first one that's acceptable. As long as a large percentage of points are acceptable it is also much faster than what you have now. It is only problematic when you have few or no acceptable locations, in that case using a linear search is better.

However, even as far as linear searches go, you could do better. You could simply pick a random point in the grid to start your linear search and then go from there and select the first point that you find that matches the criteria. The only problem here would be that acceptable points that come after a long string of unacceptable ones in the search have a higher probability of being picked, but you can remedy that by using a different search pattern (left to right, right to left, up to down, down to up, diagonally...) every time.
09-05-2008, 12:59 AM#6
fX_
i dont like the random search idea coz it doesnt seem reliable.

by linear search you mean to sweep-scan like a radar?
i can 'rotate' a line around the point, and at each instance of the turn (every x degrees) evaluate each point on the line every delta-distance from the point the line is rotated about? this will yield
a suitable point closer to the target more immediately (w/c is probably a good thing).
but: therell be overkill checking for points closer to the center and possible omission of points further out of the center, depending on the rOrderAoE

???


edit:

Collapse JASS:
library Summon

globals
    private timer gTIM = CreateTimer()
    private constant real gR_DurationTimer = 0.50
    private constant real gR_AngleIncrement = 36.00
    
    private integer gINT_CountSummon = 0
    private Summon array gSUMMON
    private constant string gSTR_OrderTargetTypeUnit = "unit"
    private constant string gSTR_OrderTargetTypeLocation = "location"
endglobals

private struct Summon
    integer intSummonIndex
    unit uSummon
    unit uCaster
    player pOwnerCaster
    
    boolean boolFollow
    boolean boolFormationFollow
    real rDistanceMove
    real rAngleMove
    real rMaxDistanceMove
    boolean boolGoHome
    real rXHome
    real rYHome
    
    boolean boolFocusAttack
    string strOrderTargetType
    string strOrder
    real rOrderAoE
    boolexpr boolexprFilterOrderTarget
    real rRangeAoE
    
    method Destroy takes nothing returns nothing
        set this.uSummon = null
        set this.uCaster = null
        set this.pOwnerCaster = null
        set this.strOrderTargetType = null
        set this.strOrder = null
        set this.boolexprFilterOrderTarget = null
        
        set gSUMMON[gINT_CountSummon].intSummonIndex = this.intSummonIndex
        set gSUMMON[this.intSummonIndex] = gSUMMON[gINT_CountSummon]
        set gSUMMON[gINT_CountSummon] = 0
        set gINT_CountSummon = gINT_CountSummon - 1
        if gINT_CountSummon == 0 then
            call PauseTimer(gTIM)
        endif
    endmethod
    
    private method CheckNotBusy takes Summon whichSummon returns boolean
        return OrderId2String(GetUnitCurrentOrder(whichSummon.uSummon)) != whichSummon.strOrder
    endmethod
    
    static method Order takes Summon whichSummon, string order, handle target returns nothing
        local location LOC_Target
        if target == null then
            call IssueImmediateOrder(whichSummon.uSummon, order)
        elseif GetWidgetLife(target) > 0 then
            call IssueTargetOrder(whichSummon.uSummon, order, target)
        else
            set LOC_Target = target
            IssuePointOrder(whichSummon.uSummon, order, GetLocationX(LOC_Target), GetLocationY(LOC_Target))
        endif
        call RemoveLocation(LOC_Target)
    endmethod
    
    private method Follow takes nothing returns nothing
        local real R_Distance
        local real R_Angle
        local location LOC_Target
        if GetUnitState(this.uCaster, UNIT_STATE_LIFE) <= 0 and this.boolGoHome then
            set LOC_Target = Location(this.rXHome, this.rYHome)
        else
            if this.rDistanceMove >= 0.00 then
                set R_Distance = this.rDistanceMove
            else
                set R_Distance = GetRandomReal(0.00, this.rMaxDistanceMove)
            endif
            if this.rAngle >= 0.00 then
                set R_Angle = this.rAngleMove
            else
                set R_Angle = GetRandomReal(0.00, 360.00)
            endif
            set R_Angle = (GetUnitFacing(this.uCaster) - 90.00 + R_Angle) * bj_DEGTORAD
            set LOC_Target = Location(GetUnitX(this.uCaster) + R_Distance * Cos(R_Angle), GetUnitY(this.uCaster) + R_Distance * Sin(R_Angle))
        endif
        call Summon.Order(gSUMMON[this.intSummonIndex], "move", LOC_Target)
        call RemoveLocation(LOC_Target)
    endmethod
    
    private method Action takes nothing returns nothing
        local handle HAND_Target
        local real R_XSummon = GetUnitX(U_Summon)
        local real R_YSummon = GetUnitY(U_Summon)
        local boolean BOOL_GotTarget = FALSE
        local group UG_Target = CreateGroup()
        local real R_XTarget
        local real R_YTarget
        local real R_OffsetAngle = 0.00
        local real R_OffsetDistance = 0.00
        if this.strOrderTargetType == gSTR_OrderTargetTypeUnit then
            call GroupEnumUnitsInRange(UG_Target, R_XSummon), R_YSummon, this.rRangeAoE, Filter(function this.boolexprFilterOrderTarget))
            set HAND_Target = FirstOfGroup(UG_Target)
            set BOOL_GotTarget = (HAND_Target != null)
        elseif this.strOrderTargetType == gSTR_OrderTargetTypeLocation then
            loop
                set R_OffsetDistance = R_OffsetDistance + this.rOrderAoE
                loop
                    set R_OffsetAngle = R_OffsetAngle + gR_AngleIncrement
                    set R_XTarget = R_XSummon + R_OffsetDistance * Cos(R_OffsetAngle * bj_DEGTORAD)
                    set R_YTarget = R_YSummon + R_OffsetDistance * Sin(R_OffsetAngle * bj_DEGTORAD)
                    if this.boolexprFilterOrderTarget(R_XTarget, R_YTarget) then
                        set BOOL_GotTarget = TRUE
                        set HAND_Target = Location(R_XTarget, R_YTarget)
                    endif
                    exitwhen R_OffsetAngle == 360.00 or BOOL_GotTarget
                endloop
                exitwhen R_OffsetDistance == this.rRangeAoE or BOOL_GotTarget
            endloop
        else
            call GroupEnumUnitsInRange(UG_Target, R_XSummon), R_YSummon, this.rRangeAoE, Filter(function this.boolexprFilterOrderTarget))
            set BOOL_GotTarget = (FirstOfGroup(UG_Target) != null)
            set HAND_Target = null
        endif
        if BOOL_GotTarget then
            call Summon.Order(gSUMMON[this.intSummonIndex], this.strOrder, HAND_Target)
        endif
        set HAND_Target = null
        call DestroyGroup(UG_Target)
    endmethod
    
    method Execute takes nothing returns nothing
        if GetUnitState(this.uSummon, UNIT_STATE_LIFE) > 0 and GetOwningPlayer(this.uSummon) == this.pOwnerCaster then
            if this.Follow and SquareRoot(Pow(GetUnitY(this.uSummon) - GetUnitY(this.uCaster), 2) + Pow(GetUnitX(this.uSummon) - GetUnitX(this.uCaster), 2)) > this.rMaxDistanceMove then
                call this.Follow()
            else
                if CheckNotBusy(gSUMMON[this.intSummonIndex]) then
                    call this.Action()
                endif
            endif
        else
            call this.Destroy()
        endif
    endmethod
endstruct

private function Callback1 takes nothing returns nothing
    local integer INT_CountSummon = 0
    loop
        set INT_CountSummon = INT_CountSummon + 1
        call gSUMMON[INT_CountSummon].Execute()
        exitwhen INT_CountSummon == gINT_CountSummon
    endloop
endfunction



//////////////////////////////////////////////////////////////////////
////////====================CONSOLE====================///////////////

function SummonCreate takes unit summon, unit caster, boolean follow, boolean formationFollow, real distanceFollow, real maxDistanceFollow, real angleFollow, boolean goHome, real xHome, real yHome, boolean focusAttack, string targetType, string order, real orderAOE, boolexpr targetFilter, real rangeTarget returns Summon
    local Summon New = Summon.allocate()
    set gINT_CountSummon = gINT_CountSummon + 1
    set New.intSummonIndex = gINT_CountSummon
    set New.uSummon = summon
    set New.uCaster = caster
    set New.pOwnerCaster = GetOwningPlayer(caster)
    if randomMove then
        set New.boolFollow = TRUE
        set New.boolFormationFollow = FALSE
        set New.rDistanceMove = -1.00
        set New.rAngleMove = -1.00
    else
        set New.boolFollow = follow
        set New.boolFormationFollow = formationFollow
        set New.rDistanceMove = distanceFollow
        set New.rAngleMove = angleFollow
    endif
    set New.rMaxDistanceMove = maxDistanceFollow
    set New.boolGoHome = goHome
    set New.rXHome = xHome
    set new.rYHome = yHome
    set New.boolAttack = attack
    set New.boolFocusAttack = focusAttack
    if targetType == gSTR_OrderTargetTypeUnit or targetType == gSTR_OrderTargetTypeLocation then
        set New.strOrderTargetType = targetType
    else
        set New.strOrderTargetType = null
    endif
    set New.strOrder = order
    set New.rOrderAoE = orderAOE
    set New.boolexprFilterOrderTarget = targetFilter
    set New.rRangeAoE = rangeTarget
    return New
    if gINT_CountSummon == 1 then
        call TimerStart(gTIM, gR_DurationTimer, TRUE, function Callback1)
    endif
endfunction

function SummonCreateMove takes unit summon, unit caster, boolean formationFollow, boolean randomMove, real distanceFollow, real maxDistanceFollow, real angleFollow, boolean goHome, real xHome, real yHome, returns Summon
    local Summon New = Summon.allocate()
    set gINT_CountSummon = gINT_CountSummon + 1
    set New.intSummonIndex = gINT_CountSummon
    set New.uSummon = summon
    set New.uCaster = caster
    set New.pOwnerCaster = GetOwningPlayer(caster)
    set New.boolFollow = TRUE
    if randomMove then
        set New.boolFormationFollow = FALSE
        set New.rDistanceMove = -1.00
        set New.rAngleMove = -1.00
    else
        set New.boolFormationFollow = formationFollow
        set New.rDistanceMove = distanceFollow
        set New.rAngleMove = angleFollow
    endif
    set New.rMaxDistanceMove = maxDistanceFollow
    set New.boolGoHome = goHome
    set New.rXHome = xHome
    set new.rYHome = yHome
    set New.boolFocusAttack = FALSE
    set New.strOrderTargetType = null
    set New.strOrder = null
    set New.rOrderAoE = 0.00
    set New.boolexprFilterOrderTarget = null
    set New.rRangeAoE = 0.00
    return New
    if gINT_CountSummon == 1 then
        call TimerStart(gTIM, gR_DurationTimer, TRUE, function Callback1)
    endif
endfunction

function SummonCreateOrder takes unit summon, unit caster, boolean focusAttack, string targetType, string order, real orderAOE, boolexpr targetFilter, real rangeTarget returns Summon
    local Summon New = Summon.allocate()
    set gINT_CountSummon = gINT_CountSummon + 1
    set New.intSummonIndex = gINT_CountSummon
    set New.uSummon = summon
    set New.uCaster = caster
    set New.pOwnerCaster = GetOwningPlayer(caster)
    set New.boolFollow = FALSE
    set New.boolFormationFollow = FALSE
    set New.rDistanceMove = 0.00
    set New.rAngleMove = 0.00
    set New.rMaxDistanceMove = 0.00
    set New.boolFocusAttack = focusAttack
    if targetType == gSTR_OrderTargetTypeUnit or targetType == gSTR_OrderTargetTypeLocation then
        set New.strOrderTargetType = targetType
    else
        set New.strOrderTargetType = null
    endif
    set New.strOrder = order
    set New.rOrderAoE = orderAOE
    set New.boolexprFilterOrderTarget = targetFilter
    set New.rRangeAoE = rangeTarget
    return New
    if gINT_CountSummon == 1 then
        call TimerStart(gTIM, gR_DurationTimer, TRUE, function Callback1)
    endif
endfunction

function SummonDestroy takes Summon whichSummon, returns nothing
    call whichSummon.Destroy()
endfunction

function SummonFind takes unit summonUnit returns Summon
    local integer INT_CountSummon = 0
    loop
        set INT_CountSummon = INT_CountSummon + 1
        if gSUMMON[INT_CountSummon].uSummon == summonUnit then
            return gSUMMON[INT_CountSummon]
        endif
        exitwhen INT_CountSummon == gINT_CountSummon
    endloop
    return 0
endfunction

function SummonOrder takes Summon whichSummon, string order, handle target returns nothing
    call Summon.Order(whichSummon, order, target)
endfunction

function SummonChangeProperty takes Summon whichSummon, unit newSummon, unit newCaster returns nothing
    set whichSummon.uSummon = newSummon
    set whichSummon.uCaster = newCaster
    set whichSummon.pOwnerCaster = GetOwningPlayer(newCaster)
endfunction

function SummonChangeMove takes Summon whichSummon, boolean randomMove, boolean newFollow, boolean newFormation, real newDistance, real newAngle, real newMaxDistance, boolean newGoHome, real newXHome, real newYHome returns nothing
    set whichSummon.boolFollow = newFollow
    set whichSummon.boolFormationFollow = newFormation
    set whichSummon.rDistanceMove = newDistance
    set whichSummon.rAngleMove = newAngle
    if (not newFormation and randomMove) or (newFormationFollow and randomMove and (newDistance < 0.00 or newAngle < 0.00)) then
        set whichSummon.boolFormationFollow = FALSE
        if newDistance < 0.00 then
            set whichSummon.rDistanceMove = -1.00
        endif
        if newAngle < 0.00 then
            set whichSummon.rAngleMove = -1.00
        endif
    endif    
    set whichSummon.rMaxDistanceMove = newMaxDistance
    set whichSummon.boolGoHome = newGoHome
    set whichSummon.rXGoHome = newXHome
    set whichSummon.rYGoHome = newYHome
endfunction

function SummonChangeOrder takes Summon whichSummon, string newTargetType, string newOrder, boolexpr newTargetFilter, real newRange, boolean newFocusAttack returns nothing
    set whichSummon.strOrderTargetType = newTargetType
    set whichSummon.strOrder = newOrder
    set whichSummon.boolexprFilterOrderTarget = newTargetFilter
    set whichSummon.rRangeAoE = newRange
    set whichSummon.boolFocusAttack = newFocusAttack
endfunction

endlibrary
09-05-2008, 11:12 AM#7
Anitarf
Quote:
Originally Posted by fX_
i dont like the random search idea coz it doesnt seem reliable.
As I said, it depends on how many points in the area are suitable targets. You can always just do a couple (like, five) random checks and if none of them gives you a suitable random coordinate, you switch to a different system; if they do, however, you have just saved a ton of time.
Quote:
by linear search you mean to sweep-scan like a radar?
You could use a polar coordinate system if you'd like, but you can also do this in a cartesian system like you're doing now.
Quote:
but: therell be overkill checking for points closer to the center and possible omission of points further out of the center, depending on the rOrderAoE
Not if you do it right.