HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Build : Advanced Build Simulation

02-02-2009, 03:29 AM#1
fX_
EDIT

Test map also changed. (use the peasant at the bottom of the map. it has 7 menus)

It now works with multiple workers each with its own set of menus.
no 2 'worker conglomerate' can make use of the same 'worker object' (unitId worker) or chaosId.

SCRIPT
Collapse JASS:
library AdvancedBuildMenu initializer Init

    private keyword WorkerMenus

globals
    private constant integer MAX_INSTANCES = 8190
    private constant integer MAX_MENUS_PER_INSTANCE = 7

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//

    private unit array gU_Excluded[8190]
    private integer gINT_CountExcluded = 0
    //Temporary variables.
    private group gUG = CreateGroup()
    private unit gU = null
    private WorkerMenus gWM = 0
endglobals

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//

    function CreateWorkerMenu takes integer primeWorkerId, integer primeChaosId returns WorkerMenus
        return WorkerMenus.Create(primeWorkerId, primeChaosId)
    endfunction
    
    function WorkerRegisterMenu takes integer primeWorkerId, integer dummyButtonId, integer workerId, integer chaosId returns boolean
        local WorkerMenus WM = WorkerMenus.Get(primeWorkerId)

        return WM.AddMenu(dummyButtonId, workerId, chaosId)
    endfunction

//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//

private struct WorkerMenus[MAX_INSTANCES]

    public integer array intDummyButtonId[MAX_MENUS_PER_INSTANCE]
    public integer array intWorkerId[MAX_MENUS_PER_INSTANCE]
    public integer array intChaosId[MAX_MENUS_PER_INSTANCE]
    public integer intCountMenu = 1

    public static method Create takes integer primeWorkerId, integer primeChaosId returns WorkerMenus
        if WorkerMenus.intCountInst < MAX_INSTANCES then
            set WorkerMenus.Inst[WorkerMenus.intCountInst] = WorkerMenus.allocate()
            set WorkerMenus.Inst[WorkerMenus.intCountInst].intDummyButtonId[0] = 0
            set WorkerMenus.Inst[WorkerMenus.intCountInst].intWorkerId[0] = primeWorkerId
            set WorkerMenus.Inst[WorkerMenus.intCountInst].intChaosId[0] = primeChaosId

            set WorkerMenus.intCountInst = WorkerMenus.intCountInst + 1

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

        return 0
    endmethod

    public method AddMenu takes integer dummyButtonId, integer workerId, integer chaosId returns boolean
        local integer INT_Index = 0
        local integer INT_Index2

        if dummyButtonId != 0 and workerId != 0 and chaosId != 0 then
            loop
                exitwhen INT_Index == WorkerMenus.intCountInst
                set INT_Index2 = 0
                loop
                    exitwhen INT_Index2 == WorkerMenus.Inst[INT_Index].intCountMenu
                    if WorkerMenus.Inst[INT_Index].intWorkerId[INT_Index2] == workerId or WorkerMenus.Inst[INT_Index].intChaosId[INT_Index2] == chaosId then
                        return false
                    endif
                    set INT_Index2 = INT_Index2 + 1
                endloop
                set INT_Index = INT_Index + 1
            endloop

            set .intDummyButtonId[.intCountMenu] = dummyButtonId
            set .intWorkerId[.intCountMenu] = workerId
            set .intChaosId[.intCountMenu] = chaosId
            set .intCountMenu = .intCountMenu + 1

            return true
        endif

        return false
    endmethod

    public static WorkerMenus array Inst[MAX_INSTANCES]
    public static integer intCountInst = 0

    public static method Get takes integer unitId returns WorkerMenus
        local integer INT_Index = 0
        local integer INT_Index2

        loop
            exitwhen INT_Index == WorkerMenus.intCountInst
            set INT_Index2 = 0
            loop
                exitwhen INT_Index2 == WorkerMenus.Inst[INT_Index].intCountMenu
                if WorkerMenus.Inst[INT_Index].intWorkerId[INT_Index2] == unitId then
                    return WorkerMenus.Inst[INT_Index]
                endif
                set INT_Index2 = INT_Index2 + 1
            endloop
            set INT_Index = INT_Index + 1
        endloop

        return 0
    endmethod

    public method GetExtraMenuIndex takes integer dummyButtonId returns integer
        local integer INT_Index = 1

        loop
            exitwhen INT_Index == WorkerMenus.Inst[INT_Index].intCountMenu
            if WorkerMenus.Inst[INT_Index].intDummyButtonId[INT_Index] == dummyButtonId then
                return INT_Index
            endif
            set INT_Index = INT_Index + 1
        endloop

        return -1
    endmethod

