• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[AI] CargoSystem

Status
Not open for further replies.
Level 29
Joined
Mar 10, 2009
Messages
5,016
What do you think about this system, any improvements are welcome...
progress: 50%

Picks a unit and loads to a ship/transport and transfer to another location


JASS:
/**********************************************************************
*   CargoSystem v0.5
*   by mckill2009
***********************************************************************/
library CargoSystem uses GroupUtils, Table, TimerUtils, SpellEffectEvent

globals
    private constant integer              LOAD_ID = 'A000' //uses purge
    private constant integer            UNLOAD_ID = 'A001' //carrion swarm
    private constant integer        LOAD_ORDER_ID = 852111
    private constant integer      UNLOAD_ORDER_ID = 852218
    private constant real             SEARCH_AREA = 3000
    //private constant integer          ATTACK = 851983
    private constant integer            MOVE = 851986
    //private constant integer           SMART = 851971
    private integer count = 0
    private group TempG = CreateGroup()
    private unit TempU = null
    private sound loadS
    private Table chk
    private TableArray typeID    
endglobals

/***************************************
*   CONFIGURABLES:
****************************************/
private function FilterMore takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_FLYING)
endfunction

/***********************************************************
*   NON-CONFIGURABLES
************************************************************/
private function UnitAlive takes unit u returns boolean
    return not IsUnitType(u, UNIT_TYPE_DEAD) and u!=null
endfunction

private function GetDistance takes real x1, real y1, real x2, real y2 returns real
    return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
endfunction

private function EnumUnits takes nothing returns nothing
    set count = count+1
endfunction

private function GetRandomUnitInArea takes real x, real y, real aoe, boolexpr b returns unit
    local integer ran
    call GroupEnumUnitsInRange(TempG, x, y, aoe, b)
    set count = 0
    call ForGroup(TempG, function EnumUnits)   
    set ran = GetRandomInt(1, count)
    set count = 0
    loop
        set TempU = FirstOfGroup(TempG)
        set count = count + 1
        exitwhen TempU==null or count==ran
        call GroupRemoveUnit(TempG, TempU)
    endloop
    call GroupClear(TempG)
    return TempU
endfunction

/***************************************
*   LOADING UNITS
****************************************/
private struct LoadMovement
    private unit u
    private unit tra
    private real x
    private real y
    
    private static method periodic takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local LoadMovement this = GetTimerData(t)
        if UnitAlive(.u) and chk.boolean[GetHandleId(.u)] then
            if GetDistance(.x, .y, GetUnitX(.u), GetUnitY(.u)) > 60000 then
                call IssuePointOrderById(.u, MOVE, .x, .y)
            else
                call IssueTargetOrderById(.tra, LOAD_ORDER_ID, .u) 
            endif 
        else
            set .u = null
            set .tra = null
            call ReleaseTimer(t)
            call .deallocate()       
        endif
        set t = null
    endmethod
    
    static method load takes unit u, unit tra, real x, real y, real interval returns nothing
        local LoadMovement this = allocate()
        set .u = u
        set .tra = tra
        set .x = x
        set .y = y   
        call TimerStart(NewTimerEx(this), interval, true, function LoadMovement.periodic)
    endmethod
endstruct


