• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Trigger] Fishing Trigger GUI

Status
Not open for further replies.
Level 4
Joined
Aug 16, 2013
Messages
75
This is a pretty simple trigger but I always have trouble with pauses and waits for abilities.

This ability will be used by multiple players, but it bugs up and I don't understand how to fix it.

You use the ability from the item and you target a wisp. Once you do that, your unit (the caster) is paused for 5 seconds. After the 5 seconds, your unit is unpaused and there is a chance that your unit will get an item. The wisp in the lake should also die whether or not you get the item.

  • Fishing Rod
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fishing Rod
    • Actions
      • Set Fishing_Drop = (Random integer number between 1 and 100)
      • Set Unit_Got_Fish = (Triggering unit)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of (Target unit of ability being cast)) Equal to Fish Test
          • Fishing_Drop Less than or equal to 30
        • Then - Actions
          • Special Effect - Create a special effect at (Position of (Target unit of ability being cast)) using Abilities\Spells\Human\AerialShackles\AerialShacklesTarget.mdl
          • Unit - Pause Unit_Got_Fish
          • Wait 5.00 seconds
          • Hero - Create Strawberry Seed and give it to Unit_Got_Fish
          • Unit - Kill (Target unit of ability being cast)
          • Unit - Unpause Unit_Got_Fish
        • Else - Actions
          • Special Effect - Create a special effect at (Position of (Target unit of ability being cast)) using Abilities\Spells\Human\AerialShackles\AerialShacklesTarget.mdl
          • Unit - Pause Unit_Got_Fish
          • Wait 5.00 seconds
          • Unit - Kill (Target unit of ability being cast)
          • Unit - Unpause Unit_Got_Fish
 
Last edited:
Level 12
Joined
Oct 16, 2010
Messages
680
but it bugs up and I don't understand how to fix it.

what do u mean by it bugs up? Give details.

also this is certainly not MUI so I assume if multiple unit is fishing at the same time, then it bugs. ofc.

first unit uses ability stored in Unit_Got_Fish, if a second unit starts to fish then it overrides the previous and it won't be unpaused ever:/

use hashtable or arrays or whaterver I suggest looking up some MUI tutorials to get the idea
 
Level 19
Joined
Jul 14, 2011
Messages
875
Place this local unit udg_Unit_Got_Fish = GetTriggerUnit() at the top of the trigger via custom text and remove the 'Set Unit_Got_Fish = (Triggering unit)' action.

Also, target unit of ability being cast isnt local, I think so you can do, e.g local unit udg_Target = GetSpellAbilityTarget() and use it instead of the event response. Just make sure you make a variable called (in this case) 'Target'.
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
Yeah, it ain't MUI.

Pausing Units is usually not desired action, because it not only pauses the unit itself (aka prevents it from moving, attacking, etc.) but it also pauses the duration of all buffs on said unit. That may not be desired.
You leak special effect, since you don't destroy it; and you leak location where you create the special effect (again because you don't destroy it).

Now you should learn to optimize your code.
If you look at what you have in the If/Then/Else block (ITE), everything is same except for one small detail - in the "Then" block you also create an item which you give to fisher.
So the whole trigger should be outside the ITE action with the last action being calculating the chance to fish something up and then the ITE block where you determine whether fisher gets the item or not.


The whole spell can be done far easier. When summarized, all the "fishing spell" does is that it:
1) "forces" the unit to fish for 5 seconds (atm done via the pause action)
2) checks if the target is fish pool
3) creates a special effect (net)
4) calculates chance
5) determines if it gives a fish to fisher or not when unpausing fisher.

For the point #1, we have an ability exactly for this! This ability is called "Channel" and the cool thing about it is that it is an ability made for triggered effects! There are two very cool things about this ability that we could make use of:
1) "Data - Follow Through Time" means how long we are casting or "channeling" the ability (imagine Priestess of the Moon's Starfall ability - she casts it for 30 seconds). If we set this to 5.00, we have a 5 second channeled spell.
2) "Data - Disable Other Abilities" - this works exactly the same as pause unit (it removes all commands like other abilities, move, attack, etc. from the unit as long as it casts the spell). The great thing about this is that it does not pause buffs like the "Pause unit" action does.

