• 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.

[Solved] Recognizing invalid crafting attempts

Level 12
Joined
Jul 5, 2014
Messages
551
I have a magic box unit with the ability to craft various items. Here's one example:

  • Potion of Restoration
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Transmute Items
      • (((Casting unit) has an item of type Potion of Healing) Equal to True) and (((Casting unit) has an item of type Potion of Mana) Equal to True)
      • (Number of items carried by (Casting unit)) Equal to 2
    • Actions
      • Set Box = (Position of (Casting unit))
      • Item - Remove (Item carried by (Casting unit) of type Potion of Mana)
      • Item - Remove (Item carried by (Casting unit) of type Potion of Healing)
      • Special Effect - Create a special effect at Box using Abilities\Spells\Other\Charm\CharmTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Hero - Create Potion of Restoration and give it to (Casting unit)
      • Custom script: call RemoveLocation(udg_Box)
I'd like to create a notification (text or simply an error sound) that plays every time the player tries using "Transmute Items" with an empty box (that alone would be easy) or when the player tries combining items that are not among the recipes. However, I can't figure out how to recognize that and my attempts usually result a successful crafting with the error sound.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
You use this Event to detect that a unit is PREPARING to cast an ability, it's like the wind up:
  • Unit - A unit Begins casting an ability
Then you use this Event to detect that a unit has SUCCESSFULLY cast an ability:
  • Unit - A unit Starts the effect of an ability
You should NOT be using "Begins casting" if you're trying to detect a successful cast. An ability beginning it's cast can be interrupted, preventing it from spending mana, going on cooldown, launching it's effects, etc. However, it'll still trigger the "Begins casting" Event. This is easily exploitable, causes bugs, and not what you want MOST of the time.

But if I understand your situation then here's a setup that would work nicely:

1) Make sure that your Magic Box unit has an Art - Cast Point of 0.01 and an Art - Cast Backswing of 0.00. Modify these values in the Object Editor, they're at the very top. These values represent how long the unit prepares an ability (Cast Point) and how long a unit continues playing it's spell animation after a successful cast (Backswing).

2) Let's create a little system for these Item Combinations. You can start by creating the Variables and the Triggers. Then let's edit our main trigger which manages everything:
  • Transmute Box Begins
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Transmute Items
    • Actions
      • Set Magic_Box_Unit = (Triggering unit)
      • -------- --------
      • -------- The Magic_Box_Outcome variable represents the different possible outcomes: --------
      • -------- 1 = Successful item transmutation (combined 2 or more items). --------
      • -------- 2 = Not enough items (box has less than 2 items). --------
      • -------- 3 = No item combinations found (had enough items, but no matches). --------
      • -------- --------
      • -------- Default it to 3, it will be modified throughout the rest of these triggers: --------
      • Set Magic_Box_Outcome = 3
      • -------- --------
      • -------- Try to combine items: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of items carried by Magic_Box_Unit) Greater than 1
        • Then - Actions
          • Trigger - Run Transmute Box Check Items <gen> (ignoring conditions)
        • Else - Actions
          • -------- It has less than 2 items: --------
          • Set Magic_Box_Outcome = 2
      • -------- --------
      • -------- Determine the final outcome based on the previous actions: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Outcome Equal to 1
        • Then - Actions
          • -------- [SUCCESS] --------
          • Trigger - Run Transmute Box Success <gen> (ignoring conditions)
        • Else - Actions
          • -------- [FAILURE] --------
          • Trigger - Run Transmute Box Failure <gen> (ignoring conditions)

3) The Check Items trigger is a central place for us to Run our different types of item combinations (like Potion of Restoration). So you'd end up adding every single type of combination in here. I made a new one, Belt of Giant Strength, as part of the example:
  • Transmute Box Check Items
    • Events
    • Conditions
    • Actions
      • -------- Try to transmute the items in the magic box: --------
      • Trigger - Run Transmute Potion of Restoration <gen> (checking conditions)
      • Trigger - Run Transmute Belt of Giant Strength <gen> (checking conditions)

4) This is a modified version of your Potion of Restoration trigger. It's no longer dealing with the actual Creation/Removal/Special Effects stuff. Instead it uses Variables to track the Items used in this transmutation. This information will be used later on to handle the Creation/Removal/Special Effects:
  • Transmute Potion of Restoration
    • Events
    • Conditions
      • Magic_Box_Outcome Not equal to 1
    • Actions
      • -------- Define what item-types will be created and removed to make this combination: --------
      • Set Magic_Box_Created_Item = Potion of Restoration
      • Set Magic_Box_Removed_Item[1] = Potion of Mana
      • Set Magic_Box_Removed_Item[2] = Potion of Healing
      • -------- --------
      • -------- Check if the magic box has these items: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Magic_Box_Unit has an item of type Magic_Box_Remove_Item[1]) Equal to True
          • (Magic_Box_Unit has an item of type Magic_Box_Remove_Item[2]) Equal to True
        • Then - Actions
          • -------- This tells the system that it was a success and that we can move on: --------
          • Set Magic_Box_Outcome = 1
        • Else - Actions

