• 🏆 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!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

Help w Caravan System

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
Hello, I need some suggestions on which way would be the best way to record which resource a unit is carrying to base. Every turn the farms produce a resource which has to be delivered to the nearby town. The problem I'm facing is that there will be different resources and I need a good way to detect which and how many (perhaps) it's carrying.

Option 1: The Caravan Unit is given one or more items representing the resource. Perhaps too many calls, with adding/removing items e.t.c. ?
Pro: Can carry multiple resources.
Con: Items...?

Option 2: A temporary pool of caravan units that are collapsed once the caravan reaches it's destination (might be too system heavy, since there will be many caravans?)
Con: Might be too many loops if you have alot of units on the map?
Pro: Very flexible.

Option 3: The custom value of the unit represents the resource and you can only send the same amount of that specific resource.
Con: Not flexible at all.
Pro: Simple.

Option 4: I add add a buff to the unit representing the cargo carried.
Pro: Nice visual effect. Can have different amount in the cargo.
Con: Can only carry one resource type.


The option seem to me, is it worth cutting down the numbers of caravans running around but having to make some kind of pool system?

Option 5: ???


There is something wrong with the index I belive.

  • Setup
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Custom script: set udg_LocalPlayer = GetLocalPlayer()
      • Player Group - Add Player 1 (Red) to Team_hum
      • -------- Town 1 --------
      • Set Town[0] = Town Hall 0000 <gen>
      • -------- Town 2 --------
      • Set Town[1] = Town Hall 0002 <gen>
      • For each (Integer A) from 0 to 1, do (Actions)
        • Loop - Actions
          • Set Town_alive[(Integer A)] = True
          • Unit - Set the custom value of Town[(Integer A)] to (Integer A)
      • -------- Pre Placed Farms --------
      • Unit Group - Add Farm 0006 <gen> to Resource_food_g
      • Unit Group - Add Farm 0007 <gen> to Resource_food_g
      • Unit - Set the custom value of Farm 0007 <gen> to 1
JASS:
function Spawn_Farm_Caravan takes nothing returns nothing

    local player p = GetOwningPlayer(GetEnumUnit())
    local integer T_array = GetUnitUserData(GetEnumUnit())
    local real x = GetLocationX(GetUnitLoc(GetEnumUnit()))
    local real y = GetLocationY(GetUnitLoc(GetEnumUnit()))
    local item i
    local unit u

    if (udg_Town_alive[T_array] == true) then
        if (IsPlayerInForce(p, udg_Team_hum) == true) then
            set u = CreateUnit(p, 'hrdh', x,y, 00)
            else
            set u = CreateUnit(p, 'oosc', x,y, 00)
        endif

        // Add unit to Caravan Index
        call GroupAddUnitSimple( u, udg_Caravan_group)
        set udg_Caravan_index_max = udg_Caravan_index_max + 1 
        set udg_Caravan[udg_Caravan_index_max] = u
        set udg_Caravan_destination[udg_Caravan_index_max] = udg_Town[T_array]
        call SetUnitUserData(u, udg_Caravan_index_max)


        call IssueTargetOrderBJ(u, "cripple", udg_Town[T_array])
        set i = CreateItem('ratc',x,y)
        call SetItemCharges(i, 5)
        call UnitAddItemSwapped(i,u)

        // Debug
        call SetUnitManaBJ(u, I2R(GetUnitUserData(u)) )

        set i = null
        set u = null
        set p = null
    endif
endfunction

function Trig_Turn_Actions takes nothing returns nothing
    call ForGroupBJ(udg_Resource_food_g, function Spawn_Farm_Caravan)
endfunction

//===========================================================================
function InitTrig_Turn takes nothing returns nothing
    local trigger t = CreateTrigger() 
    call TriggerRegisterTimerEventPeriodic(t, 10.00)
    call TriggerAddAction(t, function Trig_Turn_Actions)
    set t = null

This trigger is for when the destination is reached.
JASS:
function CheckForCaravan takes nothing returns boolean
    if (GetSpellAbilityId() == 'A000') then
        return true
    endif
endfunction

function Trig_Town_Pickup_Actions takes nothing returns nothing
    local integer i
    local unit u = GetTriggerUnit()
    if (GetItemTypeId(UnitItemInSlotBJ(u, 1)) == 'ratc') then
        set i = GetItemCharges(UnitItemInSlotBJ(u, 1))
        call DisplayTextToForce(GetPlayersAll(), ("Food carried: " + I2S(i)))
    endif

    call RemoveUnit(u)
    //Refresh Caravan Index
    set i = GetUnitUserData(u)
    loop
        exitwhen i == udg_Caravan_index_max
        set udg_Caravan[i] = udg_Caravan[i + 1]
        set udg_Caravan_destination[i] = udg_Caravan_destination[i + 1]
        call SetUnitUserData(udg_Caravan[i], GetUnitUserData(udg_Caravan[i + 1]))
        call SetUnitManaBJ(udg_Caravan[i], I2R(GetUnitUserData(udg_Caravan[i])) ) //Debug
    endloop
    set udg_Caravan[udg_Caravan_index_max] = null
    set udg_Caravan_destination[udg_Caravan_index_max] = null
    set udg_Caravan_index_max = udg_Caravan_index_max - 1
    call GroupRemoveUnitSimple(u, udg_Caravan_group)

    // Debug
    call DisplayTextToForce( GetPlayersAll(), ("Caravan Index Max =" + I2S(udg_Caravan_index_max) ) )
    call DisplayTextToForce( GetPlayersAll(), ("Units In Caravan Group = " + I2S(CountUnitsInGroup(udg_Caravan_group)) ) )
    call SetUnitManaBJ(u, I2R(GetUnitUserData(u)) )

    set u = null

