• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Trading system help

Status
Not open for further replies.
Hello everyone!

As it looks now, there are only two or three things in the way of releasing World in Flames, one of thee being the need of a proper sea trading system.

The principle of this system is that uncontrollable ships are being sent from the ports on the map to different allied players, generating income for both if it reaches it's destination.
In my system, i loop through all players on the map, group their ports, and count their allies. Then i use a couple of loops to stack the allied players in an array based on how many ports they have (their so called "trade power"), where 1 is the one with the most ports. I then start sending ships from the first port in my group, and tell it to go to the closest port owned by the target ally, where port 1 sends to the ally that is first in the array, port 2 sends to the ally that comes second, and so on. I also use ModuloInteger(i, maxallies) to make sure that if i have more ports than allies, say 3 allies and 4 ports, port no. 4 will send to ally 1 again.

Now, my script is very sloppy and unfinished, and has many apparent flaws:

*Although it doesn't sent trade ships to an ally that has no ports, it does not check a new ally in it's stead but just continues onto the next port and leaves the current one without having sent any ship.

*If a port is captured while a ship is heading towards it, i so far have no method of telling the ship to head towards a new port.

*It.. well, it doesn't work!

Here is the code:

JASS:
library TradeSys initializer Init

    globals
      integer array numports[12]
      private player temp_player
      private timer interval
      private player array pl[12]  //The "p" variable from your snippet that i had to rename, since p was a bit too commonly used for a global variable!
    endglobals
    
    private function GetPlayerPortPacific takes nothing returns boolean
        if GetOwningPlayer(GetFilterUnit()) != temp_player then
          return false
        endif
        if GetUnitY(GetFilterUnit()) > -2000 then  //Theese functions make sure that the system doesn't pick ports on the other theatre. 
          return false
        endif
        return true
    endfunction
    
    private function GetPlayerPortEurope takes nothing returns boolean
        if GetOwningPlayer(GetFilterUnit()) != temp_player then
          return false
        endif
        if GetUnitY(GetFilterUnit()) < -2500 then
          return false
        endif
        return true
    endfunction
    
    private function onLoop takes nothing returns nothing
        local integer p      = 0
        local integer i      = 0
        
        local real x         = 0
        local real y         = 0
        
        local integer allies = 0
        local group g1       = CreateGroup()
        local group g2       = CreateGroup()
        local unit u         = null
        local unit ship
        local player target
        
        //Trade Power variables
        local player b
        local player q
        local integer i2 = 0
        local integer n = 0
        local integer m = 0
        
        loop
            exitwhen p > 11
            
            set allies = 0
            set i = 0
            
            loop
                exitwhen i > 11
                if GetPlayerAlliance(Player(p), Player(i), ALLIANCE_SHARED_VISION) == true then
                    set allies = allies+1
                endif
                set i = i+1
            endloop
            
            set i = 0

            if allies != 0 then
              set temp_player = Player(p)
              call GroupEnumUnitsOfType(g1, UnitId2String('h00R'), Filter(function GetPlayerPortPacific)) //Group ports owned by the player
              loop
                  //in this loop, the index of the allies is 'i'. 
                  set u = FirstOfGroup(g1)  //...but the loop ends when the player runs out of ports.
                  exitwhen u == null
                  
                  set x = GetUnitX(u)
                  set y = GetUnitY(u)
                  
                  //The following two loops are for listing the players in an array in order of their ammount of ports possesed. 
                  
                  loop
                      exitwhen i2 > 11
                      set b = Player(i2)
                      if target != Player(i2) and IsPlayerAlly(target,b) then
                          set pl[n] = b
                          set n = n + 1
                      endif
                      set i2 = i2 + 1
                  endloop
                  set i2 = 0
                  loop
                     exitwhen n == 1 or i2 >= n
                      set m = i2
                      loop
                          set m = m + 1
                          exitwhen m >= n
                          if numports[GetPlayerId(pl[i2])] < numports[GetPlayerId(pl[m])] then
                              set q = pl[i2]
                              set pl[i2] = pl[m]
                              set pl[m] = q
                          endif
                      endloop
                      set i2 = i2 + 1
                  endloop
                  
                  
                  set target = pl[ModuloInteger(i, allies)] //this line makes sure that the picked ally is the one with the highest trading power.
                  set temp_player = Player(i)
                  call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPortPacific)) //Group ports owned by the target ally
                  if CountUnitsInGroup(g2) != 0 then
                      set u = GetClosestUnitInGroup(x, y, g2)
                      set ship = CreateUnit(Player(p), 'h01B', x, y, 0.)
                      call IssueTargetOrder(ship, "channel", u)
                  endif
                  call GroupRemoveUnit(g1, u)
              endloop
            endif
            
            set i = i+1
        endloop
        
        set p = 0
        set i = 0
        set m = 0
        set n = 0
        set i2 = 0
        set u = null
        
        loop
            exitwhen p > 11
            
            set allies = 0
            set i = 0
            
            loop
                exitwhen i > 11
                if GetPlayerAlliance(Player(p), Player(i), ALLIANCE_SHARED_VISION) == true then
                    set allies = allies+1
                endif
                set i = i+1
            endloop
            
            set i = 0

            if allies != 0 then
              set temp_player = Player(p)
              call GroupEnumUnitsOfType(g1, UnitId2String('h00R'), Filter(function GetPlayerPortEurope)) //Group ports owned by the player
              loop
                  //in this loop, the index of the allies is 'i'. 
                  set u = FirstOfGroup(g1)  //...but the loop ends when the player runs out of ports.
                  exitwhen u == null
                  
                  set x = GetUnitX(u)
                  set y = GetUnitY(u)
                  
                  
                  loop
                      exitwhen i2 > 11
                      set b = Player(i2)
                      if target != Player(i2) and IsPlayerAlly(target,b) then
                          set pl[n] = b
                          set n = n + 1
                      endif
                      set i2 = i2 + 1
                  endloop
                  set i2 = 0
                  loop
                     exitwhen n == 1 or i2 >= n
                      set m = i2
                      loop
                          set m = m + 1
                          exitwhen m >= n
                          if numports[GetPlayerId(pl[i2])] < numports[GetPlayerId(pl[m])] then
                              set q = pl[i2]
                              set pl[i2] = pl[m]
                              set pl[m] = q
                          endif
                      endloop
                      set i2 = i2 + 1
                  endloop
                  
                  
                  set target = pl[ModuloInteger(i, allies)] //this line makes sure that the picked ally is the one with the highest trading power.
                  set temp_player = Player(i)
                  call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPortEurope)) //Group ports owned by the target ally
                  if CountUnitsInGroup(g2) != 0 then
                      set u = GetClosestUnitInGroup(x, y, g2)
                      set ship = CreateUnit(Player(p), 'h01B', x, y, 0.)
                      call IssueTargetOrder(ship, "channel", u)
                  endif
                  call GroupRemoveUnit(g1, u)
              endloop
            endif
            
            set i = i+1
        endloop
    
    endfunction
    
    private function IsUnitHarbour takes nothing returns boolean
        local integer p = GetPlayerId(GetOwningPlayer(GetFilterUnit()))
        if GetUnitTypeId(GetFilterUnit()) == 'h00R' then
            set numports = numports + 1
            return true
        endif
        return false
    endfunction
    
    private function Init takes nothing returns nothing
        local integer i = 0
        local group g = CreateGroup()
        set interval = CreateTimer()
        call TimerStart(interval, 20, true, function onLoop)
        
        loop
            exitwhen i > 11
            call GroupEnumUnitsOfPlayer(g, Player(i), Filter(function IsUnitHarbour))
            call GroupClear(g)
            set i = i+1
        endloop
        
    endfunction