So with this ability alone, when we correctly set it up we can pause the caster for 5 seconds.
The problem for making this MUI is that we need to save the fish pool which our fisher targets.
We can now divide the whole spell into two triggers:
1) First trigger fires when fisher Starts the effect of an ability - in this trigger all we do is that we somehow save the fish pool he targets
2) Second trigger fires when fishers Finishes casting an ability - in this case, the 5 second timer is up (he couldn't stop it earlier due to how we set up the channel ability) and all we need to do here is to somehow get the fish pool he targeted 5 seconds ago, set the chance for drop and determine if he gets fish or not.

Now how do we somehow save and load the fish pool? I would actually do it via Hashtables, since all it requires is the hashtable itself and a temporal integer variable for getting HandleID (and we need the integer variable anyway for getting random integer number for the chance).
We can do it also by indexing arrays, but this would require 2 unit arrays (one in which we save all fishers, and in the second we save the fish pool targeted by each fisher), 1 special effect array + we need an integer variable that sets the highest index number used in those arrays + again a temporal variable for getting chance for drop - as you can see, we need far more variables for this option and the code will be more complex (especially since you need to deindex stuff as well), hence I will use hashtables.


So all I need are two variables:
1) I named it "Hash" and it is a variable of type "Hashtable"
2) A variable I call "int" and it is of type "Integer". I give it general name, because it has general use (aka it's a temporal variable).

Here are the triggers I used:

First, we need to initialize the hashtable variable, so we need one trigger that fires upon map initialization to create out hashtable. Actions in the trigger below can be add to any other Map Initialization trigger if you have some in your map already.
  • Map Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set Hash = (Last created hashtable)
This is the trigger that saves stuff into hashtable when your fisher casts Fishing ability.
  • Fishing Start
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fishing
    • Actions
      • Custom script: set udg_int = GetHandleId(GetTriggerUnit()) // This gets HandleID of our fisher - handleID is a unique identification number for each object in game
      • Special Effect - Create a special effect attached to the origin of (Target unit of ability being cast) using Abilities\Spells\Human\AerialShackles\AerialShacklesTarget.mdl
      • Hashtable - Save Handle Of(Target unit of ability being cast) as int of (Key FishingPools) in Hash
      • Hashtable - Save Handle Of(Last created special effect) as int of (Key FishPools) in Hash
This trigger loads stuff from hashtable, removes net and "fishing pool" and determines the chance for dropping fish.
  • Fishing End
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to Fishing
    • Actions
      • Custom script: set udg_int = GetHandleId(GetTriggerUnit())
      • -------- ----------- ----------- ----------- --------
      • -------- Removing the "fish pool" and the "net" --------
      • Unit - Kill (Load int of (Key FishingPools) in Hash)
      • Special Effect - Destroy (Load int of (Key FishPools) in Hash)
      • -------- ----------- ----------- ----------- --------
      • Set int = (Random integer number between 1 and 100)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • int Less than or equal to 30
        • Then - Actions
          • Hero - Create Fish and give it to (Triggering unit)
        • Else - Actions
Now there is only one thing missing that I left out on purpose.
In your trigger, you have one important mistake. Your condition in the ITE is set up badly.
You check if "Chance is less than or equal to 30" and if "Target is fish test".
The thing is - if you target something completely unrelated to fish pool, then you will "throw" net at it, pause the fisher for 5 seconds and then you kill the target!
So let's say I accidentally missclick the target and instead of fish pool I target an honored city guard - I will "fish" him and kill him after 5 seconds. You will never get fish out of him of course, since the code will always execute the "Else" block in the ITE.

I also didn't find very appealing that you have to wait 5 seconds after targeting something incorrect.
Because of those reasons, I made a final fourth trigger which checks the target before Fishing spell is executed.
  • Fishing Check
    • Events
      • Unit - A unit Is issued an order targeting an object
    • Conditions
      • (Issued order) Equal to (Order(charm)) //NOTE: This order here is the same I used in my "Channel"/Fishing ability in the "Data - Base Order ID" field
      • (Level of Fishing for (Triggering unit)) Greater than 0
      • (Unit-type of (Target unit of issued order)) Not equal to Wisp
    • Actions
      • Unit - Pause (Triggering unit)
      • Unit - Order (Triggering unit) to Stop
      • Unit - Unpause (Triggering unit)
      • -------- ----------- ----------- ----------- --------
      • -------- The action below is just for your tests --------
      • -------- You should use a proper error message system instead of this --------
      • Game - Display to (All players) the text: Must target fish po...

I have attached the map with the system. The wisp units are considered to be "fishing pools". You can also try using the Fishing spell on other units and you will see nothing happens (only the "error message" appears).

Hope it helps.
 

Attachments

  • FishingSystem.w3x
    19.2 KB · Views: 67
Level 4
Joined
Aug 16, 2013
Messages
75
Edit: I am trying to use ifs to see if the selected unit is a Small Fish Shadow(unit), I am trying to randomly give the fisher a fish which is an item. There are multiple items that are fish. I want to make this so that if the targeted unit is Small Fish Shadow, then there will be a chance to catch 3 different types of fish, but only one fish can be caught by the random chance integer 1-100.

I am also planning on having Medium Fish Shadow and Large Fish Shadow for an upgraded fishing rod item ability.

I tried loading the unit from the hash and making it equal unit type Small Fish Shadow.. which doesn't work. I then tried making the targeted unit of ability equal Small Fish Shadow which also didn't work.

I am not experienced with hash tables and it would be cool if someone could tell me or point out what I need to do.

  • Fishing Start
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fishing
    • Actions
      • Custom script: set udg_int = GetHandleId(GetTriggerUnit())
      • Special Effect - Create a special effect attached to the origin of (Target unit of ability being cast) using Abilities\Spells\Human\AerialShackles\AerialShacklesTarget.mdl
      • Hashtable - Save Handle Of(Target unit of ability being cast) as int of (Key FishingPools) in Hash
      • Hashtable - Save Handle Of(Last created special effect) as int of (Key FishPools) in Hash
  • Fishing End
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to Fishing
    • Actions
      • Custom script: set udg_int = GetHandleId(GetTriggerUnit())
      • -------- ----------- ----------- ----------- --------
      • -------- Removing the "fish pool" and the "net" --------
      • Unit - Kill (Load int of (Key FishingPools) in Hash)
      • Special Effect - Destroy (Load int of (Key FishPools) in Hash)
      • -------- ----------- ----------- ----------- --------
      • Set int = (Random integer number between 1 and 100)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Fish Shadow
          • int Less than or equal to 50
        • Then - Actions
          • Hero - Create Sardine and give it to (Triggering unit)
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Fish Shadow
              • int Less than or equal to 100
            • Then - Actions
              • Hero - Create Masu Trout and give it to (Triggering unit)
            • Else - Actions
 
Last edited:
Level 12
Joined
Oct 16, 2010
Messages
680
logical error. u reset "int" by a random value before this line
  • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Fish Shadow
so it won't load the correct unit or even load nothing

use an other int variable for the random number
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
The fishing system works even if the Fishing ability is put into item.
If I remove the Fishing ability from the hero and instead put the ability into item "Fishing Rod", the function "Unit - level of ability for unit" returns 0 if the hero doesn't have Fishing rod and 1 if he does have it.

There is a problem that I don't know how to really nicely solve - If unit has fishing rod and Charm ability, which one was it ordered to cast? Both have "charm" order.
The only solution I came up with this is that you set the Base orderId of the Fishing ability to an order of ability which does not target objects - e.g. to Starfall, or Rain of Fire, etc., since if you catch an event "unit is issued an order targeting an object" and the order is "rainoffire" then it has to be the fishing ability, because by any other means you cannot target an object with the Rain of Fire (= it is ground-targeting AoE spell).


Apart from what Lender wrote, I'm not sure if it's the best approach to first kill the fish pool and later check what unit-type it was.
If you need that fishpool, don't kill it immediately, but after you're done with it. You can easily get the HandleID by using the custom script again, since TriggeringUnit() is a local, so it won't get overwritten for that instance.
If problems persist even then, try creating a general variable of type "unit" and load the fish pool into the variable first...
  • Set u = (Load int of (Key FishingPools) in Hash)
...and then use the variable to check what type Fish pool is.


The last thing is that you're using way too many conditions and sometimes you incorrectly use ITE.
Instead of this:
  • Set int = (Random integer number between 1 and 100)
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Fish Shadow
        • int Less than or equal to 50
      • Then - Actions
        • Hero - Create Sardine and give it to (Triggering unit)
      • Else - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Fish Shadow
            • int Less than or equal to 100
          • Then - Actions
            • Hero - Create Masu Trout and give it to (Triggering unit)
          • Else - Actions
do it like this:
  • Set int = (Random integer number between 1 and 100)
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Fish Shadow
      • Then - Actions
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • int Less than or equal to 50
          • Then - Actions
            • Hero - Create Sardine and give it to (Triggering unit)
          • Else - Actions
            • Hero - Create Masu Trout and give it to (Triggering unit)
This version is more efficient, because you check if the target is "Small Fish Shadow" only once.
Since you pick random integer number in interval [1, 100], then when you check if the number is less than or equal to 50 (thus in interval [1, 50]) and it ain't, you can deduce that the number has to be in the other interval [51, 100]. It cannot be in any other interval, because you pick numbers between 1 and 100, so the condition to check if number is less than or equal to 100 will always return true, no matter what. Hence you can remove that condition and simply put only actions in the "Else" block.

Your approach would be better if you wanted to calculate chance for various fish that can be fished out of the fishing pool. But once again, you should make the unit-type condition check only once at the beginning.
  • Actions
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Fish Pool
      • Then - Actions
        • Set int = (Random integer number between 1 and 100)
        • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
          • If - Conditions
            • int Less than or equal to 30
          • Then - Actions
            • Hero - Create Long Dead Fish and give it to (Triggering unit)
          • Else - Actions
            • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
              • If - Conditions
                • int Greater than 30
                • int Less than or equal to 55
              • Then - Actions
                • Hero - Create Slimy Salmon and give it to (Triggering unit)
              • Else - Actions
                • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                  • If - Conditions
                    • int Greater than 55
                    • int Less than or equal to 75
                  • Then - Actions
                    • Hero - Create Sage Fish and give it to (Triggering unit)
                  • Else - Actions
                    • //No fish for our fisher :(
      • Else - Actions
In this case the loot table looks like this:
Long Dead FishSlimy SalmonSage FishNothing
30%25%20%25%
So we have a total of 100% chance for one of the following 4 things to happen, with each having different probability.



Independent means that chance for each fish to be fished is calculated independently from one another.
This can be done by either indenting one ITE into another, which means that you can only loot 1 (type of) fish from the pool... e.g.:
  • Set int = (Random integer number between 1 and 100)
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • int Less than or equal to 30
    • Then - Actions
      • //do actions A
    • Else - Actions
      • Set int = (Random integer number between 1 and 100)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • int Less than or equal to 15
        • Then - Actions
          • //do actions B
        • Else - Actions
          • Set int = (Random integer number between 1 and 100)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • int Less than or equal to 80
            • Then - Actions
              • //do actions C
            • Else - Actions
              • ...etc.
... or making them solitary which can cause you to fish out multiple (types of) fish, e.g.:
  • Set int = (Random integer number between 1 and 100)
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • int Less than or equal to 30
    • Then - Actions
      • //do actions A
    • Else - Actions
  • Set int = (Random integer number between 1 and 100)
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • int Less than or equal to 48
    • Then - Actions
      • //do actions B
    • Else - Actions
  • Set int = (Random integer number between 1 and 100)
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • int Less than or equal to 75
    • Then - Actions
      • //do actions C
    • Else - Actions
And last, but not least, if you have various types of fish pool, you basically first check the fishpool type and then use one of the drop tables from above.
  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
    • If - Conditions
      • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Small Pool
    • Then - Actions
      • //drop tables for Small pool
    • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of (Load int of (Key FishingPools) in Hash)) Equal to Greater Sagefish Pool
        • Then - Actions
          • //drop table for Greater Sagefish Pool
        • Else - Actions
          • //another indented ITE for fish pool
