HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Get(De)SelectingPlayer()

02-04-2009, 06:29 AM#1
fX_
Farms and Mills work differently in my map and I want them to take up a certain area in which no other Farms/Mills can be built. Auxiliary to this is a function that displays the area a Farm/Mill takes up when it is selected by a (any) player - like a blue circle pops-up around a Protoss Pylon in Starcraft as it is selected. This script determines which player has selected w/e unit.

If a unit is selected, it identifies the selecting player as the player has not had it selected but currently does. If a unit is deselected, it identifies the deselecting player as the player that has had it selected but currently does not. This method involves some indexing of selected units which seems like too much, are there any other simpler ways?

Collapse JASS:
library GetSelectionEventPlayer initializer Init

globals
    private constant integer MAX_INSTANCES = 8190

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//

    player bj_LastSelectingPlayer = null
    player bj_LastDeselectingPlayer = null
endglobals

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//

    function GetSelectingPlayer takes nothing returns player
        return bj_LastSelectingPlayer
    endfunction

    function GetDeselectingPlayer takes nothing returns player
        return bj_LastDeselectingPlayer
    endfunction

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//

    private keyword SelectedUnit

    private function Monitor takes nothing returns boolean
        local unit U = GetTriggerUnit()
        local SelectedUnit SU = SelectedUnit.Get(U)
        local integer INT_Index = 0
        local player P

        if GetTriggerEventId() == EVENT_PLAYER_UNIT_SELECTED then
            loop
                exitwhen INT_Index == 12
                set P = Player(INT_Index)
                if SU.boolIs[INT_Index] == false and IsUnitSelected(U, P) then
                    set SU.boolIs[INT_Index] = true
                    set SU.intCountSelecter = SU.intCountSelecter + 1
                    set bj_LastSelectingPlayer = P

                    set U = null
                    set P = null
                    return false
                endif
                set INT_Index = INT_Index + 1
            endloop
        else
            loop
                exitwhen INT_Index == 12
                set P = Player(INT_Index)
                if SU.boolIs[INT_Index] and IsUnitSelected(U, P) == false then
                    set SU.boolIs[INT_Index] = true
                    set SU.intCountSelecter = SU.intCountSelecter - 1
                    if SU.intCountSelecter == 0 then
                        call SU.Destroy()
                    endif
                    set bj_LastSelectingPlayer = P

                    set U = null
                    set P = null
                    return false
                endif
                set INT_Index = INT_Index + 1
            endloop
        endif

        set U = null
        set P = null
        return false
    endfunction

    private function Init takes nothing returns nothing
        local trigger TRIG = CreateTrigger()

        call TriggerRegisterAnyUnitEventBJ(TRIG, EVENT_PLAYER_UNIT_SELECTED)
        call TriggerRegisterAnyUnitEventBJ(TRIG, EVENT_PLAYER_UNIT_DESELECTED)
        call TriggerAddCondition(TRIG, Condition(function Monitor))

        set TRIG = null
    endfunction

private struct SelectedUnit[MAX_INSTANCES]

    public unit u
    public boolean array boolIs[12]
    public integer intCountSelecter = 0

    private static method Create takes unit u returns SelectedUnit
        local integer INT_Index = 0

        if SelectedUnit.intCountInst < MAX_INSTANCES then
            set SelectedUnit.Inst[SelectedUnit.intCountInst] = SelectedUnit.allocate()
            set SelectedUnit.Inst[SelectedUnit.intCountInst].u = u
            loop
                exitwhen INT_Index == 12
                set SelectedUnit.Inst[SelectedUnit.intCountInst].boolIs[INT_Index] = false
                set INT_Index = INT_Index + 1
            endloop

            set SelectedUnit.intCountInst = SelectedUnit.intCountInst + 1

            return SelectedUnit.Inst[SelectedUnit.intCountInst - 1]
        endif

        return 0
    endmethod

    public method Destroy takes nothing returns nothing
        call RemoveUnit(.uAreaIndicator)

        set SelectedUnit.intCountInst = SelectedUnit.intCountInst - 1
        set this = SelectedUnit.Inst[SelectedUnit.intCountInst]
        set SelectedUnit.Inst[SelectedUnit.intCountInst] = 0
    endmethod

    public static method Get takes unit u returns SelectedUnit
        local integer INT_Index = 0

        loop
            exitwhen INT_Index == SelectedUnit.intCountInst
            if SelectedUnit.Inst[INT_Index].u == u then
                return SelectedUnit.Inst[INT_Index]
            endif
            set INT_Index = INT_Index + 1
        endloop

        return SelectedUnit.Create(u)
    endmethod

endstruct

endlibrary

Collapse JASS:
library FarmOperator initializer Init requires SimError, GetSelectionEventPlayer

    //////////////////////////////////////////////////////////////////////
    //  FarmOperator
    //====================================================================
    //      Simulates all a Farm's functions in the map, 'The Razing'.
    //
    //  Functions of Farms:
    //      - Provide food to afford players more arms to defend
    //        the land they have claimed from The Horde.
    //      - Take up a certain area about them so that no other Farms
    //        can be built in this area as they exist.
    //      - Display the circumference of the area they are
    //        established on.
    //      - Maybe other functions later.
    //
    //  *this script is also to be used as a template for MillOperator.
    //////////////////////////////////////////////////////////////////////

