🏆 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!
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
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'.
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())
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
-------- 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).
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())
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 Fish
Slimy Salmon
Sage Fish
Nothing
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
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.
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.)
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.