• 🏆 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!

Trade System

Status
Not open for further replies.
Level 11
Joined
Mar 31, 2016
Messages
657
I want to set up a trade system similar to Age of Empires. Market has trade-able resources and also serves as a trading post for trade carts - the dock also works for merchant ships.

Are there any systems already out there that could be used as a template or can somebody summarize how I should go about triggering this?
 
Level 11
Joined
Mar 31, 2016
Messages
657
Bump

I'm not sure what trigger lines to use however I have an idea on what events\conditions\actions to use
I imagine the trade units have a trade ability which will trigger in events when the ability is used within range of market/dock. Then in conditions, check that the market/dock is owned by another player (other than self) who is also an ally - then trigger actions: wait 1 sec, play new animation (load/unload cargo), and move back to player owned market/dock then auto-repeat.

Anybody know what lines to use in GUI or Jass? Or wants to help make it?
 
Level 14
Joined
Mar 11, 2017
Messages
587
If you are still developing the details of the concept, I think that the readers and authors of the triggering subforum will be more competent to help you refine the specifics of your system. In this subforum you might be lucky and find someone with coding skills who bakes the whole system for you from the ground up but it's less likely to find someone that discusses triggering with you here.

I can think of some things:
I assume you want some automation. You might want to press an ability button, maybe target a market building manually, and then your tradesman unit goes back and forth doing his thing by himself, right? This creates some additional consequences for your concept:
  • What if a player has more than one market? I assume that the tradesman will have to return to the nearest market. You will need a system that detects the nearest market. This will have to scan markets more than once because you'll need a recalculation each time you build a new market.
  • What if the player has his market destroyed and later rebuilds it in a different spot? Should the tradesman stop when the market is destroyed? Should it restart automatically when a new market is built?
  • What if he gets attacked? Should he flee? Should he return to the task after fleeing for a while and surviving?
  • Of course if this is to be used in a multi-player fashion, it needs proper indexing to be made MUI.
I can definitely see close proximity between your ageofempirish trade system and the gold mining system of warIII. On the other hand, I cannot say if you can modify the blizzard mining abilities to suit your purposes, and to what extent you can do so. I suggest you get an opinion from someone with knowledge in triggering about the feasibility of the system you're imagining, and the parts that must be detailed further.

I am a triggering noob so I can't really help beside stating the obvious like i wrote here above. Cheers.
My suggestion is to see if this can be assimilated to an additional gold-based custom resource harvesting system, where the gold mine is your ally's market and the town hall is your own market.
Of course this would require that simultaneously your market is both a town hall (for you) and a gold mine (for your allies) and vice versa for each player and his allies. No idea if that's implementable.
 
Last edited:
Level 11
Joined
Mar 31, 2016
Messages
657
If you are still developing the details of the concept, I think that the readers and authors of the triggering subforum will be more competent to help you refine the specifics of your system. In this subforum you might be lucky and find someone with coding skills who bakes the whole system for you from the ground up but it's less likely to find someone that discusses triggering with you here.

I can think of some things:
I assume you want some automation. You might want to press an ability button, maybe target a market building manually, and then your tradesman unit goes back and forth doing his thing by himself, right? This creates some additional consequences for your concept:
  • What if a player has more than one market? I assume that the tradesman will have to return to the nearest market. You will need a system that detects the nearest market. This will have to scan markets more than once because you'll need a recalculation each time you build a new market.
  • What if the player has his market destroyed and later rebuilds it in a different spot? Should the tradesman stop when the market is destroyed? Should it restart automatically when a new market is built?
  • What if he gets attacked? Should he flee? Should he return to the task after fleeing for a while and surviving?
  • Of course if this is to be used in a multi-player fashion, it needs proper indexing to be made MUI.
I can definitely see close proximity between your ageofempirish trade system and the gold mining system of warIII. On the other hand, I cannot say if you can modify the blizzard mining abilities to suit your purposes, and to what extent you can do so. I suggest you get an opinion from someone with knowledge in triggering about the feasibility of the system you're imagining, and the parts that must be detailed further.