endstruct

    private function IsUnitContingentSubject takes nothing returns boolean
        local integer INT_Index = 0
        set gU = GetFilterUnit()

        loop
            exitwhen INT_Index == gINT_CountExcluded
            if gU_Excluded[INT_Index] == gU then
                set gINT_CountExcluded = gINT_CountExcluded - 1
                set gU_Excluded[INT_Index] = gU_Excluded[gINT_CountExcluded]
                set gU_Excluded[gINT_CountExcluded] = null

                return false
            endif
            set INT_Index = INT_Index + 1
        endloop

        return IsUnitType(gU, UNIT_TYPE_PEON) and IsUnitSelected(gU, GetOwningPlayer(gU))
    endfunction

    private function OpenFirstMenu takes nothing returns nothing
        local integer INT_UnitId

        call GroupEnumUnitsInRect(gUG, bj_mapInitialPlayableArea, Filter(function IsUnitContingentSubject))
        loop
            set gU = FirstOfGroup(gUG)
            exitwhen gU == null
            set INT_UnitId = GetUnitTypeId(gU)
            set gWM = WorkerMenus.Get(INT_UnitId)
            if gWM != 0 and INT_UnitId != gWM.intWorkerId[0] then
                call UnitAddAbility(gU, gWM.intChaosId[0])
            endif
            call GroupRemoveUnit(gUG, gU)
        endloop

        call GroupClear(gUG)
        set gU = null
        set gWM = 0
    endfunction

    private function OpenExtraMenu takes nothing returns nothing
        local integer INT_Index
        set gU = GetTriggerUnit()
        set gWM = WorkerMenus.Get(GetUnitTypeId(gU))

        set INT_Index = gWM.GetExtraMenuIndex(GetSpellAbilityId())
        if INT_Index != -1 then
            if GetUnitTypeId(gU) != gWM.intWorkerId[INT_Index] then
                call UnitAddAbility(gU, gWM.intChaosId[INT_Index])
            endif
            set gU_Excluded[gINT_CountExcluded] = gU
            set gINT_CountExcluded = gINT_CountExcluded + 1
            if GetLocalPlayer() == GetOwningPlayer(gU) then
                call ForceUIKey("B")
            endif
        endif

        set gU = null
        set gWM = 0
    endfunction

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

        call TriggerRegisterGameEvent(TRIG, EVENT_GAME_BUILD_SUBMENU)
        call TriggerAddAction(TRIG, function OpenFirstMenu)

        set TRIG = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(TRIG, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddAction(TRIG, function OpenExtraMenu)

        set TRIG = null
    endfunction

endlibrary

Test
Collapse JASS:
library Test initializer Init requires AdvancedBuildMenu
private function Init takes nothing returns nothing
call CreateWorkerMenu('h001','S000')
call WorkerRegisterMenu('h001', 'A000','h00C', 'S001')
call WorkerRegisterMenu('h001', 'A001','h00D', 'S002')
call WorkerRegisterMenu('h001', 'A002','h00E', 'S003')
call WorkerRegisterMenu('h001', 'A003','h00F', 'S004')
call WorkerRegisterMenu('h001', 'A004','h00G', 'S005')
call WorkerRegisterMenu('h001', 'A005','h00H', 'S006')
endfunction
endlibrary
Attached Files
File type: w3xA.w3x (1.7 MB)
02-02-2009, 01:46 PM#2
ToukoAozaki
It seems to work better with EVENT_PLAYER_UNIT_SPELL_CAST.

Added: isn't group with API better than loop iteration with arrays? I think just a single group and IsUnitInGroup native would be enough.
Added 2: two (mayby identical) questions: does EVENT_GAME_BUILD_SUBMENU fire for every players? is this multiplayer-ready?
02-02-2009, 11:58 PM#3
fX_
for some reason, if spell cast is used, it fires twice; because they are issued some order first then 'chaos'd then issued it again after chaos.

it was at first a GroupAddUNit() IsUnitInGroup() GroupRemoveUnit() operation. but later i regarded some post i read somewhere saying that looping is better than 'group'ing - or maybe i just made this up in my head... verification?

it works in multiplayer, or at least i trhink it does. the game event does fire for ALL players but it doesnt matter if the other players' peasants are altered as well since they will, by this script, be able to access any build menu still.
i have not been able to think of a way to determine which unit's build menu was opened. suggestions?

a concern i have is that the workers may be silenced...