/***************************************
*   TRANSPORT MOVEMENT
****************************************/
struct CargoSystem
    private unit transport
    private player owner
    private real xGather
    private real yGather
    private real xDock
    private real yDock
    private real xUnload
    private real yUnload
    private real interval
    private integer maxLoad
    private integer loadedUnitCount
    private integer typeCount
    private group loadGroup
    private boolean isOn
    private boolean isTransportLoading
    
    private static integer loadCount = 0
    private static integer DATA
    
    private static method countUnitsInGroup takes nothing returns nothing
        local thistype this = DATA
        if UnitAlive(GetEnumUnit()) then
            set loadCount = loadCount + 1
        endif
    endmethod
    
    private static method unloadGroup takes nothing returns nothing
        local thistype this = DATA
        local unit u = GetEnumUnit()
        if UnitAlive(u) then
            call chk.remove(GetHandleId(u))
            call GroupRemoveUnit(.loadGroup, u)
            call SetUnitPosition(u, .xUnload, .yUnload)        
            call ShowUnit(u, true)
            call SetUnitInvulnerable(u, false)
            call UnitRemoveAbility(u, 'Abun')
        endif
        set u = null
    endmethod
    
    private static method filterTransported takes nothing returns boolean 
        local thistype this = DATA
        return not IsUnitInGroup(GetFilterUnit(), .loadGroup) and UnitAlive(GetFilterUnit()) and .owner==GetOwningPlayer(GetFilterUnit()) /*
            */ and GetFilterUnit()!=.transport and FilterMore(GetFilterUnit()) and not chk.has(GetHandleId(GetFilterUnit())) /*
            */ and typeID[this][GetRandomInt(1, .typeCount)]==GetUnitTypeId(GetFilterUnit())
    endmethod
    
    private static method periodic takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local thistype this = GetTimerData(t)
        local unit target
        local real x
        local real y
        if UnitAlive(.transport) and .isOn then
            set x = GetUnitX(.transport)
            set y = GetUnitY(.transport)
            //if transporting
            if .isTransportLoading then
                if GetDistance(.xDock, .yDock, x, y) > 40000 then
                    call IssuePointOrderById(.transport, MOVE, .xDock, .yDock)
                else
                    set DATA = this
                    set loadCount = 0
                    call ForGroup(.loadGroup, function thistype.countUnitsInGroup)
                    if .maxLoad > loadCount then    
                        set target = GetRandomUnitInArea(.xDock, .yDock, SEARCH_AREA, Filter(function thistype.filterTransported))
                        if target!=null then
                            call RemoveGuardPosition(target)
                            set chk[GetHandleId(target)] = this
                            set chk.boolean[GetHandleId(target)] = true
                            call LoadMovement.load(target, .transport, .xGather, .yGather, .interval)
                            call GroupAddUnit(.loadGroup, target)
                            set target = null
                        endif
                    endif
                endif
            else //transport is unloading cargo here
                call IssuePointOrderById(.transport, UNLOAD_ORDER_ID, .xUnload, .yUnload)
            endif            
        else
            set .transport = null
            call ReleaseGroup(.loadGroup)
            call ReleaseTimer(t)
            call .deallocate()
        endif 
        set t = null
    endmethod
    
    private static method death takes nothing returns nothing
        if chk.has(GetHandleId(GetTriggerUnit())) then
            call chk.remove(GetHandleId(GetTriggerUnit()))
        endif
    endmethod

    private static method loadUnit takes nothing returns nothing
        local thistype this
        local unit u = GetSpellTargetUnit()
        local integer id = GetHandleId(u)
        local integer transportID
        if chk.has(id) then
            set this = chk[id]
            set transportID = GetHandleId(.transport)
            call ShowUnit(u, false)
            call SetUnitInvulnerable(u, true)
            call UnitAddAbility(u, 'Abun')
            set .loadedUnitCount = .loadedUnitCount + 1
            set chk.boolean[id] = false
            if .loadedUnitCount==.maxLoad then
                set .isTransportLoading = false
                call UnitAddAbility(.transport, UNLOAD_ID)
            endif
        endif
        set u = null
    endmethod
    
    private static method unloadUnit takes nothing returns nothing
        local unit tra = GetTriggerUnit()
        local thistype this = chk[GetHandleId(tra)]
        if chk.has(GetHandleId(tra)) then
            set DATA = this
            call ForGroup(.loadGroup, function thistype.unloadGroup)
            set .isTransportLoading = true
            set .loadedUnitCount = 0
            call UnitRemoveAbility(.transport, UNLOAD_ID)
        endif
        set tra = null
    endmethod

    private static method onInit takes nothing returns nothing
        call RegisterSpellEffectEvent(LOAD_ID, function thistype.loadUnit)
        call RegisterSpellEffectEvent(UNLOAD_ID, function thistype.unloadUnit)
        call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_DEATH, function thistype.death)
        set chk = Table.create()
        set typeID  = TableArray[0x3000]
    endmethod
    
    /***************************************
    *   API:
    ****************************************/
    static method register takes unit transport, integer maxLoad returns thistype
        local thistype this
        local integer id = GetHandleId(transport)
        if chk.has(id) then
            call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "thistype ERROR: "+ GetUnitName(transport) + " is already registered!")
        else
            set this = allocate()
            set chk[id] = this
            set .loadGroup = NewGroup()
            set .transport = transport
            set .maxLoad = maxLoad      
            set .owner = null
            set .isOn = true
            set .isTransportLoading = true
            call RemoveGuardPosition(transport)
            call UnitAddAbility(transport, LOAD_ID)
        endif        
        return this
    endmethod
    
    method setRoute takes real xLoad, real yLoad, real xUnload, real yUnload returns nothing
        set .xDock = xLoad
        set .yDock = yLoad
        set .xUnload = xUnload
        set .yUnload = yUnload        
    endmethod 
    
    method setGatherPoint takes real x, real y returns nothing
        set .xGather = x
        set .yGather = y
    endmethod
    
    method setLoadedPlayer takes player p returns nothing
        set .owner = p
    endmethod
    
    method setUnitLoadingIdType takes integer unitID returns nothing
        set .typeCount = .typeCount + 1
        set typeID[this][.typeCount] = unitID    
    endmethod
    
    method setMaxLoad takes integer maxLoad returns nothing
        set .maxLoad = maxLoad    
        set chk[GetHandleId(.transport)] = maxLoad
    endmethod
    
    method removeUnitType takes integer unitID returns nothing
        local integer i = 0
        
        
        
    endmethod
    
    method launch takes real interval returns nothing
        set .interval = interval
        call TimerStart(NewTimerEx(this), interval, true, function thistype.periodic)
    endmethod 
    
    method remove takes nothing returns nothing
        call chk.remove(GetHandleId(.transport))
        set .isOn = false
    endmethod  
endstruct

endlibrary
 

Attachments

  • CargoSystem.w3x
    56.5 KB · Views: 53
Level 29
Joined
Mar 10, 2009
Messages
5,016
Im not using the normal load/unload abilities coz they have limits, this however has ulimited load depends on the maxLoad...

mechanics as follows;
- transport goes to the dock, picks random unitType that is registered
- when maxLoad is full, ship unloads all units to the xy point
- transport goes back to pick units again

this goes on perpetually until ship dies or removed from system
 
Status
Not open for further replies.
Top