endlibrary

Can anyone help me sort this out?
 
Last edited:
JASS:
    private function IsUnitHarbour takes nothing returns boolean
        return GetUnitTypeId(GetFilterUnit()) == 'h00R'
    endfunction

    call GroupEnumUnitsOfPlayer(g, Player(i), Filter(function IsUnitHarbour))
    set numports[i] = CountUnitsInGroup(g)

->>>
    private function IsUnitHarbour takes nothing returns boolean
        if GetUnitTypeId(GetFilterUnit()) == 'h00R' then
            set numports[i] = numports[i] + 1
            return true
        endif
        return false
    endfunction

    call GroupEnumUnitsOfPlayer(g, Player(i), Filter(function IsUnitHarbour))

EDIT: sry forgot that filter can not take parameters.

JASS:
    private function GetPlayerPortPacific takes nothing returns boolean
        if GetOwningPlayer(GetFilterUnit()) != temp_player then
          return false
        endif
        if GetUnitY(GetFilterUnit()) > -2000 then  //Theese functions make sure that the system doesn't pick ports on the other theatre.
          return false
        endif
        return true
    endfunction
    
    private function GetPlayerPortEurope takes nothing returns boolean
        if GetOwningPlayer(GetFilterUnit()) != temp_player then
          return false
        endif
        if GetUnitY(GetFilterUnit()) < -2500 then
          return false
        endif
        return true
    endfunction