5) Once that's all said and done we will either Run the Success trigger or the Failure trigger, depending on the final outcome.

Success:
  • Transmute Box Success
    • Events
    • Conditions
    • Actions
      • -------- Items were successfully transmuted. --------
      • -------- --------
      • Set Magic_Box_Point = (Position of Magic_Box_Unit)
      • Special Effect - Create a special effect at Magic_Box_Point using Abilities\Spells\Other\Charm\CharmTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation( udg_Magic_Box_Point )
      • -------- --------
      • Item - Remove (Item carried by Magic_Box_Unit of type Magic_Box_Removed_Item[1])
      • Item - Remove (Item carried by Magic_Box_Unit of type Magic_Box_Removed_Item[2])
      • Hero - Create Magic_Box_Created_Item and give it to Magic_Box_Unit

Failure:
  • Transmute Box Failure
    • Events
    • Conditions
    • Actions
      • -------- Items failed to transmute. --------
      • -------- --------
      • -------- Determine your error messages: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Outcome Equal to 2
        • Then - Actions
          • Set Magic_Box_Error_Message = Not enough items!
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Magic_Box_Outcome Equal to 3
            • Then - Actions
              • Set Magic_Box_Error_Message = No combinations found!
            • Else - Actions
      • -------- --------
      • -------- Display error message to the casting player: --------
      • Set Magic_Box_PG = (Player group((Owner of Magic_Box_Unit)))
      • Game - Display to Magic_Box_PG for 4.00 seconds the text: Magic_Box_Error_Message
      • Custom script: call DestroyForce( udg_Magic_Box_PG )
      • -------- --------
      • -------- Cancel the ability being cast: --------
      • Unit - Order Magic_Box_Unit to Stop.

Here are all of the Variables used:
1736445085585.png


A system like this allows for a lot more organization and separates the logic into parts which makes editing easier. Let's say in the future that you wanted to combine up to 3 Items, all it would take is two steps. First, set an extra Removed_Item[] variable in your specific item's "creation" trigger. Second, go into the Success trigger and Remove a [3rd] item like you're already doing with item's [1] and [2]. That's one additional "system" Action needed to introduce new functionality to the entire system.
 

Attachments

  • Magic Box Transmute.w3m
    20.7 KB · Views: 3
Last edited:
Level 12
Joined
Jul 5, 2014
Messages
551
You use this Event to detect that a unit is PREPARING to cast an ability, it's like the wind-up:
  • Unit - A unit Begins casting an ability
Then you use this Event to detect that a unit has SUCCESSFULLY cast an ability:
  • Unit - A unit Starts the effect of an ability
You should NOT be using "Begins casting" if you're trying to detect a successful cast. An ability beginning it's cast can be interrupted, preventing it from spending mana, going on cooldown, launching it's effects, etc. However, it'll still trigger the "Begins casting" Event. This is easily exploitable, causes bugs, and not what you want MOST of the time.

But if I understand your situation then here's a setup that would work nicely:

1) Make sure your Magic Box unit has an Art - Cast Point of 0.01 and an Art - Cast Backswing of 0.00. Modify these values in the Object Editor, they're at the very top. These values represent how long the unit prepares an ability (Cast Point) and how long a unit continues playing it's spell animation after a successful cast (Backswing).

2) Let's create a little system for these Item Combinations. Hopefully this isn't too complicated. Start by creating the Variables and the Triggers.

3) First let's have a central trigger for detecting the usage of Transmute Items:
  • Transmute Box Begins
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Transmute Items
    • Actions
      • Set Magic_Box_Unit = (Triggering unit)
      • -------- --------
      • -------- The Magic_Box_Outcome variable represents the different possible outcomes: --------
      • -------- 1 = Successful item transmutation (combined 2 or more items). --------
      • -------- 2 = Not enough items (box has less than 2 items). --------
      • -------- 3 = No item combinations found (had enough items, but no matches). --------
      • -------- --------
      • -------- Default it to 3, it will be modified throughout the rest of these triggers: --------
      • Set Magic_Box_Outcome = 3
      • -------- --------
      • -------- Try to combine items: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of items carried by Magic_Box_Unit) Greater than 1
        • Then - Actions
          • Trigger - Run Transmute Box Check Items <gen> (ignoring conditions)
        • Else - Actions
          • -------- It has less than 2 items: --------
          • Set Magic_Box_Outcome = 2
      • -------- --------
      • -------- Determine the final outcome based on the previous actions: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Outcome Equal to 1
        • Then - Actions
          • -------- [SUCCESS] --------
          • Trigger - Run Transmute Box Success <gen> (ignoring conditions)
        • Else - Actions
          • -------- [FAILURE] --------
          • Trigger - Run Transmute Box Failure <gen> (ignoring conditions)