I am a triggering noob so I can't really help beside stating the obvious like i wrote here above. Cheers.
My suggestion is to see if this can be assimilated to an additional gold-based custom resource harvesting system, where the gold mine is your ally's market and the town hall is your own market.
Of course this would require that simultaneously your market is both a town hall (for you) and a gold mine (for your allies) and vice versa for each player and his allies. No idea if that's implementable.

Thanks for the feedback. I feel you however I asked for advice one time and simply mentioned if you wanted to do it all go ahead and the thread was moved to Requests - so I thought that would happen again if I posted in Triggers.

Good points. This trigger is going to be more complicated than I thought. Not sure about having the market as a gold mine, that would complicate my other resources.

Alright - I'll try posting for advice in the Triggers section and won't mention anything related to requests. Hopefully the trigger moves one step closer to completion.

Cheers!
 
Level 14
Joined
Mar 11, 2017
Messages
587
Well I'm pretty sure you can avoid all the troublesome points i listed if you can make it like another custom resource, because then you can rely on the default unit behavior system pre-made by blizzard, they'll behave like the usual workers harvesting resources: they'll find the nearest return point by themselves and will react to attacks normally.
 
Level 11
Joined
Mar 31, 2016
Messages
657
Well actually, I have someone working on a custom resource system right now. And one of the custom resources is gold (old gold is now food) - and all trades will use gold as currency. Hmm - interesting, sounds do-able except for all the other variables that have to be accounted for. I'll post in triggers system later tonight.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
I made something similar to this awhile back. It was set up by selecting start and end destinations, you could pause and resume the walker and it would carry mana to the target destination, pretty simple stuff. I'm not sure if that is how you want it implemented so futher details would be needed.