This approach is usually the best, because once you find the correct fish pool, the code doesn't check the other ITEs. However if you made those ITEs solitary (non-indented), you would check every fish pool even if your fish pool was found in the first ITE, resulting in decrease of efficiency.


Of course the more you add to it, the more complicated the whole thing becomes, in which case it may be better to mechanize the code and save all data in for example hashtable, instead of manually writing everything
 
Level 4
Joined
Aug 16, 2013
Messages
75
Okay. I believe I got it working (tested it 10 times to be sure).

  • Fishing End
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
      • (Ability being cast) Equal to Fishing
    • Actions
      • Custom script: set udg_int = GetHandleId(GetTriggerUnit())
      • -------- ----------- ----------- ----------- --------
      • -------- Removing the "fish pool" and the "net" --------
      • Unit - Kill (Load int of (Key FishingPools) in Hash)
      • Special Effect - Destroy (Load int of (Key FishPools) in Hash)
      • -------- ----------- ----------- ----------- --------
      • Set u = (Load int of (Key FishingPools) in Hash)
      • Set int = (Random integer number between 1 and 100)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of u) Equal to Small Fish Shadow
          • int Less than or equal to 33
        • Then - Actions
          • Hero - Create Sardine and give it to (Triggering unit)
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of u) Equal to Small Fish Shadow
              • int Greater than or equal to 34
              • int Less than or equal to 66
            • Then - Actions
              • Hero - Create Masu Trout and give it to (Triggering unit)
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Unit-type of u) Equal to Small Fish Shadow
                  • int Greater than or equal to 67
                • Then - Actions
                  • Hero - Create Strawberry Seed and give it to (Triggering unit)
                • Else - Actions