globals
    private constant integer FARM_UNIT_ID = 'h00A'
    private constant real FARM_AREA_RADIUS = 1000.00
    private constant integer FARM_AREA_INDICATOR_UNIT_ID = 'h00A'
    private constant integer MAX_FARMS = 100
    private constant integer BUILD_FARM_ORDER_ID = 174998somethingsomethingsomething
    private constant string BUILD_ERROR_MSG = "Unable to build a Farm there. That location is within the boundary of an already existing Farm."

    private group gUG = CreateGroup()
endglobals

private struct Farm[MAX_FARMS]

    private unit uFarm
    private player pOwner
    private real rX
    private real rY
    private unit uAreaIndicator

    public static method Create takes unit u returns boolean
        if Farm.intCountInst < MAX_FARMS then
            set Farm.Inst[Farm.intCountInst] = Farm.allocate()
            set Farm.Inst[Farm.intCountInst].uFarm = u
            set Farm.Inst[Farm.intCountInst].pOwner = GetOwningPlayer(u)
            set Farm.Inst[Farm.intCountInst].rX = GetUnitX(u)
            set Farm.Inst[Farm.intCountInst].rY = GetUnitY(u)
            set Farm.Inst[Farm.intCountInst].uAreaIndicator = CreateUnit(Farm.Inst[Farm.intCountInst].pOwner, AREA_INDICATOR_UNIT_ID, Farm.Inst[Farm.intCountInst].rX, Farm.Inst[Farm.intCountInst].rY, 0.00)
            call SetUnitVertexColor(Farm.Inst[Farm.intCountInst].uAreaIndicator, 100, 100, 100, 0)

            set Farm.intCountInst = Farm.intCountInst + 1

            return true
        endif

        return false
    endmethod

    public method Destroy takes nothing returns nothing
        call RemoveUnit(.uAreaIndicator)

        set Farm.intCountInst = Farm.intCountInst - 1
        set this = Farm.Inst[Farm.intCountInst]
        set Farm.Inst[Farm.intCountInst] = 0
    endmethod

    private static Farm array Inst[MAX_FARMS]
    private static integer intCountInst = 0

    public static method Get takes unit u returns Farm
        local integer INT_Index = 0

        loop
            exitwhen INT_Index == Farm.intCountInst
            if Farm.Inst[INT_Index].uFarm == u then
                return Farm.Inst[INT_Index]
            endif
        endloop

        return 0
    endstruct