We're splitting things up into multiple triggers to keep it nice and organized. We take advantage of Variables to track what's happening at the different stages and Run the appropriate triggers whenever necessary.

4) This Check Items trigger is a central place for us to Run our different types of item combinations (like Potion of Restoration). So you'd end up adding every single type of combination in here. I made a new one, Belt of Giant Strength, as part of the example:
  • Transmute Box Check Items
    • Events
    • Conditions
    • Actions
      • -------- Try to transmute the items in the magic box: --------
      • Trigger - Run Transmute Potion of Restoration <gen> (checking conditions)
      • Trigger - Run Transmute Belt of Giant Strength <gen> (checking conditions)
5) This is a modified version of your Potion of Restoration trigger. It's no longer dealing with the actual Creation/Removal/Special Effects, instead it simply sets a bunch of variables that will tell the system what to do next.
  • Transmute Potion of Restoration
    • Events
    • Conditions
      • Magic_Box_Outcome Not equal to 1
    • Actions
      • -------- Define what item-types will be created and removed to make this combination: --------
      • Set Magic_Box_Created_Item = Potion of Restoration
      • Set Magic_Box_Removed_Item[1] = Potion of Mana
      • Set Magic_Box_Removed_Item[2] = Potion of Healing
      • -------- --------
      • -------- Check if the magic box has these items: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Magic_Box_Unit has an item of type Magic_Box_Remove_Item[1]) Equal to True
          • (Magic_Box_Unit has an item of type Magic_Box_Remove_Item[2]) Equal to True
        • Then - Actions
          • -------- This tells the system that it was a success and that we can move on: --------
          • Set Magic_Box_Outcome = 1
        • Else - Actions
6) Once that's all said and done we will either Run the Success trigger or the Failure trigger, depending on the final outcome.

Success:
  • Transmute Box Success
    • Events
    • Conditions
    • Actions
      • -------- Items were successfully transmuted. --------
      • -------- --------
      • Set Magic_Box_Point = (Position of Magic_Box_Unit)
      • Special Effect - Create a special effect at Magic_Box_Point using Abilities\Spells\Other\Charm\CharmTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation( udg_Magic_Box_Point )
      • -------- --------
      • Item - Remove (Item carried by Magic_Box_Unit of type Magic_Box_Removed_Item[1])
      • Item - Remove (Item carried by Magic_Box_Unit of type Magic_Box_Removed_Item[2])
      • Hero - Create Magic_Box_Created_Item and give it to Magic_Box_Unit
Failure:
  • Transmute Box Failure
    • Events
    • Conditions
    • Actions
      • -------- Items failed to transmute. --------
      • -------- --------
      • -------- Determine your error messages: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Outcome Equal to 2
        • Then - Actions
          • Set Magic_Box_Error_Message = Not enough items!
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Magic_Box_Outcome Equal to 3
            • Then - Actions
              • Set Magic_Box_Error_Message = No combinations found!
            • Else - Actions
      • -------- --------
      • -------- Display error message to the casting player: --------
      • Set Magic_Box_PG = (Player group((Owner of Magic_Box_Unit)))
      • Game - Display to Magic_Box_PG for 4.00 seconds the text: Magic_Box_Error_Message
      • Custom script: call DestroyForce( udg_Magic_Box_PG )
      • -------- --------
      • -------- Cancel the ability being cast: --------
      • Unit - Order Magic_Box_Unit to Stop.
Here are all of the Variables used:
View attachment 507753
If I understand your version correctly, you're using the item-type array as a sort of joker card to refer to all the components in various recipes with this same two variables. I guess the items assigned to numbers 1 and 2 aren't running the risk of getting mixed up and not create the restoration potion, right?

A bigger issue is is the variety. I have tons of recipes with various numbers of items, sometimes it's just a single item transformed into another or 2 of the same items create a new one (which needed integer because otherwise the trigger doesn't understand that it should use, ex 2 healing potions instead of just one). So, do I need separate triggers each time a different number of components are being used?