Anyway, I could provide you with the code (don't recall how functional it ever got) or maybe revisit it, but can't really spend any great amount of time on it presently.
 
Last edited:
Level 11
Joined
Mar 31, 2016
Messages
657
I made something similar to this awhile back. It was set up by selecting start and end destinations, you could pause and resume the walker and it would carry mana to the target destination. I could provide you with the code (don't recall how functional it ever got) or maybe revisit it, but can't really spend any great amount of time on it presently.

Hey mate - long time no see.

Glad you replied, I'd like to see that code. Could help me and a couple trigger people i know to develop this.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
Think he means, easy. :p

Hey mate - long time no see.

Glad you replied, I'd like to see that code. Could help me and a couple trigger people i know to develop this.

Found the map and be warned it's not very well documented. Can pass on the map if you want to test it.

JASS:
/*
    Issues
 
    - Can't detect if a targeted area is reachable by land or water.
    - Has no Errror Messages
    - Units on route that have been blocked are left standing still even after the block is removed
      they should automatically start moving again.
   
    Posible changes:
    - Replace the timer check for blocked pathing with an error message only.

    Known bug: - if you issue to deliver goods to a city outside of during free-time, it will be added
                to the failure group temporarily. (until next PERIOD)
                - During supply route and you order it to another destination then its supposed target it will continue afterwards.
                    if it fails the failure is stuck above the unit until next refresh event

*/

scope SupplyCities initializer Init
    globals
        constant integer SUPPLY_CARAVAN         = 'hrdh'
        constant integer SUPPLY_SHIP            = 'hbot'
        constant integer CANCEL_ROUTE           = 'Atau'
        constant integer HOME_DEST              = 'A004'
        constant integer HOME_DEST_UNS          = 'A006'
        constant integer SUPPLY_DEST            = 'A005'
        constant integer SUPPLY_DEST_UNS        = 'A007'
        constant integer DELIVER                = 'A003'
        constant integer DELIVER_SHIP           = 'A00G'
        constant integer GATHER                 = 'A00B'
        constant integer GATHER_SHIP            = 'A00H'
        constant integer WAITING_DELIVER        = 'A00F'
        constant integer WAITING_GATHER         = 'A002'
        constant integer PLAY_PAUSE             = 'A00D'
        constant integer PLAY_PAUSE_SHIP        = 'A00I'
        constant integer STATUS_FREE            = 0        // If only two options exist these can be removed
        constant integer STATUS_WORKING         = 1
        constant string ORDER_GATHER            = "shadowstrike"
        constant string ORDER_DELIVER           = "cripple"
        constant string ORDER_STOP_WORK         = "bearform"
        //constant string ORDER_NEW_DEST          = "unholyfrenzy"    // Not sure these are used
        //constant string ORDER_NEW_HOME          = "charm"
        private constant real PERIOD            = 5.
        private constant real GATHER_PERCENT    = 50.
        private integer array cityDest
        private integer array cityHome
        private integer array status    
        private string array order
        private real array x
        private real array y
        private group failures = CreateGroup()
        private group active = CreateGroup()
        private trigger trgPeriodic
    endglobals

 
    private function Cancel takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local integer uId = GetUnitUserData(caster)
        local unit u = GetTriggerUnit()
        if cityDest[uId] != 0 then
            set cityDest[uId] = 0
            call UnitAddAbility(caster, SUPPLY_DEST_UNS)
            call UnitRemoveAbility(caster, SUPPLY_DEST)
        endif
        if cityHome[uId] != 0 then
            set cityHome[uId] = 0
            call UnitAddAbility(caster, HOME_DEST_UNS)
            call UnitRemoveAbility(caster, HOME_DEST)
        endif
        if status[uId] != STATUS_FREE then
            call IssueImmediateOrderDelayed(caster, ORDER_STOP_WORK, 0.05)
        endif
        set caster = null
    endfunction
 
    private function Destination takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        if cityDest[uId] == 0 then
            call UnitAddAbility(caster, SUPPLY_DEST)
            call UnitRemoveAbility(caster, SUPPLY_DEST_UNS)
        endif
        set cityDest[uId] = GetUnitUserData(target)
        if cityDest[uId] == cityHome[uId] then
            set cityHome[uId] = 0
            call UnitAddAbility(caster, HOME_DEST_UNS)
            call UnitRemoveAbility(caster, HOME_DEST)
        endif
        set caster = null
        set target = null
    endfunction
 
    private function Home takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        if cityHome[uId] == 0 then
            call UnitAddAbility(caster, HOME_DEST)
            call UnitRemoveAbility(caster, HOME_DEST_UNS)
        endif
        set cityHome[uId] = GetUnitUserData(target)
        if cityHome[uId] == cityDest[uId] then
            set cityDest[uId] = 0
            call UnitAddAbility(caster, SUPPLY_DEST_UNS)
            call UnitRemoveAbility(caster, SUPPLY_DEST)
        endif
        set caster = null
        set target = null
    endfunction
 
    private function ToggleFailure takes unit u, integer id, boolean toggle returns nothing
        if IsUnitInGroup(u, failures) == true and toggle == false then
            call GroupRemoveUnit(failures, u)
            call UnitRemoveAbility(u, WAITING_GATHER)
            call UnitRemoveAbility(u, WAITING_DELIVER)
        elseif IsUnitInGroup(u, failures) == false and toggle == true then
            if order[id] == ORDER_GATHER then
                call UnitAddAbility(u, WAITING_GATHER)
            else
               call UnitAddAbility(u, WAITING_DELIVER)
            endif
            call GroupAddUnit(failures, u)
        endif
    endfunction
 
    private function SetFree takes unit u, integer id returns nothing
        if GetUnitTypeId(u) == SUPPLY_CARAVAN then
            call UnitRemoveAbility(u, PLAY_PAUSE)
            call UnitAddAbility(u, PLAY_PAUSE)
        else
            call UnitRemoveAbility(u, PLAY_PAUSE_SHIP)
            call UnitAddAbility(u, PLAY_PAUSE_SHIP)
        endif
        set status[id] = STATUS_FREE
        set order[id] = null
        call ToggleFailure(u, id, false)
        call GroupRemoveUnit(active, u)
    endfunction
 
 
    private function PlayPauseButton takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local integer uId = GetUnitUserData(caster)
        local real mana
        if cityDest[uId] != 0 and cityHome[uId] != 0 and status[uId] == STATUS_FREE then
            set status[uId] = 1
            set mana = GetUnitState(caster, UNIT_STATE_MANA)
            if mana > 0 then
                set order[uId] = ORDER_DELIVER
                call IssueTargetOrder(caster, ORDER_DELIVER, city[cityDest[uId]].u)
            else
                set order[uId] = ORDER_GATHER
                call IssueTargetOrder(caster, ORDER_GATHER, city[cityHome[uId]].u)
            endif
            call GroupAddUnit(active, caster)
        else
            call SetFree(caster, uId)
        endif
        set caster = null
    endfunction
 
    private function InterruptionCheck takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer uId = GetUnitUserData(u)
        local integer typeId = GetUnitTypeId(u)
        if typeId == SUPPLY_CARAVAN or typeId == SUPPLY_SHIP then
            if status[uId] == STATUS_WORKING and order[uId] != OrderId2String(GetIssuedOrderId())  then
                call SetFree(u, uId)
                call IssueImmediateOrder(u, "stop")
            endif
        endif
        set u = null
        return false
    endfunction
 
    private function GatherSupplies takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        local real cityMana = GetUnitState(target, UNIT_STATE_MANA)
        local integer statusIn = status[uId]
        if cityMana/GetUnitState(caster, UNIT_STATE_MAX_MANA)*100 >= GATHER_PERCENT  then
            set status[uId] = STATUS_FREE
            call IssueTargetOrder(caster, "smart", target)
            if statusIn == STATUS_WORKING then
                set order[uId] = ORDER_DELIVER
                call ToggleFailure(caster, uId, false)
                call IssueTargetOrderDelayed(caster, ORDER_DELIVER, city[cityDest[uId]].u, 0.1)
                set status[uId] = STATUS_WORKING
            endif
        elseif status[uId] == STATUS_WORKING then
            call ToggleFailure(caster, uId, true)
        endif
        set target = null
        set caster = null
    endfunction

    private function DeliverSupplies takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        local real cityMana = GetUnitState(target, UNIT_STATE_MANA)
        local real cityManaMax = GetUnitState(target, UNIT_STATE_MAX_MANA)
        local real unitMana = GetUnitState(caster, UNIT_STATE_MANA)
        local integer statusIn = status[uId]
     
        if cityManaMax >= unitMana + cityMana then
            call SetUnitState(target, UNIT_STATE_MANA, unitMana + cityMana)
            call SetUnitState(caster, UNIT_STATE_MANA, 0)
            if status[uId] == STATUS_WORKING then
                call ToggleFailure(caster, uId, false)
                set order[uId] = ORDER_GATHER
                call IssueTargetOrder(caster, ORDER_GATHER, city[cityHome[uId]].u)
            endif
        else
            // Delivers what mana posible and toggles failure on
            call SetUnitState(target, UNIT_STATE_MANA, cityManaMax)
            set unitMana = unitMana - cityManaMax + cityMana
            call SetUnitState(caster, UNIT_STATE_MANA, unitMana)
            if status[uId] == STATUS_WORKING then
                call ToggleFailure(caster, uId, true)
            endif
        endif
        set target = null
        set caster = null
    endfunction
 
    private function RedoTask takes nothing returns nothing
        local unit u = GetEnumUnit()
        local integer uId = GetUnitUserData(u)
        if status[uId] == 0 then
            set order[uId] = null
            call ToggleFailure(u, uId, false)
        else
            if order[uId] == ORDER_DELIVER then
                call IssueTargetOrder(u, order[uId], city[cityDest[uId]].u)
            elseif order[uId] == ORDER_GATHER then
                call IssueTargetOrder(u, ORDER_GATHER, city[cityHome[uId]].u)
            endif
        endif
        set u = null
    endfunction
 
    private function Refresh takes nothing returns nothing
        local unit u = GetEnumUnit()
        local integer id = GetUnitUserData(u)
        local real old_x = x[id]
        local real old_y = y[id]
        set x[id] = GetUnitX(u)
        set y[id] = GetUnitY(u)
        if (not IsUnitInGroup(u, failures) and old_x == x[id] and old_y == y[id]) or IsUnitInGroup(u, failures) == true then
            if order[id] == ORDER_DELIVER then
                call IssueTargetOrder(u, ORDER_DELIVER, city[cityDest[id]].u)
            else
                call IssueTargetOrder(u, ORDER_GATHER, city[cityHome[id]].u)
            endif
        endif
    endfunction
 
    private function Periodic takes nothing returns nothing
        call ForGroup(active, function Refresh)
    endfunction
 
    private function Init takes nothing returns nothing
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
        local trigger t3 = CreateTrigger()
        local trigger t4 = CreateTrigger()
        local trigger t5 = CreateTrigger()
        local trigger t6 = CreateTrigger()
        local trigger t7 = CreateTrigger()
        local integer i = 0
        local player p
        set trgPeriodic = CreateTrigger()
        loop
            set p = Player(i)
            call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerRegisterTimerEvent(trgPeriodic, PERIOD, true)
        call TrgRegisterGenericSpellFinish(t1, CANCEL_ROUTE)
        call TrgRegisterGenericSpellFinish(t2, SUPPLY_DEST_UNS)
        call TrgRegisterGenericSpellFinish(t2, SUPPLY_DEST)
        call TrgRegisterGenericSpellFinish(t3, HOME_DEST_UNS)
        call TrgRegisterGenericSpellFinish(t3, HOME_DEST)
        call TrgRegisterGenericSpellFinish(t4, DELIVER)
        call TrgRegisterGenericSpellFinish(t4, DELIVER_SHIP)
        call TrgRegisterGenericSpellFinish(t5, GATHER)
        call TrgRegisterGenericSpellFinish(t5, GATHER_SHIP)
        call TrgRegisterGenericSpellFinish(t6, PLAY_PAUSE)
        call TrgRegisterGenericSpellFinish(t6, PLAY_PAUSE_SHIP)
        call TriggerAddAction(t1, function Cancel)
        call TriggerAddAction(t2, function Destination)
        call TriggerAddAction(t3, function Home)
        call TriggerAddAction(t4, function DeliverSupplies)
        call TriggerAddAction(t5, function GatherSupplies)
        call TriggerAddAction(t6, function PlayPauseButton)
        call TriggerAddCondition(t7, Condition(function InterruptionCheck))
        call TriggerAddAction(trgPeriodic, function Periodic)
    endfunction
endscope
 
Level 11
Joined
Mar 31, 2016
Messages
657
Think he means, easy. :p



Found the map and be warned it's not very well documented. Can pass on the map if you want to test it.

JASS:
/*
    Issues
 
    - Can't detect if a targeted area is reachable by land or water.
    - Has no Errror Messages
    - Units on route that have been blocked are left standing still even after the block is removed
      they should automatically start moving again.
  
    Posible changes:
    - Replace the timer check for blocked pathing with an error message only.

    Known bug: - if you issue to deliver goods to a city outside of during free-time, it will be added
                to the failure group temporarily. (until next PERIOD)
                - During supply route and you order it to another destination then its supposed target it will continue afterwards.
                    if it fails the failure is stuck above the unit until next refresh event

*/

scope SupplyCities initializer Init
    globals
        constant integer SUPPLY_CARAVAN         = 'hrdh'
        constant integer SUPPLY_SHIP            = 'hbot'
        constant integer CANCEL_ROUTE           = 'Atau'
        constant integer HOME_DEST              = 'A004'
        constant integer HOME_DEST_UNS          = 'A006'
        constant integer SUPPLY_DEST            = 'A005'
        constant integer SUPPLY_DEST_UNS        = 'A007'
        constant integer DELIVER                = 'A003'
        constant integer DELIVER_SHIP           = 'A00G'
        constant integer GATHER                 = 'A00B'
        constant integer GATHER_SHIP            = 'A00H'
        constant integer WAITING_DELIVER        = 'A00F'
        constant integer WAITING_GATHER         = 'A002'
        constant integer PLAY_PAUSE             = 'A00D'
        constant integer PLAY_PAUSE_SHIP        = 'A00I'
        constant integer STATUS_FREE            = 0        // If only two options exist these can be removed
        constant integer STATUS_WORKING         = 1
        constant string ORDER_GATHER            = "shadowstrike"
        constant string ORDER_DELIVER           = "cripple"
        constant string ORDER_STOP_WORK         = "bearform"
        //constant string ORDER_NEW_DEST          = "unholyfrenzy"    // Not sure these are used
        //constant string ORDER_NEW_HOME          = "charm"
        private constant real PERIOD            = 5.
        private constant real GATHER_PERCENT    = 50.
        private integer array cityDest
        private integer array cityHome
        private integer array status   
        private string array order
        private real array x
        private real array y
        private group failures = CreateGroup()
        private group active = CreateGroup()
        private trigger trgPeriodic
    endglobals

 
    private function Cancel takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local integer uId = GetUnitUserData(caster)
        local unit u = GetTriggerUnit()
        if cityDest[uId] != 0 then
            set cityDest[uId] = 0
            call UnitAddAbility(caster, SUPPLY_DEST_UNS)
            call UnitRemoveAbility(caster, SUPPLY_DEST)
        endif
        if cityHome[uId] != 0 then
            set cityHome[uId] = 0
            call UnitAddAbility(caster, HOME_DEST_UNS)
            call UnitRemoveAbility(caster, HOME_DEST)
        endif
        if status[uId] != STATUS_FREE then
            call IssueImmediateOrderDelayed(caster, ORDER_STOP_WORK, 0.05)
        endif
        set caster = null
    endfunction
 
    private function Destination takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        if cityDest[uId] == 0 then
            call UnitAddAbility(caster, SUPPLY_DEST)
            call UnitRemoveAbility(caster, SUPPLY_DEST_UNS)
        endif
        set cityDest[uId] = GetUnitUserData(target)
        if cityDest[uId] == cityHome[uId] then
            set cityHome[uId] = 0
            call UnitAddAbility(caster, HOME_DEST_UNS)
            call UnitRemoveAbility(caster, HOME_DEST)
        endif
        set caster = null
        set target = null
    endfunction
 
    private function Home takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        if cityHome[uId] == 0 then
            call UnitAddAbility(caster, HOME_DEST)
            call UnitRemoveAbility(caster, HOME_DEST_UNS)
        endif
        set cityHome[uId] = GetUnitUserData(target)
        if cityHome[uId] == cityDest[uId] then
            set cityDest[uId] = 0
            call UnitAddAbility(caster, SUPPLY_DEST_UNS)
            call UnitRemoveAbility(caster, SUPPLY_DEST)
        endif
        set caster = null
        set target = null
    endfunction
 
    private function ToggleFailure takes unit u, integer id, boolean toggle returns nothing
        if IsUnitInGroup(u, failures) == true and toggle == false then
            call GroupRemoveUnit(failures, u)
            call UnitRemoveAbility(u, WAITING_GATHER)
            call UnitRemoveAbility(u, WAITING_DELIVER)
        elseif IsUnitInGroup(u, failures) == false and toggle == true then
            if order[id] == ORDER_GATHER then
                call UnitAddAbility(u, WAITING_GATHER)
            else
               call UnitAddAbility(u, WAITING_DELIVER)
            endif
            call GroupAddUnit(failures, u)
        endif
    endfunction
 
    private function SetFree takes unit u, integer id returns nothing
        if GetUnitTypeId(u) == SUPPLY_CARAVAN then
            call UnitRemoveAbility(u, PLAY_PAUSE)
            call UnitAddAbility(u, PLAY_PAUSE)
        else
            call UnitRemoveAbility(u, PLAY_PAUSE_SHIP)
            call UnitAddAbility(u, PLAY_PAUSE_SHIP)
        endif
        set status[id] = STATUS_FREE
        set order[id] = null
        call ToggleFailure(u, id, false)
        call GroupRemoveUnit(active, u)
    endfunction
 
 
    private function PlayPauseButton takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local integer uId = GetUnitUserData(caster)
        local real mana
        if cityDest[uId] != 0 and cityHome[uId] != 0 and status[uId] == STATUS_FREE then
            set status[uId] = 1
            set mana = GetUnitState(caster, UNIT_STATE_MANA)
            if mana > 0 then
                set order[uId] = ORDER_DELIVER
                call IssueTargetOrder(caster, ORDER_DELIVER, city[cityDest[uId]].u)
            else
                set order[uId] = ORDER_GATHER
                call IssueTargetOrder(caster, ORDER_GATHER, city[cityHome[uId]].u)
            endif
            call GroupAddUnit(active, caster)
        else
            call SetFree(caster, uId)
        endif
        set caster = null
    endfunction
 
    private function InterruptionCheck takes nothing returns boolean
        local unit u = GetTriggerUnit()
        local integer uId = GetUnitUserData(u)
        local integer typeId = GetUnitTypeId(u)
        if typeId == SUPPLY_CARAVAN or typeId == SUPPLY_SHIP then
            if status[uId] == STATUS_WORKING and order[uId] != OrderId2String(GetIssuedOrderId())  then
                call SetFree(u, uId)
                call IssueImmediateOrder(u, "stop")
            endif
        endif
        set u = null
        return false
    endfunction
 
    private function GatherSupplies takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        local real cityMana = GetUnitState(target, UNIT_STATE_MANA)
        local integer statusIn = status[uId]
        if cityMana/GetUnitState(caster, UNIT_STATE_MAX_MANA)*100 >= GATHER_PERCENT  then
            set status[uId] = STATUS_FREE
            call IssueTargetOrder(caster, "smart", target)
            if statusIn == STATUS_WORKING then
                set order[uId] = ORDER_DELIVER
                call ToggleFailure(caster, uId, false)
                call IssueTargetOrderDelayed(caster, ORDER_DELIVER, city[cityDest[uId]].u, 0.1)
                set status[uId] = STATUS_WORKING
            endif
        elseif status[uId] == STATUS_WORKING then
            call ToggleFailure(caster, uId, true)
        endif
        set target = null
        set caster = null
    endfunction

    private function DeliverSupplies takes nothing returns nothing
        local unit caster = genLastSpellCaster
        local unit target = genLastSpellTarget
        local integer uId = GetUnitUserData(caster)
        local real cityMana = GetUnitState(target, UNIT_STATE_MANA)
        local real cityManaMax = GetUnitState(target, UNIT_STATE_MAX_MANA)
        local real unitMana = GetUnitState(caster, UNIT_STATE_MANA)
        local integer statusIn = status[uId]
    
        if cityManaMax >= unitMana + cityMana then
            call SetUnitState(target, UNIT_STATE_MANA, unitMana + cityMana)
            call SetUnitState(caster, UNIT_STATE_MANA, 0)
            if status[uId] == STATUS_WORKING then
                call ToggleFailure(caster, uId, false)
                set order[uId] = ORDER_GATHER
                call IssueTargetOrder(caster, ORDER_GATHER, city[cityHome[uId]].u)
            endif
        else
            // Delivers what mana posible and toggles failure on
            call SetUnitState(target, UNIT_STATE_MANA, cityManaMax)
            set unitMana = unitMana - cityManaMax + cityMana
            call SetUnitState(caster, UNIT_STATE_MANA, unitMana)
            if status[uId] == STATUS_WORKING then
                call ToggleFailure(caster, uId, true)
            endif
        endif
        set target = null
        set caster = null
    endfunction
 
    private function RedoTask takes nothing returns nothing
        local unit u = GetEnumUnit()
        local integer uId = GetUnitUserData(u)
        if status[uId] == 0 then
            set order[uId] = null
            call ToggleFailure(u, uId, false)
        else
            if order[uId] == ORDER_DELIVER then
                call IssueTargetOrder(u, order[uId], city[cityDest[uId]].u)
            elseif order[uId] == ORDER_GATHER then
                call IssueTargetOrder(u, ORDER_GATHER, city[cityHome[uId]].u)
            endif
        endif
        set u = null
    endfunction
 
    private function Refresh takes nothing returns nothing
        local unit u = GetEnumUnit()
        local integer id = GetUnitUserData(u)
        local real old_x = x[id]
        local real old_y = y[id]
        set x[id] = GetUnitX(u)
        set y[id] = GetUnitY(u)
        if (not IsUnitInGroup(u, failures) and old_x == x[id] and old_y == y[id]) or IsUnitInGroup(u, failures) == true then
            if order[id] == ORDER_DELIVER then
                call IssueTargetOrder(u, ORDER_DELIVER, city[cityDest[id]].u)
            else
                call IssueTargetOrder(u, ORDER_GATHER, city[cityHome[id]].u)
            endif
        endif
    endfunction
 
    private function Periodic takes nothing returns nothing
        call ForGroup(active, function Refresh)
    endfunction
 
    private function Init takes nothing returns nothing
        local trigger t1 = CreateTrigger()
        local trigger t2 = CreateTrigger()
        local trigger t3 = CreateTrigger()
        local trigger t4 = CreateTrigger()
        local trigger t5 = CreateTrigger()
        local trigger t6 = CreateTrigger()
        local trigger t7 = CreateTrigger()
        local integer i = 0
        local player p
        set trgPeriodic = CreateTrigger()
        loop
            set p = Player(i)
            call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
            call TriggerRegisterPlayerUnitEvent(t7, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerRegisterTimerEvent(trgPeriodic, PERIOD, true)
        call TrgRegisterGenericSpellFinish(t1, CANCEL_ROUTE)
        call TrgRegisterGenericSpellFinish(t2, SUPPLY_DEST_UNS)
        call TrgRegisterGenericSpellFinish(t2, SUPPLY_DEST)
        call TrgRegisterGenericSpellFinish(t3, HOME_DEST_UNS)
        call TrgRegisterGenericSpellFinish(t3, HOME_DEST)
        call TrgRegisterGenericSpellFinish(t4, DELIVER)
        call TrgRegisterGenericSpellFinish(t4, DELIVER_SHIP)
        call TrgRegisterGenericSpellFinish(t5, GATHER)
        call TrgRegisterGenericSpellFinish(t5, GATHER_SHIP)
        call TrgRegisterGenericSpellFinish(t6, PLAY_PAUSE)
        call TrgRegisterGenericSpellFinish(t6, PLAY_PAUSE_SHIP)
        call TriggerAddAction(t1, function Cancel)
        call TriggerAddAction(t2, function Destination)
        call TriggerAddAction(t3, function Home)
        call TriggerAddAction(t4, function DeliverSupplies)
        call TriggerAddAction(t5, function GatherSupplies)
        call TriggerAddAction(t6, function PlayPauseButton)
        call TriggerAddCondition(t7, Condition(function InterruptionCheck))
        call TriggerAddAction(trgPeriodic, function Periodic)
    endfunction
endscope

Phew, o ok.
Sure - send it to me.

Nice - this code looks legit. I'll tinker with this later.
 
Status
Not open for further replies.
Top