->>>
// Use one of the globals temporary to make filter functions much smoother:

    private function GetPlayerPort takes nothing returns boolean
        if someglobal then
            return GetOwningPlayer(GetFilterUnit()) == temp_player and GetUnitY(GetFilterUnit()) < -2500
        endif
        return GetOwningPlayer(GetFilterUnit()) == temp_player and GetUnitY(GetFilterUnit()) > -2000
    endfunction
// Let it be boolean or integer (1 or 0 value)

Now:
JASS:
    call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPortEurope)) //Group ports owned by the target ally
    if CountUnitsInGroup(g2) != 0 then
// And
    call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPortPacific)) //Group ports owned by the target ally
    if CountUnitsInGroup(g2) != 0 then

->>
    set someglobal = true  // or someglobal = 1
    call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPort)) //Group ports owned by the target ally

    set someglobal = false  // or someglobal = 0
    call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPort)) //Group ports owned by the target ally

It would be nice if you use other integer global for counting purposes here too (similar as I did above).
 
Last edited:
Thank you for the responses, Pharaoh and Maker, you were both correct, and Spinnaker, i updated the IsUnitHarbour function like you suggested. I would also love it if i could combine both loops into one single (for both europe and pacific), but t is so hard to work with this code when there are so many loops inside eachother. I also discovered earlier that you cannot call a function inside a loop, if said function contains another loop within itself (not start a new thread containing a loop, that is). It causes a fatal error and crashes the game. That is why i have to use this virtually unreadable suloution.

Anyways, i updated the code to fix some of theese errors (check the first post), and i also removed a "i = i+1" statement that looked kinda off (since i was also increasing i outside of the loop at the same time!). Still, the code won't produce any ships and is propably abordet somewhere.

I will run some debugs later tonight.
 
I don't understand.. what do you mean?

What i meant about combining two loops was the fact that i have two almost identical parts, one for the pacific theatre, and one for the european. Since the only difference is the filter i use, i should propably be able to combine them somehow.

Right now though, most important is getting it to work in the first place. Lol.
 
JASS:
    private function GetPlayerPortPacific takes nothing returns boolean
        if GetOwningPlayer(GetFilterUnit()) != temp_player then
          return false
        endif
        if GetUnitY(GetFilterUnit()) > -2000 then  //Theese functions make sure that the system doesn't pick ports on the other theatre.
          return false
        endif
        return true
    endfunction
    
    private function GetPlayerPortEurope takes nothing returns boolean
        if GetOwningPlayer(GetFilterUnit()) != temp_player then
          return false
        endif
        if GetUnitY(GetFilterUnit()) < -2500 then
          return false
        endif
        return true
    endfunction

->

JASS:
    private function GetPlayerPortPacific takes nothing returns boolean
        return GetUnitY(GetFilterUnit()) <= -2000 and GetOwningPlayer(GetFilterUnit()) == temp_player
    endfunction
    
    private function GetPlayerPortEurope takes nothing returns boolean
        return GetUnitY(GetFilterUnit()) >= -2500 and GetOwningPlayer(GetFilterUnit()) == temp_player
    endfunction

edit

JASS:
        local group g1       = CreateGroup()
        local group g2       = CreateGroup()

rage-face.jpg