Also, I wonder if your item-type array can recognize 2 of the same item types, like putting healing potion to both Removed_item(1) and Removed_item(2) and understanding to look for 2 potions?
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
A bigger issue is is the variety. I have tons of recipes with various numbers of items, sometimes it's just a single item transformed into another or 2 of the same items create a new one (which needed integer because otherwise the trigger doesn't understand that it should use, ex 2 healing potions instead of just one). So, do I need separate triggers each time a different number of components are being used?
The single item thing is a minor issue that can be solved pretty easily.

Edit 2: Alright, I think this update solves all of the potential issues you listed:

In Transmute Box Begins we have 3 changes. I introduced a new Integer variable called Magic_Box_Inventory_Size, then I check if the box has more than 0 items instead of more than 1, and I Run a new trigger called Transmute Box Reset Items:
  • Transmute Box Begins
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
    • Actions
      • Set Magic_Box_Unit = (Triggering unit)
      • Set Magic_Box_Inventory_Size = (Size of inventory for Magic_Box_Unit)
      • -------- --------
      • -------- The Magic_Box_Outcome variable represents the different possible outcomes: --------
      • -------- 1 = Successful item transmutation (combined 2 or more items). --------
      • -------- 2 = No items found. --------
      • -------- 3 = No item combinations found (not enough or invalid types). --------
      • -------- --------
      • -------- Default it to 3, it will be modified throughout the rest of these triggers: --------
      • Set Magic_Box_Outcome = 3
      • -------- --------
      • -------- Reset data: --------
      • Trigger - Run Transmute Box Reset Items <gen> (ignoring conditions)
      • -------- --------
      • -------- Try to combine items: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of items carried by Magic_Box_Unit) Greater than 0
        • Then - Actions
          • Trigger - Run Transmute Box Combine <gen> (ignoring conditions)
        • Else - Actions
          • -------- It has no items: --------
          • Set VariableSet Magic_Box_Outcome = 2
      • -------- --------
      • -------- Determine the final outcome based on the previous actions: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Outcome Equal to 1
        • Then - Actions
          • -------- [SUCCESS] --------
          • Trigger - Run Transmute Box Success <gen> (ignoring conditions)
        • Else - Actions
          • -------- [FAILURE] --------
          • Trigger - Run Transmute Box Failure <gen> (ignoring conditions)

Transmute Box Success now uses For Loops to Remove and Create items. Note how Magic_Box_Created_Item is now an Array - it acts similar to Removed_Items[] and allows for multiple rewards:
  • Transmute Box Success
    • Events
    • Conditions
    • Actions
      • -------- Items were successfully transmuted. --------
      • -------- --------
      • Set VariableSet Magic_Box_Point = (Position of Magic_Box_Unit)
      • Special Effect - Create a special effect at Magic_Box_Point using Abilities\Spells\Other\Charm\CharmTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation( udg_Magic_Box_Point )
      • -------- --------
      • -------- Remove matching items: --------
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Item - Remove (Item carried by Magic_Box_Unit of type Magic_Box_Removed_Item[Magic_Box_Slot_A])
      • -------- --------
      • -------- Create new items: --------
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Hero - Create Magic_Box_Created_Item[Magic_Box_Slot_A] and give it to Magic_Box_Unit

Here's the new Transmute Box Reset Items trigger which we use to avoid carrying unwanted data over to different transmutations:
  • Transmute Box Reset Items
    • Events
    • Conditions
    • Actions
      • -------- Reset all data to prevent unwanted creation and removal of items: --------
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Custom script: set udg_Magic_Box_Created_Item[udg_Magic_Box_Slot_A] = 0
          • Custom script: set udg_Magic_Box_Removed_Item[udg_Magic_Box_Slot_A] = 0

Here's the new Transmute Box Scan Inventory trigger which could likely be improved to be honest. It's job is to test each Inventory Slot to see if it has a required item, and tally how many it finds without counting the same one twice. Hopefully my logic is sound - I didn't test this:
  • Transmute Box Scan Inventory
    • Events
    • Conditions
    • Actions
      • Set Magic_Box_Needed = 0
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Custom script: if udg_Magic_Box_Removed_Item[udg_Magic_Box_Slot_A] != 0 then
          • -------- --------
          • Set Magic_Box_Needed = (Magic_Box_Needed + 1)
          • Set Magic_Box_Item_Was_Found[Magic_Box_Slot_A] = False
          • For each (Integer Magic_Box_Slot_B) from 1 to Magic_Box_Inventory_Size, do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Item-type of (Item carried by Magic_Box_Unit in slot Magic_Box_Slot_B)) Equal to Magic_Box_Removed_Item[Magic_Box_Slot_A]
                • Then - Actions
                  • Set Magic_Box_Item_Was_Found[Magic_Box_Slot_A] = True
                • Else - Actions
          • -------- --------
          • Custom script: endif
      • -------- --------
      • Set Magic_Box_Count = 0
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Magic_Box_Item_Was_Found[Magic_Box_Slot_A] Equal to True
            • Then - Actions
              • Set Magic_Box_Count = (Magic_Box_Count + 1)
            • Else - Actions
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Count Greater than or equal to Magic_Box_Needed
        • Then - Actions
          • -------- This tells the system that it was a success and that we can move on: --------
          • Set Magic_Box_Outcome = 1
        • Else - Actions