endfunction

//===========================================================================
function InitTrig_Town_Pickup takes nothing returns nothing
    local trigger t = CreateTrigger()
    set gg_trg_Town_Pickup = t
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_FINISH )
    call TriggerAddCondition(t, Condition(function CheckForCaravan))
    call TriggerAddAction(t, function Trig_Town_Pickup_Actions)
    set t = null
endfunction

This trigger is for moving stopped Caravans:
  • Caravan Stopped
    • Events
      • Time - Every 5.00 seconds of game time
    • Conditions
      • (Number of units in Caravan_group) Greater than 0
    • Actions
      • Unit Group - Pick every unit in Caravan_group and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Current order of (Picked unit)) Equal to (Order(hold position))
            • Then - Actions
              • Unit - Order (Picked unit) to Undead Necromancer - Cripple Caravan_destination[(Custom value of (Picked unit))]
            • Else - Actions

So, how would you do it?

*Edit also I'm not sure how to check if it can reach it's destination, perhaps there is such a sytem already.
 
Last edited:
Level 7
Joined
Jan 28, 2012
Messages
266
I would use a Unit indexer (like bribes unit Indexer on the Hive)
and then I would have a bunch of arrays and use the units index to store the data.

Option 2: A temporary pool of caravan units that are collapsed once the caravan reaches it's destination (might be too system heavy, since there will be many caravans?)
Con: Might be too many loops if you have a lot of units on the map?
Pro: Very flexible.

I think it would be look good to have each caravan consist of a couple of units.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
I decided to go with the items, a unit indexer might be too extensive if you have say +50 units? It's true that a caravan index could have more units in the caravan, will be keeping that in mind.

There is another issue that needs to be resolved though. The system currently works the following: A caravan unit is created. It uses a spell on the destination, and everything works fine. However if the path is blocked it stops the cast spell order. Which is good, but I can't detect it??? How would one detect it?

This does not work:
  • Destination Halt
    • Events
      • Unit - A unit Is issued an order with no target
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Pack Horse
    • Actions
      • Game - Display to (All players) the text: Caravan Halted!
It apears I will be using a unit indexer afterall, since I know of no other method to check if the unit has stopped then to compare its position to what it was some time ago.
 
Last edited:
Level 25
Joined
Jul 10, 2006
Messages
3,315
Get UnitIndexer and IsUnitMoving.
Every 5-10 seconds, compare each unit in the caravan's position to its former position, if the coordinates are the same, order it to retarget.


Instead of items, you could use abilities. (abilities that do nothing)
Check if level of ability >= 1 to see if a unit has the ability. You can also use level of ability for the amount of cargo being carried, although I wouldn't advise this for cargo loads >50 or so.

So data-wise,
- Each caravan is in the CaravanGroup unit group.
- Each caravan has a CaravanTarget[] variable (array index is the unit's custom value) for retargeting)
If you don't want to use abilities or items, you additionally have:
- Integer CargoType[] - what type of resource the unit is carrying.
- Integer CargoAmount[] - how much of the resource it is carrying.

EDIT:
It apears I will be using a unit indexer afterall, since I know of no other method to check if the unit has stopped then to compare its position to what it was some time ago.

You can periodically check the unit's current order.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
JASS:
        // add unit to Caravan Index
        // add unit to Caravan Index
        call GroupAddUnitSimple( u, udg_Caravan_group)
        set udg_Caravan_index_max = udg_Caravan_index_max + 1 
        set udg_Caravan[udg_Caravan_index_max] = u
        call SetUnitUserData(u, udg_Caravan_index_max)

JASS:
    //Refresh Caravan Index
    set i = GetUnitUserData(u)
    loop
        exitwhen i == udg_Caravan_index_max
        set udg_Caravan[i] = udg_Caravan[i + 1]
        set udg_Caravan_destination[i] = udg_Caravan_destination[i + 1]
        call SetUnitUserData(udg_Caravan[i], GetUnitUserData(udg_Caravan[i + 1]))
    endloop
    set udg_Caravan[udg_Caravan_index_max] = null
    set udg_Caravan_destination[udg_Caravan_index_max] = null
    set udg_Caravan_index_max = udg_Caravan_index_max - 1

So the benefit would be that I would only need one indexer in my map compared to what I did above which would have to be recreated for every trigger that needs indexing? Still would like to know if the above is a correctly made indexer.
 
Last edited:
Status
Not open for further replies.
Top