1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[Trigger] Garrison into neutral building and change ownership

Discussion in 'Triggers & Scripts' started by Hankxiety, Sep 1, 2018.

  1. Hankxiety

    Hankxiety

    Joined:
    Sep 1, 2018
    Messages:
    13
    Resources:
    0
    Resources:
    0
    In my map, neutral buildings are taken over by garrisoning a player's unit inside. Emphasis is on commandeering existing structures. Building or repairing will be time and resource-intensive by design.

    The solution I've worked out is susceptible to abuse and another avenue is needed.

    The Big Picture

    Before I explain the issue, let me first share the different neutral buildings and how they will function differently:
    • orc burrow
      • +10 food
      • Cargo Hold ability modified to hold 1 peon-type unit.
        • haven't decided if I want an attack function from this.
      • Creates a farmstead (Undead blight) on which other farms cannot be constructed.
    • watchtower
      • based on orc burrow unit.
      • Cargo Hold ability modified to hold 4 or more ground units (non-peon).
        • attack-speed increases as more units are added (just like orc burrow).
    • lumber mill
      • Cargo Hold ability modified to hold 1 peon-type unit.
    • town hall
      • uncertain how I want to use the Cargo Hold ability and which type of units it will garrison, but this will enable players to harvest gold from a gold mine.

    My ad hoc solution

    I gave the orc peon an ability based on Purge (orc shaman). When targeting a neutral structure, that neutral structure will cast Devour (kodo) on the casting peon.

    Here's that trigger. Note that by "farm" I mean "burrow":

    • Control Farm
      • Events
        • Unit - A unit Begins casting an ability
      • Conditions
        • ((Ability being cast) Equal to Control Farm ) and (((Owner of (Target unit of ability being cast)) Equal to Neutral Passive) and ((Unit-type of (Target unit of ability being cast)) Equal to Orc Burrow))
      • Actions
        • Unit - Change ownership of (Target unit of ability being cast) to (Owner of (Casting unit)) and Change color
        • Unit - Order (Target unit of ability being cast) to Orc Kodo Beast - Devour (Casting unit)


    So far, so good. But I want the farm to return to neutral when a peon leaves the burrow.

    I thought I figured this out with the second trigger:

    • Lose Control of Farm
      • Events
        • Unit - A unit Finishes casting an ability
      • Conditions
        • (Ability being cast) Equal to Stand Down
        • (Unit-type of (Triggering unit)) Equal to Orc Burrow
      • Actions
        • Unit - Change ownership of (Casting unit) to Neutral Passive and Change color


    The problem

    This works if you select the burrow and click the ability "Stand Down". It doesn't work if you unload the peon by clicking on the portrait. He leaves the burrow and it stays in your ownership.

    My assessment

    From playing with this and doing a little reading, it seems unlikely that I can do this using straight-forward Events and Conditions. (Update: I was wrong, it is possible using order(unload).)

    A Hive member asked about this very thing in March 2010: how can i make a unit garrison inside a neutral building and change its owner

    That's where I got the idea to use Devour, because I couldn't get Battle Stations to work. If anyone has ideas to make Battle Stations work without Devour, I'm all ears (think it'd be a bit more elegant, no?).

    Others alluded to solutions involving "custom data to control units count (0-4)". That same user made an other post I didn't really understand:

    I'm assuming this guy is right (or close).

    Asking for guidance
    • Can someone help me understand the above comment?
    • Will that comment, or any others in that thread, help solve my problem?
    • Is there a simple enough solution that you can modify my triggers to work or write sample code?
    • Do I need to be directed to a particular tutorial in order to help myself?

    I've done my best to research this problem further but didn't turn anything up. If anyone is able to find and share a relevant thread, that'd be great.
     
    Last edited: Sep 2, 2018
  2. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    2,910
    Resources:
    1
    Spells:
    1
    Resources:
    1
    I'm not sure that it specifically interfaces with the Battle Stations ability, but you can use this system to enable a "unit is unloaded" event. It may fire and give you the right information. If it does, what the user you quoted meant was:
    • Events
      • -------- loaded event --------
      • Game - CargoEvent Becomes Equal to 1.00
    • Conditions
    • Actions
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • Custom value of CargoTransportUnit[UDex] equal to 0 //it had no loaded units before
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Owner of (Triggering Unit)) and change color
      • Set Custom Value of CargoTransportUnit[UDex] to ((Custom value of CargoTransportUnit[UDex]) + 1)
    • -------- --------
    • -------- --------
    • Events
      • -------- unloaded loaded event --------
      • Game - CargoEvent Becomes Equal to 2.00
    • Conditions
    • Actions
      • Set Custom Value of CargoTransportUnit[UDex] to ((Custom value of CargoTransportUnit[UDex]) - 1)
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • Custom value of CargoTransportUnit[UDex] equal to 0 //it's empty now
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Neutral Passive) and change color
     
  3. Hankxiety

    Hankxiety

    Joined:
    Sep 1, 2018
    Messages:
    13
    Resources:
    0
    Resources:
    0
    Thanks for interpreting that.

    The difficulty stems from there being an available loading event:

    • Events
    • Unit - Peon Is loaded into a transport


    But no unloading event.

    So if I'm understanding properly, if a loading event takes place (above), there is a way to detect the number of units inside of a transport. We need some work-around.

    As I'm typing this, suddenly have an idea:

    • Events
    • Unit - Peon Starts the effect of an ability.


    I'll put a dummy passive aura on the peon which should only be active when not transported (right)? That should allow me to make use of the code above, then.

    Have to go right now, will need to test this later.
     
  4. pick-a-chew

    pick-a-chew

    Joined:
    Jul 15, 2007
    Messages:
    691
    Resources:
    4
    Icons:
    2
    Maps:
    2
    Resources:
    4
    Unloading via click isn't an ability cast (hopefully for obvious reasons), you should find that the following event triggers when you click something out of a burrow:

    • Melee Initialization
      • Events
        • Unit - A unit Is issued an order targeting an object
      • Conditions
        • (Issued order) Equal to (Order(unload))
      • Actions
        • Game - Display to (All players) the text: Hello
     
  5. Hankxiety

    Hankxiety

    Joined:
    Sep 1, 2018
    Messages:
    13
    Resources:
    0
    Resources:
    0
    Well that wasn't obvious to me because I wasn't acquainted with order strings, but it certainly is obvious now.

    Great, this works. Big thanks.

    Only change I made is the Action, of course:

    • Actions
      • Unit - Change ownership of (Triggering unit) to Neutral Passive and Change color


    I used "Triggering Unit" because I didn't see anything more specific (ie. "Unit Issuing Order"). Don't know if that's the syntax I should be using, but it worked.

    Now, I need to update the code so that it'll work for structures that can hold more than one unit.

    Questions:
    • I suppose I need to use arrays to store and modify the amount of units in a given garrison, right?
    • Do I need to be creating variables for the garrisons (buildings) or the units inside the garrison?
    • Are "Unit Group" variables the key to making this thing work?



    Update: I'm lost
    (Not sure this qualified as an exception to the double posting rule, so just updating this existing post.)

    Alright, I've spent the last couple of hours trying to apply what Pyrogasm shared.

    I assume your journeyman mapmaker would be able to quickly digest and replicate that trigger. However, I'm basically a complete beginner and was unable to.

    So I'm going to show exactly where I'm getting lost, and hopefully someone can make things nice and basic for me.

    Disclaimer: I don't have any experience with arrays or the UDex system. That should come as no surprise.

    What's up with CargoEvent?

    • Events
      • Game - CargoEvent Becomes Equal to 1.00


    This means there's another trigger in which CargoEvent becomes equal to 1.00, right? I'm guessing it would start something like this:

    • Events
      • Unit - A unit Is loaded into a transport


    Aside from making a guess at how this hypothetical trigger might start, I have no clue what the rest of it would look like. Please correct me if I'm off. Moving along.

    Confused about CargoTransportUnit[]

    • Events
      • Game - CargoEvent Becomes Equal to 1.00
    • Conditions
    • Actions
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Custom value of CargoTransportUnit[UDex] equal to 0 //it had no loaded units before
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Owner of (Triggering Unit)) and change color
      • Set Custom Value of CargoTransportUnit[UDex] to ((Custom value of CargoTransportUnit[UDex]) + 1)


    To my untrained eye it looks like were first doing an integer comparison with CargoTransportUnit[UDex] followed by a unit comparison.

    I'm not able to replicate this, as the variable CargoTransportUnit[] is not an option for a unit comparison.

    As mentioned, I'm not sure how UDex plays into this. I don't know the first thing about putting a UDex system in place. It's a system, right? (I don't know what that means.) If that's a simpler way of making this happen than using default settings on World Editor, then I'm open to learning it.

    Though in my early planning stages, this Garrisoning function is probably the most complex triggering I plan to do with my map and I'm hoping for smooth sailing from here. So my preference is the most accessible thing to learn and apply.

    Unloading Event

    • Events
      • -------- unloaded loaded event --------
      • Game - CargoEvent Becomes Equal to 2.00
    • Conditions
    • Actions
      • Set Custom Value of CargoTransportUnit[UDex] to ((Custom value of CargoTransportUnit[UDex]) - 1)
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • Custom value of CargoTransportUnit[UDex] equal to 0 //it's empty now
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Neutral Passive) and change color


    Wait -- an unloading event occurred, but instead of the CargoEvent value going down, as I would expect... it goes up to 2.00. Which means I don't know what the CargoEvent variable is supposed to represent.

    Clearly there's a triggering technique that I don't know about here. You can probably see how limited my knowledge is on this subject.

    Thanks for reading. Anyone that feels like they can help, would love if you chimed in.
     
    Last edited: Sep 2, 2018
  6. pick-a-chew

    pick-a-chew

    Joined:
    Jul 15, 2007
    Messages:
    691
    Resources:
    4
    Icons:
    2
    Maps:
    2
    Resources:
    4
    I took a more in depth look at your problem. There's lots of ways you could make a solution:

    • Use variables to track loaded/unloaded units.
    • Use Hashtables.
    • Use a property you can dynamically update on your burrows (e.g. custom value (not recommended) or an ability).
    I put together a very basic system using a hashtable that works. Oddly enough there was no order string or ability cast when a unit loads into a burrow, but the event for when a unit is transported works. When units are unloaded via standdown this also doesn't trigger order events but when this ability is cast one can assume that all garrisoned units will be emptied out.

    You can look at my solution and see if it helps you. It's not perfect but i believe it does what you want.
     

    Attached Files:

  7. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    2,910
    Resources:
    1
    Spells:
    1
    Resources:
    1
    I'm real sorry @Hankxiety I fucked up and said "use this system" and then forgot to include a link to it: GUI Unit Event v2.5.2.0

    That should resolve all your confusion and questions about where CargoEvent come from and all the unit variables being assigned properly. They are created and set by the system! The additional problem with this that I did not forsee before I posted last time is that it already uses Custom Value to keep track of which unit is which (where UDex comes into play-- you're right it is a unit indexer system), so you cannot use that to store the amount of units currently loaded inside. Instead you will have to create a new integer array variable and use that instead with UDex as the array index we're modifying.

    • Events
      • -------- loaded event --------
      • Game - CargoEvent Becomes Equal to 1.00
    • Conditions
    • Actions
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • GARRISON_ARRAY[UDex] equal to 0 //it had no loaded units before
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Owner of (Triggering Unit)) and change color
        • Else - Actions
      • Set GARRISON_ARRAY[UDex] to (GARRISON_ARRAY[UDex] + 1)
    • -------- --------
    • -------- --------
    • Events
      • -------- unloaded event --------
      • Game - CargoEvent Becomes Equal to 2.00
    • Conditions
    • Actions
      • Set GARRISON_ARRAY[UDex] to (GARRISON_ARRAY[UDex] - 1)
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • GARRISON_ARRAY[UDex] equal to 0 //it's empty now
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Neutral Passive) and change color
        • Else - Actions



    Now, you CAN also just use the order trigger that pick-a-chew posted above, but be aware that if you start using Custom Value to store information in your map you won't be able to use any other system/resource that requires the use of it (usually through a unit indexer) without breaking everything you've done that uses CV. Not generally recommended, though if you feel confident you won't run into this issue you can avoid having to import the system I linked. It would look like this:

    • Events
      • Unit - A unit Is loaded into a transport
    • Conditions
    • Actions
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • (Custom Value of (Loading Unit)) equal to 0 //it had no loaded units before, loading unit is the building it's going into
        • Then - Actions
          • Unit - Change ownership of (Loading Unit) to (Owner of (Triggering Unit)) and change color
        • Else - Actions
      • Unit - Set Custom Value of (Loading Unit) to (Custom Value of (Loading Unit) + 1)
    • -------- --------
    • -------- --------
    • Events
      • Unit - A unit Is issued an order targeting an object
    • Conditions
      • (Issued order) Equal to (Order(unload))
    • Actions
      • Unit - Set Custom Value of (Target unit of issued order) to (Custom Value of (Target unit of issued order) - 1)
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • (Custom Value of (Target unit of issued order)) equal to 0 //it's empty now
        • Then - Actions
          • Unit - Change ownership of (Target Unit of Issued Order) to (Neutral Passive) and change color
        • Else - Actions


    You can also use a hashtable as pick-a-chew suggested to avoid having to import the system and circumventing any issues with using Custom Value for this in your map.
     
  8. Hankxiety

    Hankxiety

    Joined:
    Sep 1, 2018
    Messages:
    13
    Resources:
    0
    Resources:
    0
    Response to pick-a-chew
    That makes it perfect, in my eyes. Thanks for going through the trouble, major help.

    Now that it works, I want to make sure I understand it.

    I spent a couple of hours testing and digesting your code. A lot of questions popped up as I was reading it, but was able to find answers for most of them.

    Namely, I wasn't sure how hashtables were different from arrays. This tutorial cleared that up in an eloquent way:

    I was really confused by the following actions until I realized that '0' was not referencing the 'x-axis', as I would expect from an array, but the 'y-axis'. Right?

    • Set GarrisonInteger = (Load 0 of (Key (Transporting unit)) from GarrisonHash)
    • Set GarrisonInteger = (GarrisonInteger + 1)
    • Hashtable - Save GarrisonInteger as 0 of (Key (Transporting unit)) in GarrisonHash


    Still fuzzy on what's meant by a Handle -- that's the 'x-axis', right? And if that's right, then Handle ID is referring to it's position on the 'x-axis'?. Some clarity on that would be illuminating, no doubt.

    What's also unresolved for me is where and when, exactly, "Transporting Unit" is added to the hashtable "GarrisonHash". I'm gonna make a guess in the commented sections below. Am I right?

    Code (Text):

    ACTION TYPE: Set Variable
            VARIABLE: GarrisonInteger
            FUNCTION: Hashtable - Load Integer Value (hashtable)    // this function can be used to designate where on the 'y-axis' we are storing data, yes?
                VALUE: 0
                FUNCTION: Hashtable - Get Handle ID                        // my guess: this the function we use to call an existing handle or set a new one.
                    FUNCTION: Event Response - Transporting Unit       // my guess: if transporting unit does not yet belong to the hashtable, it's assigned a Handle ID here.
            VARIABLE: GarrisonHash
    Hope that's easy enough to read. I used this formatting to try to understand the triggers.


    Response to Pyrogasm


    Okay, now I can see why those values were set for the real variable "CargoEvent". The System Description says a whole lot that explains that trigger:

    Now that's been cleared up. As for your other point, I think I follow:

    So I take that to mean this trigger cannot work using just one array, even if we're harnessing the power of UDex.

    • We need an array to refer the different garrisons: CargoEvent[UDex]
    • We need another array to store the number of units in the garrisons stored in CargoEvent[UDex]: GARRISON_ARRAY[UDex]
    The alternative, then, is a hashtable which can store these two data points -- the garrison and the number of units in the garrison -- on the x- and y-axes, respectively.

    I think I'm getting the hang of this. Thank you!

     
    Last edited: Sep 3, 2018
  9. pick-a-chew

    pick-a-chew

    Joined:
    Jul 15, 2007
    Messages:
    691
    Resources:
    4
    Icons:
    2
    Maps:
    2
    Resources:
    4
    Different people may tell you different things but i personally visualize a hashtable as a table... I think of it this way as I'm scientifically minded (axis for me is limited to numbers). In the hashtable i made for you, it's simply:

    Hashtable 0
    Handle of transporting unit GarrisonInt


    To my mind it's arbitrary as to what you use for the X and Y axis. What's more important is that when you save a variable, you load it from the place you saved it, so if you saved at 0 of Key(Transporting Unit) you load from that location and not Key(Transporting Unit) of 0.

    Handle is simply a reference to an entity that isn't a value by its default nature, integers/reals can simply be saved into a hashtable without any problem. However if you want to save something more complex, such as a unit or special effect, they need to be referenced in a way that can be recalled so they are given an ID. This is, at least my interpretation of it (i am not a coder by profession :p).

    I think of hashtables as dynamic constructs. You can add handles to them as you want and they will exist in there until you clear them out with:
    • Hashtable - Clear all child hashtables of child (Handle) in Hashtable
     
  10. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    2,910
    Resources:
    1
    Spells:
    1
    Resources:
    1
    No, CargoEvent is just a real variable that is used by the system I linked in order to "create" the "unit is unloaded" event. It doesn't need to be an array and you don't need to touch it at all once it's in your variable editor; the system does all of that for you. When it detects an unload event it will automatically set the value of CargoEvent to 2.00, which acts as the "event" that fires your unloading trigger. Similarly, when it detects a load event it will automatically set the value of CargoEvent to 1.00, which acts as the "event" that fires your loading trigger.

    The reason we need GARRISON_ARRAY is because if you try to set the Custom Value of the holding units it will mess up the Unit Indexer because the UI uses Custom Value of each unit to give each unit a unique ID. Because each unit has a unique ID, you can be sure that if you use that ID as an array index to keep track of the units garrisoned inside that specific unit nothing will randomly overwrite it because of a unit-ID-number collision.

    I did make another error here when I suggested you do GARRISON_ARRAY[UDex]. The error is using UDex. As the system specifies, the UDex = Custom Value of (unit that triggered the event) which will be the unit that is being garrisoned, not the unit it's garrisoned in. We want to store the information about how many units are inside under the unit index of the garrison itself, else when we try to set it GARRISON_ARRAY[] +/-1 we'll be getting different UDex numbers for each unit that loads in and out! To solve this, we'll make one more integer variable and store into it the custom value of the garrison itself (its unit id). Then we use that as the index for our array:

    finally correct
    • Events
      • -------- loaded event --------
      • Game - CargoEvent Becomes Equal to 1.00 //no array here
    • Conditions
    • Actions
      • Set GARRISON_ID = (Custom Value of (CargoTransportUnit[UDex]))
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • GARRISON_ARRAY[GARRISON_ID] equal to 0 //it had no loaded units before
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Owner of (Triggering Unit)) and change color
        • Else - Actions
      • Set GARRISON_ARRAY[GARRISON_ID] to (GARRISON_ARRAY[GARRISON_ID] + 1)
    • -------- --------
    • -------- --------
    • Events
      • -------- unloaded event --------
      • Game - CargoEvent Becomes Equal to 2.00
    • Conditions
    • Actions
      • Set GARRISON_ID = (Custom Value of (CargoTransportUnit[UDex]))
      • Set GARRISON_ARRAY[GARRISON_ID] to (GARRISON_ARRAY[GARRISON_ID] - 1)
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditoins
          • GARRISON_ARRAY[GARRISON_ID] equal to 0 //it's empty now
        • Then - Actions
          • Unit - Change ownership of CargoTransportUnit[UDex] to (Neutral Passive) and change color
        • Else - Actions


    You're very close to fully understanding hashtables. I will attempt to nudge you in the right direction by giving an example. It is fine to think of the 2 keys for hashtables as 2 dimensions of integers in X/Y space, but you can also use a string for either of them to make it more clear to you what you are storing at a particular location. I'm gonna call your hashtable Table[x][y] for now, simulating the two axes/keys you could use to store... but be aware that the way GUI lays it out is written as Store y of x in TABLE, not Store x of y in TABLE, so the order you'd use would be reversed of my example. This is important because you usually want to put all the information about "one" object under a single x key for that object with ys holding the different data you want to store, not under a single y with multiple xes because that becomes very hard to flush the data from and clean up when necessary.

    Say you generate kill gold and lumber manually for all units/players on your map and want to store the data of what each unit-type is worth in gold and lumber in your Table[x][y] instead of an array. A rudimentary way to do this would be to cache the data on map init in something like this:
    index value
    Table[x=0][y=0] "footman"
    Table[x=0][y=1] 10
    Table[x=0][y=2] 1
    Table[x=1][y=0] "knight"
    Table[x=1][y=1] 35
    Table[x=1][y=2] 6

    But here you have to know which index is for gold, [x][1], and which for lumber, [x][2], and to get the right data for each unit type you have to loop through the list of [x][0]s checking the unit's name vs what you cached. Not very efficient or easy to use, highly prone to user error. The next step would be to use "gold" and "lumber" as your y keys and then instead store everything under x values that are the Unit-Type of the unit. All unit-types are actually integers in base-36 (all letters + 0-9) and 'hfoo', for example, is the integer 813480. Normally 813480 is way outside array bounds (up to 8191 pre-1.29, larger after) so you can't use it as an array index like GoldAmount['hfoo'] but hashtables have no restrictions on the integers/strings used for keys in them. Note GUI won't let you use '' characters in integer input fields so you can't use this directly but it's just an example. You can then store it this way instead
    index value
    Table[x='hfoo'][y="gold"] 10
    Table[x='hfoo'][y="lumber"] 1
    Table[x='hkni'][y="gold"] 35
    Table[x='hkni'][y="lumber"] 6

    So when you want to know how much gold to give a player for killing a unit you just grab its unit type integer and then look up Table[ThatInteger]["gold"]. Nifty. Now we go one level deeper: suppose you want to be able to modify the resources that a specific individual footman or knight should reward on death. Perhaps every time a unit kills another unit it gains 1 additional lumber as a bounty. To do this we'll keep the table we used above but also store information about any specific units in a second separate table. We'll use the Unit ID (not unit-type) of the specific unit as our x value! Where do we get such a unit ID for that specific unit? That's where the Hashtable - Get Handle ID function comes in; it spits out a unique number for each unit that we can use. Every time you use that function on the same unit you'll get the same number. This function reads as Key (<some handle>) in GUI once you've used it, so don't get confused there. When we need to modify a unit's bonus bounty on it killing another unit we'll do these steps
    • Load Table[x=Key(<killer>)][y="bonus lumber"] into some variable
    • Increase that variable by 1
    • Save that variable into Table[x=Key(<killer>)][y="bonus lumber"]
    When we then need to properly figure out how much gold and lumber to give we'll load data from the cached values and from the value specific to the unit. If no value has been saved in Table[x][y] prior to it being loaded it will return 0, "", or null depending on the type of variable you're trying to load so there is no problem that may cause error here.
    • Load Table[x=Key(<dying unit>)][y="bonus lumber"] into var1
    • Load Table[x=Unit Type(<dying unit>)][y="gold"] into var2
    • Load Table[x=Unit Type(<dying unit>)][y="lumber"] into var3
    • Give the proper player var2 gold and var3+var1 lumber
     
  11. Hankxiety

    Hankxiety

    Joined:
    Sep 1, 2018
    Messages:
    13
    Resources:
    0
    Resources:
    0
    Response to pick-a-chew
    Okay, that's easy enough to understand. A hashtable can just as easily be visualized as a table.

    Thanks for these explanations, I think I'm getting the hang of it.

    In fact, I needed to make use of Handles to meet a new requirement:
    - It should change owner of the transporting unit to Neutral Passive when GarrisonInteger = 0.

    So, I added this line to your GarrisonLoad trigger:

    • Hashtable - Save Handle Of(Transporting unit) as 1 of (Key (Transporting unit)) in GarrisonHash


    And then added these lines to your GarrisonUnload trigger:

    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Load GarrisonInteger of (Key (Triggering unit)) from GarrisonHash) Equal to 0
      • Then - Actions
        • Wait 0.10 game-time seconds
        • Unit - Change ownership of (Load 1 of (Key (Ordered unit)) in GarrisonHash) to Neutral Passive and Change color
      • Else - Actions
        • Do nothing


    For GarrisonStandDown I removed the If statement and changed 'Ordered unit' to 'Casting unit'.

    For a while it was changing the ownership of the ground unit exiting the garrison to Neutral Passive. That's until I added the 'Wait' action, which solved the problem.

    I suppose, then, the table would look something like this:

    GarrisonHash
    0 1
    GarrisonInteger (Transporting Unit)


    I'm wondering if saving the Handle of (Transporting Unit) was redundant, though that's how I managed to make this work how I wanted it to.



    Response to Pyrogasm

    Got it. It's good to see examples of Real Variables being used like this. I'm certain I'll run into this again.

    Seems the advantage of using UDex is you don't have to define certain variables ('cargoEvent', in this case) which aren't defined in the GUI.

    So if I'm understanding correctly, that means we're changing the custom value of the units position in the array, not the custom value of the unit... because only one custom value can be assigned to an object, and custom values are used to designate unit IDs.

    I haven't installed UDex yet (worried I might break something...) but let me see if I can demonstrate my comprehension of your code by consolidating those two events into a single trigger.

    • Events
      • Game - cargoEvent Becomes Greater than 0.00
    • Conditions
    • Actions
      • Set garrisonID = (Custom Value of (cargoEvent[UDex]))
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If (Conditions)
          • garrisonArray[garrisonID] equal to 0 and cargoEvent equal to 1.00
        • Then - Actions
          • Unit - Change ownership of cargoTransportUnit[UDex] to (Owner of (Triggering Unit)) and change color.
        • Else - Actions
          • Set garrisonArray[garrisonID] to (garrisonArray[garrisonID] + 1)
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • cargoEvent equal to 2.00 and garrisonArray[garrisonID] equal to 0
        • Then - Actions
          • Unit - Change ownership of cargoTransportUnit[UDex] to (Neutral Passive) and change color.
        • Else - Actions


    Thanks, both of you. Now I can move on to other map requirements.

    Hope this was instructive for anyone else that followed along.
     
    Last edited: Sep 7, 2018
  12. Pyrogasm

    Pyrogasm

    Joined:
    Feb 27, 2007
    Messages:
    2,910
    Resources:
    1
    Spells:
    1
    Resources:
    1
    The Unit Indexer that GUI Unit Event 2.5.2.0 uses isn't a separate system, it's part of that system. If you've properly installed it it will have included the unit indexer trigger(s) and now you can get any unit's index whenever you want by loading its Custom Value.

    CargoEvent is not an array variable; it's a single real varaible that GUIUE sets. You don't need to make it yourself because it will be automatically generated by virtue of being used in the triggers you need to copy over to get GUIUE working; if you are going to use GUIUE you should delete any such variables you've made yourself before importing/installing it. At any rate Custom Value of (CargoEvent[UDex]) is not correct syntax because Custom Value expects a unit and you're giving it a real (only units and items have custom values, no other variable/object types). You have the right idea but the reference to the unit you're trying to get to is actually CargoTransportUnit[UDex]. When a load/unload event is detected the system also sets UDex and the correct CargoTransportUnit[] before changing CargoEvent to 1.00/2.00 so that you can use Triggering Unit to access the unit that is being loaded/unloaded and CargoTransportUnit[UDex] to access the unit that is doing the loading/unloading.

    It's not more efficient to have it all in one trigger. In fact, from a code execution standpoint it's actually less because of the If-blocks. You do save a negligible number of bytes by having fewer triggers, but map size isn't really a Bnet concern any more. I wouldn't recommend using "Greater than 0.00" because I have no idea what the system does internally between events. It might set the variable to 1.5 as an intermediary step or something else entirely; you should only use "equal to" for variable-setting-based events. Your example trigger also does not decrease garrisonArray when units unload, so it will never properly change back to neutral passive. All of it in a single trigger would actually look like this:

    • Events
      • Game - CargoEvent Becomes equal to 1.00
      • Game - CargoEvent Becomes equal to 2.00
    • Conditions
    • Actions
      • Set garrisonID = (Custom Value of (CargoTransportEvent[UDex]))
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If (Conditions)
          • CargoEvent equal to 1.00
        • Then - Actions
          • If (All conditions are true) then do (Then Actions) else do (Else Actions)
            • If (Conditions)
              • garrisonArray[garrisonID] equal to 0
            • Then - Actions
              • Unit - Change ownership of cargoTransportUnit[UDex] to (Owner of (Triggering Unit)) and change color.
            • Else - Actions
          • Set garrisonArray[garrisonID] to (garrisonArray[garrisonID] + 1)
        • Else - Actions
      • If (All conditions are true) then do (Then Actions) else do (Else Actions)
        • If (Conditions)
          • CargoEvent equal to 2.00
        • Then - Actions
          • Set garrisonArray[garrisonID] to (garrisonArray[garrisonID] - 1)
          • If (All conditions are true) then do (Then Actions) else do (Else Actions)
            • If (Conditions)
              • garrisonArray[garrisonID] equal to 0
            • Then - Actions
              • Unit - Change ownership of cargoTransportUnit[UDex] to (Neutral Passive) and change color.
            • Else - Actions
        • Else - Actions
     
  13. Hankxiety

    Hankxiety

    Joined:
    Sep 1, 2018
    Messages:
    13
    Resources:
    0
    Resources:
    0
    Can really tell you're scrutinizing my code! I appreciate that. You're catching a lot of things I'm sure I would have learned about the hard way later on.

    Okay, that's a helpful distinction.

    Understood. Looks like I just made a mistake when trying to replicate your code, typing 'CargoEvent' instead of 'CargoTransportUnit[UDex]' when setting variable 'garrisonID'.

    Good to know that, as well. Here I was, thinking I was being clever.

    Also a good point.

    Oh, I did miss that. Geez.