All of these changes has the benefit of making your Item triggers much simpler. For example, the Potion of Restoration trigger now only needs to run the Scan Inventory trigger rather than handle the "does it have item X" logic itself:
  • Transmute Potion of Restoration
    • Events
    • Conditions
      • Magic_Box_Outcome Not equal to 1
    • Actions
      • -------- Define what item-types will be created and removed to make this combination: --------
      • Set Magic_Box_Created_Item[1] = Potion of Restoration
      • Set Magic_Box_Removed_Item[1] = Potion of Mana
      • Set Magic_Box_Removed_Item[2] = Potion of Healing
      • -------- --------
      • -------- Check if the magic box has these items: --------
      • Trigger - Run Transmute Box Scan Inventory <gen> (ignoring conditions)

All of these changes should allow for any number of of Created/Removed item combinations.

Also:
- I renamed Transmute Box Check Items to Transmute Box Combine but besides that it remains unchanged.
- Transmute Box Failure remains unchanged.
1736450818731.png
1736452635754.png
 

Attachments

  • Magic Box Transmute 2.w3m
    22.4 KB · Views: 3
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
You mean this lets the user combine multiple items at once? Because I'd specifically want it to make 1 item/use.
No, it's only going to transmute the first valid combination it finds then stop there:
  • Transmute Box Combine
    • Events
    • Conditions
    • Actions
      • -------- Try to transmute the items in the magic box: --------
      • Trigger - Run Transmute Potion of Restoration <gen> (checking conditions)
      • Trigger - Run Transmute Belt of Giant Strength <gen> (checking conditions)
Note the (checking conditions) part, this is important.

If the items needed to create Potion of Restoration are found then the system won't get past the Conditions block in the Belt of Giant Strength trigger - or any trigger after it. That's because they all use this Condition which will be Set to 1 once a valid combination is found:
  • Conditions
    • Magic_Box_Outcome Not equal to 1
This also means that you can order these triggers to determine what has priority, if need be. It's first come, first serve.
 
Last edited:
Level 12
Joined
Jul 5, 2014
Messages
551
The single item thing is a minor issue that can be solved pretty easily.

Edit 2: Alright, I think this update solves all of the potential issues you listed:

In Transmute Box Begins we have 3 changes. I introduced a new Integer variable called Magic_Box_Inventory_Size, then I check if the box has more than 0 items instead of more than 1, and I Run a new trigger called Transmute Box Reset Items:
  • Transmute Box Begins
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
    • Actions
      • Set Magic_Box_Unit = (Triggering unit)
      • Set Magic_Box_Inventory_Size = (Size of inventory for Magic_Box_Unit)
      • -------- --------
      • -------- The Magic_Box_Outcome variable represents the different possible outcomes: --------
      • -------- 1 = Successful item transmutation (combined 2 or more items). --------
      • -------- 2 = No items found. --------
      • -------- 3 = No item combinations found (not enough or invalid types). --------
      • -------- --------
      • -------- Default it to 3, it will be modified throughout the rest of these triggers: --------
      • Set Magic_Box_Outcome = 3
      • -------- --------
      • -------- Reset data: --------
      • Trigger - Run Transmute Box Reset Items <gen> (ignoring conditions)
      • -------- --------
      • -------- Try to combine items: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of items carried by Magic_Box_Unit) Greater than 0
        • Then - Actions
          • Trigger - Run Transmute Box Combine <gen> (ignoring conditions)
        • Else - Actions
          • -------- It has no items: --------
          • Set VariableSet Magic_Box_Outcome = 2
      • -------- --------
      • -------- Determine the final outcome based on the previous actions: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Outcome Equal to 1
        • Then - Actions
          • -------- [SUCCESS] --------
          • Trigger - Run Transmute Box Success <gen> (ignoring conditions)
        • Else - Actions
          • -------- [FAILURE] --------
          • Trigger - Run Transmute Box Failure <gen> (ignoring conditions)