endstruct

    private function FilterFarm takes nothing returns boolean
        return GetUnitTypeId(GetFilterUnit()) == FARM_UNIT_ID
    endfunction

    private function EnforceAreaBoundary takes nothing returns boolean
        local unit U = GetTriggerUnit()

        if GetIssuedOrderId() == BUILD_FARM_ORDER_ID then
            //I think a single group-enum call is more efficient than comparison between
            //FARM_AREA_RADIUS and the distance of a Farm from the target point for each
            //existing farm as the latter method entails the evaluation of distance
            //for each existing Farm instance.
            call GroupEnumUnitsInRange(gUG, GetOrderPointX(), GetOrderPointY(), FARM_AREA_RADIUS, Filter(function FilterFarm))
            if FirstOfGroup(gUG) != null then
                call SimError(GetOwningPlayer(U), BUILD_ERROR_MSG)
                call PauseUnit(U, true)
                call IssueImmediateOrder(U, "stop")
                call PauseUnit(U, false)
            endif
            call GroupClear(gUG)
        endif

        set U = null
        return false
    endfunction

    private function RegisterFarm takes nothing returns boolean
        local unit U = GetTriggerUnit()

        if GetUnitTypeId(U) == FARM_UNIT_ID then
            call Farm.Create(U)
        endif

        set U = null
        return false
    endfunction

    private function UnregisterFarm takes nothing returns boolean
        local unit U = GetTriggerUnit()
        local Farm FARM

        if GetUnitTypeId(U) == FARM_UNIT_ID then
            set FARM = Farm.Get(U)
            call FARM.Destroy()
        endif

        set U = null
        return false
    endfunction

    private function ToggleAreaBoundaryDisplay takes nothing returns boolean
        local unit U = GetTriggerUnit()
        local Farm FARM
        local player P

        if GetUnitTypeId(U) == FARM_UNIT_ID then
            set FARM = Farm.Get(U)
            set P = GetSelectingPlayer()
            if GetTriggerEventId() == EVENT_PLAYER_UNIT_SELECTED then
                if GetLocalPlayer() == P then
                    call SetUnitVertexColor(FARM.uAreaIndicator, 100, 100, 100, 100)
                endif
            else
                if GetLocalPlayer() == P then
                    call SetUnitVertexColor(FARM.uAreaIndicator, 100, 100, 100, 0)
                endif
            endif
        endif

        set U = null
        set P = null
    endfunction

    private function Init takes nothing returns nothing
        local trigger TRIG = CreateTrigger()
        local region REG = CreateRegion()

        call TriggerRegisterAnyUnitEventBJ(TRIG, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
        call TriggerAddCondition(TRIG, Condition(function EnforceAreaBoundary))

        set TRIG = CreateTrigger()
        call RegionAddRect(REG, bj_mapInitialPlayableArea)
        call TriggerRegisterEnterRegion(TRIG, REG, Filter(function RegisterFarm))
        set gTRIG = CreateTrigger()
        call TriggerRegisterLeaveRegion(TRIG, REG, Filter(function UnregisterFarm))

        set gTRIG = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(TRIG, EVENT_PLAYER_UNIT_SELECTED)
        call TriggerRegisterAnyUnitEventBJ(TRIG, EVENT_PLAYER_UNIT_DESELECTED)
        call TriggerAddCondition(TRIG, Condition(function ToggleAreaBoundaryDisplay))

        set TRIG = null
        set REG = null
    endfunction

endlibrary
02-04-2009, 11:31 AM#2
DioD
Collapse JASS:
function Trig_Untitled_Trigger_005_Actions takes nothing returns nothing
DO STUFF FOR PLAYER 1
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_005 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_005 = CreateTrigger(  )
    call TriggerRegisterPlayerSelectionEventBJ( gg_trg_Untitled_Trigger_005, Player(0), true )
    call TriggerAddAction( gg_trg_Untitled_Trigger_005, function Trig_Untitled_Trigger_005_Actions )
endfunction

function Trig_Untitled_Trigger_006_Actions takes nothing returns nothing
DO STUFF FOR PLAYER 2
endfunction

//===========================================================================
function InitTrig_Untitled_Trigger_006 takes nothing returns nothing
    set gg_trg_Untitled_Trigger_006 = CreateTrigger(  )
    call TriggerRegisterPlayerSelectionEventBJ( gg_trg_Untitled_Trigger_006, Player(1), true )
    call TriggerAddAction( gg_trg_Untitled_Trigger_006, function Trig_Untitled_Trigger_006_Actions )
endfunction

....

12 separate triggers linked with its player (via any storage system).

This will allow to get any data from GetTriggeringTrigger(), including player.

Or linked to 12 cloned hardcoded by player functions, this way is no jass.

This way easy as possible.
02-05-2009, 02:42 AM#3
fX_
HAHAHAHA

thx for that alternative

edit: like this?

also, i assume that TriggerRegisterPlayerUnitEvent means 'Trigger register player event where player acts on unit' and not 'trigger register unit-of-player event'; coz if it's the latter then wouldnt this not work as intended?
Collapse JASS:
library GetSelectionEventPlayer initializer Init

globals
    private trigger array gTRIG[12]
    
    player bj_LastSelectingPlayer = null
    player bj_LastDeselectingPlayer = null
endglobals

    function GetSelectingPlayer takes nothing returns player
        return bj_LastSelectingPlayer
    endfunction
    
    function GetDeselectingPlayer takes nothing returns player
        return bj_LastDeselectingPlayer
    endfunction
    
    private function Evaluate takes nothing returns boolean
        local trigger TRIG = GetTriggeringTrigger()
        local integer INT_Index = 0
        
        loop
            exitwhen gTRIG[INT_Index] == TRIG
            set INT_Index = INT_Index + 1
        endloop
        if GetTriggerEventId() == EVENT_PLAYER_UNIT_SELECTED then
            set bj_LastSelectingPlayer = Player(INT_Index)
        else
            set bj_LastDeselectingPlayer = Player(INT_Index)
        endif
        
        set TRIG = null
        return false
    endfunction
    
    private function Init takes nothing returns nothing
        local integer INT_Index = 0
        local player P
        
        loop
            exitwhen INT_Index == 12
            set P = Player(INT_Index)
            set gTRIG[INT_Index] = CreateTrigger()
            call TriggerRegisterPlayerUnitEvent(gTRIG[INT_Index], P, EVENT_PLAYER_UNIT_SELECTED, null)
            call TriggerRegisterPlayerUnitEvent(gTRIG[INT_Index], P, EVENT_PLAYER_UNIT_DESELECTED, null)
            call TriggerAddCondition(gTRIG[INT_Index], Condition(function Evaluate))
            set INT_Index = INT_Index + 1
        endloop
        
        set P = null
    endfunction

endlibrary
02-05-2009, 03:50 AM#4
Ammorth
I believe it is the later.
02-05-2009, 07:03 AM#5
DioD
Sync functions shoud not be called from callbacks or conditions.

Any sync call cause trigger sleep(0.0)
02-05-2009, 09:50 AM#6
fX_
What is a sync function?

edit: is it such a function that evaluates as the one here?

edit2: how then can i determine (de)selecting player for a (de)selection event?