^I am doing it for multiple items, which is the reason why I have multiple ITE.


The last thing for this trigger I am trying to do is add the ability Locust to the targeted fish pool so other fishers can't use their Fishing ability to channel the same fish.

You can't add Locust through GUI from what I have read and tried. Right now, I am trying to add Locust through Custom script and I have no Custom script knowledge whatsoever. It should be really simple and I am messing around with it.

None of these work.

  • Custom script: call UnitAddAbility(TargetUnitOfAbilityBeingCast(), 'Aloc')
  • Custom script: call UnitAddAbility(Getudg_int(), 'Aloc')
  • Custom script: call UnitAddAbility(GetTriggerUnit(), 'Aloc')
^All this does is make the fisher Locust and not the fish pool.

I have tried a bunch of others and am still trying to Locust the fish pool unit.
 
Last edited:
Level 4
Joined
Aug 16, 2013
Messages
75
It seems to work without the morphing.

  • Fishing Start
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fishing
    • Actions
      • Custom script: set udg_int = GetHandleId(GetTriggerUnit())
      • Custom script: call UnitAddAbility(GetSpellTargetUnit(), 'Aloc')
      • Special Effect - Create a special effect attached to the origin of (Target unit of ability being cast) using Abilities\Spells\Human\AerialShackles\AerialShacklesTarget.mdl
      • Hashtable - Save Handle Of(Target unit of ability being cast) as int of (Key FishingPools) in Hash
      • Hashtable - Save Handle Of(Last created special effect) as int of (Key FishPools) in Hash
Thanks for all your help Nichilus. I would +rep you but I already did a while back which makes me unable to do so. I will put you on credits for the fishing system / any other triggers you have helped me with (It might have been the farming system that you also helped me with, I can't recall.)

Thanks a lot. :thumbs_up:
 
Status
Not open for further replies.
Top