Transmute Box Success now uses For Loops to Remove and Create items. Note how Magic_Box_Created_Item is now an Array - it acts similar to Removed_Items[] and allows for multiple rewards:
  • Transmute Box Success
    • Events
    • Conditions
    • Actions
      • -------- Items were successfully transmuted. --------
      • -------- --------
      • Set VariableSet Magic_Box_Point = (Position of Magic_Box_Unit)
      • Special Effect - Create a special effect at Magic_Box_Point using Abilities\Spells\Other\Charm\CharmTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation( udg_Magic_Box_Point )
      • -------- --------
      • -------- Remove matching items: --------
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Item - Remove (Item carried by Magic_Box_Unit of type Magic_Box_Removed_Item[Magic_Box_Slot_A])
      • -------- --------
      • -------- Create new items: --------
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Hero - Create Magic_Box_Created_Item[Magic_Box_Slot_A] and give it to Magic_Box_Unit

Here's the new Transmute Box Reset Items trigger which we use to avoid carrying unwanted data over to different transmutations:
  • Transmute Box Reset Items
    • Events
    • Conditions
    • Actions
      • -------- Reset all data to prevent unwanted creation and removal of items: --------
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Custom script: set udg_Magic_Box_Created_Item[udg_Magic_Box_Slot_A] = 0
          • Custom script: set udg_Magic_Box_Removed_Item[udg_Magic_Box_Slot_A] = 0

Here's the new Transmute Box Scan Inventory trigger which could likely be improved to be honest. It's job is to test each Inventory Slot to see if it has a required item, and tally how many it finds without counting the same one twice. Hopefully my logic is sound - I didn't test this:
  • Transmute Box Scan Inventory
    • Events
    • Conditions
    • Actions
      • Set Magic_Box_Needed = 0
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • Custom script: if udg_Magic_Box_Removed_Item[udg_Magic_Box_Slot_A] != 0 then
          • -------- --------
          • Set Magic_Box_Needed = (Magic_Box_Needed + 1)
          • Set Magic_Box_Item_Was_Found[Magic_Box_Slot_A] = False
          • For each (Integer Magic_Box_Slot_B) from 1 to Magic_Box_Inventory_Size, do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Item-type of (Item carried by Magic_Box_Unit in slot Magic_Box_Slot_B)) Equal to Magic_Box_Removed_Item[Magic_Box_Slot_A]
                • Then - Actions
                  • Set Magic_Box_Item_Was_Found[Magic_Box_Slot_A] = True
                • Else - Actions
          • -------- --------
          • Custom script: endif
      • -------- --------
      • Set Magic_Box_Count = 0
      • For each (Integer Magic_Box_Slot_A) from 1 to Magic_Box_Inventory_Size, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Magic_Box_Item_Was_Found[Magic_Box_Slot_A] Equal to True
            • Then - Actions
              • Set Magic_Box_Count = (Magic_Box_Count + 1)
            • Else - Actions
      • -------- --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Magic_Box_Count Greater than or equal to Magic_Box_Needed
        • Then - Actions
          • -------- This tells the system that it was a success and that we can move on: --------
          • Set Magic_Box_Outcome = 1
        • Else - Actions

All of these changes has the benefit of making your Item triggers much simpler. For example, the Potion of Restoration trigger now only needs to run the Scan Inventory trigger rather than handle the "does it have item X" logic itself:
  • Transmute Potion of Restoration
    • Events
    • Conditions
      • Magic_Box_Outcome Not equal to 1
    • Actions
      • -------- Define what item-types will be created and removed to make this combination: --------
      • Set Magic_Box_Created_Item[1] = Potion of Restoration
      • Set Magic_Box_Removed_Item[1] = Potion of Mana
      • Set Magic_Box_Removed_Item[2] = Potion of Healing
      • -------- --------
      • -------- Check if the magic box has these items: --------
      • Trigger - Run Transmute Box Scan Inventory <gen> (ignoring conditions)

All of these changes should allow for any number of of Created/Removed item combinations.

Also:
- I renamed Transmute Box Check Items to Transmute Box Combine but besides that it remains unchanged.
- Transmute Box Failure remains unchanged.
View attachment 507757View attachment 507763
I'm trying to wrap my head around this system but it's extremely complex. I see there's a player group variable which I'm guessing is for multiple players which isn't really an issue with my campaign since there's only one non-computer player. I'm getting lost with trying to understand the meaning for Slot_A and Slot_B. And while I'm guessing this is probably a tidier version of my original recipe, I just getting lost in all these variables, not to mention the 30+ working recipes that need to redo again from the beginning. I appreciate the effort but this massive change just so I can give the player an error sound/message don't seem to worth it.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
I appreciate the effort but this massive change just so I can give the player an error sound/message don't seem to worth it.
That's fine, the logic to cancel the ability and throw an error can be found in the Begins / Failure triggers. You can focus on those two triggers to figure it out but it's simple:

Box begins casting the ability -> IF it's inventory has zero items THEN throw an error and cancel the ability.

Then you can change your 30+ item triggers to use the "Starts an effect" Event to prevent them from running if the ability is cancelled.

I'm trying to wrap my head around this system but it's extremely complex. I see there's a player group variable which I'm guessing is for multiple players which isn't really an issue with my campaign since there's only one non-computer player. I'm getting lost with trying to understand the meaning for Slot_A and Slot_B. And while I'm guessing this is probably a tidier version of my original recipe, I just getting lost in all these variables, not to mention the 30+ working recipes that need to redo again from the beginning.
- Slot_A and Slot_B are so we can use two For Loops together without them interfering with one another. We loop over the unit's entire inventory (Slots A), then we Loop over the Removed items (Slots B) and compare them. In other words, we compare all Removed items to the item in Slot 1, then we repeat this process in Slot 2, and so on. Perhaps read up on For Loops to get a better understanding, they're an extremely useful tool to master (and quite simple).

- The Player Group variable is to avoid a memory leak. You can simply use Player Group - Red instead if your map is singleplayer and you play as Red, just don't destroy that group. Or just use (All players) in that case, it's really only important in multiplayer to avoid seeing other people's error messages.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
But that leak only exists in your version, right? I don't see such leak in my version of the trigger.
Your trigger doesn't display a Text Message so there is no potential for a Player Group related memory leak.

This would cause a memory leak because it creates a new Player Group object:
  • Game - Display to (Player group((Owner of Magic_Box_Unit))) for 4.00 seconds the text: Some error message text
This would NOT leak because it uses an existing Player Group object:
  • Game - Display to (All players) for 4.00 seconds the text: Some error message text
  • Game - Display to Player Group - Player 1 (Red) for 4.00 seconds the text: Some error message text
 
Level 12
Joined
Jul 5, 2014
Messages
551
Your trigger doesn't display a Text Message so there is no potential for a Player Group related memory leak.

This would cause a memory leak because it creates a new Player Group object:
  • Game - Display to (Player group((Owner of Magic_Box_Unit))) for 4.00 seconds the text: Some error message text
This would NOT leak because it uses an existing Player Group object:
  • Game - Display to (All players) for 4.00 seconds the text: Some error message text
  • Game - Display to Player Group - Player 1 (Red) for 4.00 seconds the text: Some error message text
I didn't know about that leak. It only applies to message?

Here's a dumbed down version of what you've suggested. It probably stings your eyes but I just put it here to make sure it's a working thing (in game it seemed to work.)

  • Start Transmute
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Transmute Items
    • Actions
      • Set Combine = False
      • Trigger - Run Potion of Restoration <gen> (checking conditions) +a bunch of recipes once it gets the green light

  • Potion of Restoration
    • Events
    • Conditions
      • Combine Equal to False
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (((Casting unit) has an item of type Potion of Healing) Equal to True) and (((Casting unit) has an item of type Potion of Mana) Equal to True)
          • (Number of items carried by (Casting unit)) Equal to 2
        • Then - Actions
          • Set Combine = True
          • Set Box = (Position of (Casting unit))
          • Item - Remove (Item carried by (Casting unit) of type Potion of Mana)
          • Item - Remove (Item carried by (Casting unit) of type Potion of Healing)
          • Special Effect - Create a special effect at Box using Abilities\Spells\Other\Charm\CharmTarget.mdl
          • Special Effect - Destroy (Last created special effect)
          • Wait 0.50 seconds
          • Hero - Create Potion of Restoration and give it to (Casting unit)
          • Custom script: call RemoveLocation(udg_Box)
        • Else - Actions
          • Trigger - Run Combine Items Fail <gen> (checking conditions)

  • Combine Items Fail
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Combine Equal to False
        • Then - Actions
          • Sound - Play Error <gen>
        • Else - Actions
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
Here's a dumbed down version of what you've suggested.
Here's a simplified version of your triggers with a few fixes:
  • Start Transmute
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Transmute Items
    • Actions
      • Set Combine = False
      • Trigger - Run Potion of Restoration <gen> (checking conditions) +a bunch of recipes once it gets the green light
      • -------- check Combine last --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Combine Equal to False
        • Then - Actions
          • Sound - Play Error <gen>
        • Else - Actions
  • Potion of Restoration
    • Events
    • Conditions
      • Combine Equal to False
      • (((Triggering unit) has an item of type Potion of Healing) Equal to True) and (((Triggering unit) has an item of type Potion of Mana) Equal to True)
      • (Number of items carried by (Triggering unit)) Equal to 2
    • Actions
      • Set Combine = True
      • Item - Remove (Item carried by (Triggering unit) of type Potion of Mana)
      • Item - Remove (Item carried by (Triggering unit) of type Potion of Healing)
      • Set Box = (Position of (Triggering unit))
      • Special Effect - Create a special effect at Box using Abilities\Spells\Other\Charm\CharmTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation(udg_Box)
      • Wait 0.50 seconds of game-time
      • Hero - Create Potion of Restoration and give it to (Triggering unit)