You should be using global groups here.
 
I updated the conditions, and added some more comments.
I will sitch to global groups later, i might include the GroupUtils library but i dunno.

Here is the code anyways, i was somehow unable to update the main post due to database error:

JASS:
library TradeSys initializer Init

    globals
      integer array numports[12]
      private player temp_player
      private timer interval
      private player array pl[12]  //The "p" variable from your snippet that i had to rename, since p was a bit too commonly used for a global variable!
    endglobals
    
    private function GetPlayerPortPacific takes nothing returns boolean
        return GetUnitY(GetFilterUnit()) <= -2000 and GetOwningPlayer(GetFilterUnit()) == temp_player
    endfunction

    private function GetPlayerPortEurope takes nothing returns boolean
        return GetUnitY(GetFilterUnit()) >= -2500 and GetOwningPlayer(GetFilterUnit()) == temp_player
    endfunction
    
    private function onLoop takes nothing returns nothing
        local integer p      = 0
        local integer i      = 0
        
        local real x         = 0
        local real y         = 0
        
        local integer allies = 0
        local group g1       = CreateGroup()
        local group g2       = CreateGroup()
        local unit u         = null
        local unit ship
        local player target
        
        //Trade Power variables
        local player b
        local player q
        local integer i2 = 0
        local integer n = 0
        local integer m = 0
        
        loop
            exitwhen p > 11
            //What i want to do in this, the main loop, is to cycle through the players, and in turn cycle through their ports. 
            
            set allies = 0
            set i = 0
            
            //With the below line, i count the number of allies the currently picked player has - i use this number later on in the code. 
            
            loop
                exitwhen i > 11
                if GetPlayerAlliance(Player(p), Player(i), ALLIANCE_SHARED_VISION) == true then
                    set allies = allies+1
                endif
                set i = i+1
            endloop
            
            set i = 0

            if allies != 0 then
              //If the player has allies, we will start checking where to send the ships
              set temp_player = Player(p)
              call GroupEnumUnitsOfType(g1, UnitId2String('h00R'), Filter(function GetPlayerPortPacific)) //Group ports owned by the player
              loop
                  //in this loop, the index of the allies is 'i'. 
                  set u = FirstOfGroup(g1)  //...but the loop ends when the player runs out of ports.
                  exitwhen u == null
                  
                  set x = GetUnitX(u)
                  set y = GetUnitY(u)
                  
                  //The following two loops are for listing the players in an array in order of their ammount of ports possesed. 
                  //The reason for this is that i prioritize sending trade ships to allies that has a lot of ports, to reward them of this. 
                  
                  loop
                      exitwhen i2 > 11
                      set b = Player(i2)
                      if target != Player(i2) and IsPlayerAlly(target,b) then
                          set pl[n] = b
                          set n = n + 1
                      endif
                      set i2 = i2 + 1
                  endloop
                  set i2 = 0
                  loop
                     exitwhen n == 1 or i2 >= n
                      set m = i2
                      loop
                          set m = m + 1
                          exitwhen m >= n
                          if numports[GetPlayerId(pl[i2])] < numports[GetPlayerId(pl[m])] then
                              set q = pl[i2]
                              set pl[i2] = pl[m]
                              set pl[m] = q
                          endif
                      endloop
                      set i2 = i2 + 1
                  endloop
                  
                  //Thank you Garfield1337, for the above two loops. 
                  
                  
                  set target = pl[ModuloInteger(i, allies)] //this line makes sure that the picked ally is the one with the highest trading power.
                  //ModuloInteger will make sure that the number "i" is always within the bound "allies", which would make (i == 6 out of allies == 4) into i == 2, and so on.
                  //This way i will loop back to the first player when i have gone through all of them. 
                  set temp_player = Player(i)
                  call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPortPacific)) //Group ports owned by the target ally
                  if CountUnitsInGroup(g2) != 0 then //Only start sending ships if the ally has ports in the first place. 
                                                     //Sadly, if he doesn't, this port will not send any ships as it is now. 
                      set u = GetClosestUnitInGroup(x, y, g2) //I make sure that i send to the closest of the ports. 
                      set ship = CreateUnit(Player(p), 'h01B', x, y, 0.)
                      call IssueTargetOrder(ship, "channel", u) //This is a dummy ability i use to trace then the ship has reached it's destination. 
                  endif
                  call GroupRemoveUnit(g1, u)
              endloop
            endif
            
            set i = i+1
        endloop
        
        
        //===========================================================================//
        //==Everything below is just the same thing as above, for the other theatre==//
        //===========================================================================//
        
        set p = 0
        set i = 0
        set m = 0
        set n = 0
        set i2 = 0
        set u = null
        
        loop
            exitwhen p > 11
            
            set allies = 0
            set i = 0
            
            loop
                exitwhen i > 11
                if GetPlayerAlliance(Player(p), Player(i), ALLIANCE_SHARED_VISION) == true then
                    set allies = allies+1
                endif
                set i = i+1
            endloop
            
            set i = 0

            if allies != 0 then
              set temp_player = Player(p)
              call GroupEnumUnitsOfType(g1, UnitId2String('h00R'), Filter(function GetPlayerPortEurope)) //Group ports owned by the player
              loop
                  //in this loop, the index of the allies is 'i'. 
                  set u = FirstOfGroup(g1)  //...but the loop ends when the player runs out of ports.
                  exitwhen u == null
                  
                  set x = GetUnitX(u)
                  set y = GetUnitY(u)
                  
                  
                  loop
                      exitwhen i2 > 11
                      set b = Player(i2)
                      if target != Player(i2) and IsPlayerAlly(target,b) then
                          set pl[n] = b
                          set n = n + 1
                      endif
                      set i2 = i2 + 1
                  endloop
                  set i2 = 0
                  loop
                     exitwhen n == 1 or i2 >= n
                      set m = i2
                      loop
                          set m = m + 1
                          exitwhen m >= n
                          if numports[GetPlayerId(pl[i2])] < numports[GetPlayerId(pl[m])] then
                              set q = pl[i2]
                              set pl[i2] = pl[m]
                              set pl[m] = q
                          endif
                      endloop
                      set i2 = i2 + 1
                  endloop
                  
                  
                  set target = pl[ModuloInteger(i, allies)] //this line makes sure that the picked ally is the one with the highest trading power.
                  set temp_player = Player(i)
                  call GroupEnumUnitsOfType(g2, UnitId2String('h00R'), Filter(function GetPlayerPortEurope)) //Group ports owned by the target ally
                  if CountUnitsInGroup(g2) != 0 then
                      set u = GetClosestUnitInGroup(x, y, g2)
                      set ship = CreateUnit(Player(p), 'h01B', x, y, 0.)
                      call IssueTargetOrder(ship, "channel", u)
                  endif
                  call GroupRemoveUnit(g1, u)
              endloop
            endif
            
            set i = i+1
        endloop
    
    endfunction
    
    private function IsUnitHarbour takes nothing returns boolean
        local integer p = GetPlayerId(GetOwningPlayer(GetFilterUnit()))
        if GetUnitTypeId(GetFilterUnit()) == 'h00R' then
            set numports = numports + 1
            return true
        endif
        return false
    endfunction
    
    private function Init takes nothing returns nothing
        local integer i = 0
        local group g = CreateGroup()
        set interval = CreateTimer()
        call TimerStart(interval, 20, true, function onLoop)
        
        loop
            exitwhen i > 11
            call GroupEnumUnitsOfPlayer(g, Player(i), Filter(function IsUnitHarbour))
            call GroupClear(g)
            set i = i+1
        endloop
        
    endfunction

endlibrary
 
UnitId2String will bug after the game has loaded.

You should be using global groups, as has been mentioned before, that
never get destroyed.

In fact, if you do it right you can use "bj_lastCreatedGroup" for almost
everything, so you never even have to create it.

Delete this line from IsUnitHarbor: "return true"

Delete the GroupClear line as well from the loop, the group automatically
clears the next time you enumerate it anyway.

Instead of using "local integer i" in both of those functions, use a global
integer so you don't have to keep doing "GetPlayerId(GetOwningPlayer(GetFilterUnit()))"
which is obviously redundant.
 
Status
Not open for further replies.
Top