You cannot reference (Casting unit) after using a Wait, there is no guarantee that it will still reference the same caster. Waits are generally bad practice because of this, here's a list of the Event Responses that are safe and unsafe:
Always use (Triggering unit) when you can (you almost always can).

But I'm not sure why you have the Wait in the first place, that just complicates things and doesn't seem necessary. If you NEED the Wait then your ability will need a Cooldown of ~1 second to avoid multiple casts running at the same time.
 
Level 12
Joined
Jul 5, 2014
Messages
551
Here's a simplified version of your triggers with a few fixes:
  • Start Transmute
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
      • (Ability being cast) Equal to Transmute Items
    • Actions
      • Set Combine = False
      • Trigger - Run Potion of Restoration <gen> (checking conditions) +a bunch of recipes once it gets the green light
      • -------- check Combine last --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Combine Equal to False
        • Then - Actions
          • Sound - Play Error <gen>
        • Else - Actions
  • Potion of Restoration
    • Events
    • Conditions
      • Combine Equal to False
      • (((Triggering unit) has an item of type Potion of Healing) Equal to True) and (((Triggering unit) has an item of type Potion of Mana) Equal to True)
      • (Number of items carried by (Triggering unit)) Equal to 2
    • Actions
      • Set Combine = True
      • Item - Remove (Item carried by (Triggering unit) of type Potion of Mana)
      • Item - Remove (Item carried by (Triggering unit) of type Potion of Healing)
      • Set Box = (Position of (Triggering unit))
      • Special Effect - Create a special effect at Box using Abilities\Spells\Other\Charm\CharmTarget.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation(udg_Box)
      • Wait 0.50 seconds of game-time
      • Hero - Create Potion of Restoration and give it to (Triggering unit)
You cannot reference (Casting unit) after using a Wait, there is no guarantee that it will still reference the same caster. Waits are generally bad practice because of this, here's a list of the Event Responses that are safe and unsafe:
Always use (Triggering unit) when you can (you almost always can).

But I'm not sure why you have the Wait in the first place, that just complicates things and doesn't seem necessary. If you NEED the Wait then your ability will need a Cooldown of ~1 second to avoid multiple casts running at the same time.
1. What's the idea with the changed orders? Since the box is stationary, I'm not sure how it improves to lock the position and destroying the position around the special effect? Or it's just a generic thing?

2. Only the box has the transmute ability and the player won't have access to 2 of them in the same time. I also think it's unlikely that a player can take out an item, put a new one inside and press the button within 0.5 seconds. Of course, a cooldown is no big deal to add.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,868
1. What's the idea with the changed orders? Since the box is stationary, I'm not sure how it improves to lock the position and destroying the position around the special effect? Or it's just a generic thing?

2. Only the box has the transmute ability and the player won't have access to 2 of them in the same time. I also think it's unlikely that a player can take out an item, put a new one inside and press the button within 0.5 seconds. Of course, a cooldown is no big deal to add.
I ordered things in a way that helped avoid some of the issues that the Wait would've caused.

There's no reason to delay the removal of the Point after the Wait since it's no longer needed after creating the Special Effect.

You want to deal with things immediately as to avoid the pitfalls of timing related issues, especially in regards to memory leaks.

Anyway, if the Ability has a long enough Cooldown and you're certain that the Wait has finished before it can run again then the changes to the order aren't essential. I still recommend putting the Combine check in the first trigger, that should make your life easier and more importantly it avoids multiple Errors running at once.
 
Last edited:
Level 12
Joined
Jul 5, 2014
Messages
551
I ordered things in a way that helped avoid some of the issues that the Wait would've caused.

There's no reason to delay the removal of the Point after the Wait since it's no longer needed immediately after creating the Special Effect.

You want to deal with things immediately as to avoid the pitfalls of timing issues, especially in regards to memory leaks.

Anyway, if the Ability has a long enough Cooldown and you're certain that the Wait has finished before it can run again then the changes to the order aren't essential. I still recommend putting the Combine check in the first trigger, that should make your life easier and more importantly it avoids multiple Errors running at once.
I see. That's fair. And yeah, I didn't account for all the recipes running the error trigger in the same time. It seems like the latest settings got the triggers working as I originally intended. Thanks for the help.
 
Top