• 🏆 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] Unit in Group is being picked all the time

Status
Not open for further replies.

sentrywiz

S

sentrywiz

I have a problem that I can't see the solution.

The issue is, when a unit is damaged by the trigger, it is being added to unit group. Then at the end of the lifespan of the projectile, that unit group is being cleared from all units in it. The point is that the trigger should damage one unit only ONCE per projectile and add it to a group so it doesn't damage it again. But the trigger repeatedly adds the same unit to the unit group and damaging it again, thus resulting in insta kill once you get hit the projectile:

I've marked where the trigger is (in the 2nd one) with the HERE >>>>>>>>

  • fb start
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fast Blade
    • Actions
      • Set fb_loc1 = (Position of (Triggering unit))
      • Set fb_loc2 = (Target point of ability being cast)
      • Set fb_loc3 = (fb_loc1 offset by 60.00 towards (Angle from fb_loc1 to fb_loc2) degrees)
      • Set fb_next_unit[(Player number of (Owner of (Triggering unit)))] = 50.00
      • Set fb_max_units[(Player number of (Owner of (Triggering unit)))] = 15
      • Set fb_unit[(Player number of (Owner of (Triggering unit)))] = 0
      • Set fb_total = (fb_total + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Triggering unit) has buff Cyclone -) Equal to True
        • Then - Actions
          • Set fb_faster[(Player number of (Owner of (Triggering unit)))] = True
          • Set fb_duration[(Player number of (Owner of (Triggering unit)))] = 0.50
        • Else - Actions
          • Set fb_faster[(Player number of (Owner of (Triggering unit)))] = False
          • Set fb_duration[(Player number of (Owner of (Triggering unit)))] = 0.80
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Triggering unit) has buff Accuracy) Equal to True
        • Then - Actions
          • Set fb_wider[(Player number of (Owner of (Triggering unit)))] = True
          • Set fb_dmg[(Player number of (Owner of (Triggering unit)))] = 75
          • Set fb_max_dmg[(Player number of (Owner of (Triggering unit)))] = 245
        • Else - Actions
          • Set fb_wider[(Player number of (Owner of (Triggering unit)))] = False
          • Set fb_dmg[(Player number of (Owner of (Triggering unit)))] = 50
          • Set fb_max_dmg[(Player number of (Owner of (Triggering unit)))] = 170
      • Unit - Create 1 Frog for (Owner of (Triggering unit)) at fb_loc3 facing (Angle from fb_loc1 to fb_loc2) degrees
      • Unit - Add a fb_duration[(Player number of (Owner of (Triggering unit)))] second Generic expiration timer to (Last created unit)
      • Unit Group - Add (Last created unit) to fb_group
      • Trigger - Turn on fb loop <gen>
      • Custom script: call RemoveLocation ( udg_fb_loc1 )
      • Custom script: call RemoveLocation ( udg_fb_loc2 )
      • Custom script: call RemoveLocation ( udg_fb_loc3 )
  • fb loop
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • fb_total Greater than 0
          • (Number of units in fb_group) Greater than 0
        • Then - Actions
          • Unit Group - Pick every unit in fb_group and do (Actions)
            • Loop - Actions
              • Set fb_player_int = (Player number of (Owner of (Picked unit)))
              • Set fb_real_unit[fb_player_int] = (Picked unit)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • fb_unit[fb_player_int] Less than fb_max_units[fb_player_int]
                • Then - Actions
                  • Set fb_unit[fb_player_int] = (fb_unit[fb_player_int] + 1)
                  • Set fb_dmg[fb_player_int] = (fb_dmg[fb_player_int] + 15)
                  • Set fb_loc1 = (Position of (Picked unit))
                  • Set fb_pos1[fb_player_int] = (Position of (Picked unit))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • fb_faster[(Player number of (Owner of (Picked unit)))] Equal to True
                    • Then - Actions
                      • Set fb_pos2[fb_player_int] = (fb_pos1[fb_player_int] offset by 60.00 towards (Facing of (Picked unit)) degrees)
                    • Else - Actions
                      • Set fb_pos2[fb_player_int] = (fb_pos1[fb_player_int] offset by 40.00 towards (Facing of (Picked unit)) degrees)
                  • Unit - Move (Picked unit) instantly to fb_pos2[fb_player_int]
                  • Set fb_pos3[fb_player_int] = (Position of (Picked unit))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • fb_wider[fb_player_int] Equal to True
                    • Then - Actions
                      • Set fb_hit_groupp[fb_player_int] = (Units within 150.00 of fb_pos3[fb_player_int] matching ((((Matching unit) belongs to an enemy of (Owner of (Picked unit))) Equal to True) and (((Matching unit) is alive) Equal to True)))
                      • Animation - Change (Picked unit)'s size to (250.00%, 250.00%, 250.00%) of its original size
                    • Else - Actions
                      • Set fb_hit_groupp[fb_player_int] = (Units within 100.00 of fb_pos3[fb_player_int] matching ((((Matching unit) belongs to an enemy of (Owner of (Picked unit))) Equal to True) and (((Matching unit) is alive) Equal to True)))
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Number of units in fb_hit_groupp[fb_player_int]) Greater than 0
                    • Then - Actions
                      • HERE ->>>>>>> Unit Group - Pick every unit in fb_hit_groupp[fb_player_int] and do (Actions)
                        • Loop - Actions
                          • Set fb_hit_unit = (Picked unit)
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • (fb_hit_unit is in fb_unit_already_hit[fb_player_int]) Equal to True
                            • Then - Actions
                              • Game - Display to (All players) for 2.00 seconds the text: ((Name of fb_hit_unit) + is in group)
                            • Else - Actions
                              • Game - Display to (All players) for 2.00 seconds the text: ((Name of fb_hit_unit) + isn't in group)
                              • If (fb_dmg[fb_player_int] Greater than fb_max_dmg[fb_player_int]) then do (Set fb_dmg[fb_player_int] = fb_max_dmg[fb_player_int]) else do (Do nothing)
                              • Unit - Cause fb_real_unit[fb_player_int] to damage fb_hit_unit, dealing (Real(fb_dmg[fb_player_int])) damage of attack type Spells and damage type Universal
                              • Unit Group - Add fb_hit_unit to fb_unit_already_hit[fb_player_int]
                              • Floating Text - Create floating text that reads (String(fb_dmg[fb_player_int])) above fb_hit_unit with Z offset 0.00, using font size 10.00, color (100.00%, 0.00%, 0.00%), and 0.00% transparency
                              • Floating Text - Set the velocity of (Last created floating text) to 64.00 towards 90.00 degrees
                              • Floating Text - Change (Last created floating text): Disable permanence
                              • Floating Text - Change the lifespan of (Last created floating text) to 1.00 seconds
                    • Else - Actions
                  • Custom script: call DestroyGroup ( udg_fb_hit_groupp [ udg_fb_player_int ] )
                  • Custom script: call RemoveLocation ( udg_fb_pos1 [ udg_fb_player_int ] )
                  • Custom script: call RemoveLocation ( udg_fb_pos2 [ udg_fb_player_int ] )
                  • Custom script: call RemoveLocation ( udg_fb_pos3 [ udg_fb_player_int ] )
                • Else - Actions
                  • Set fb_total = (fb_total - 1)
                  • Set fb_faster[fb_player_int] = False
                  • Unit Group - Remove (Picked unit) from fb_group
                  • Unit Group - Remove all units from fb_unit_already_hit[fb_player_int]
        • Else - Actions
          • Trigger - Turn off (This trigger)
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
Use a non array group for the hit group that picks units withing 100-150 radius. Destroy it after use in the loop.

Use an group array variable for the spell instance, create it when the spell is cast and destroy it when the spell ends.

Add units from the non array variable to the array group.

if udg_group == null then
set udg_group[index] = CreateGroup()
endif
 

sentrywiz

S

sentrywiz

Remove "Custom script: call DestroyGroup ( udg_fb_hit_groupp [ udg_fb_player_int ] )"

Should work fine then.

I don't understand. How does that make it work in the way it's working?
I'm not criticizing. If you can to explain it to me so I can see.

Use a non array group for the hit group that picks units withing 100-150 radius. Destroy it after use in the loop.

Use an group array variable for the spell instance, create it when the spell is cast and destroy it when the spell ends.

Add units from the non array variable to the array group.

if udg_group == null then
set udg_group[index] = CreateGroup()
endif

I thought that by making an array group I'd avoid collision between multiple units using the same group to store units. I don't get why its working the way it is with a more MPI solution?
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Sorry for my post but I stopped reading when I saw that destroygroup...


I do appreciate that you want to make such a system all by yourself but I am sorry to tell you that there are a lot of things that should not be used the way you do it.
Like: Groups (must be arrays), Player numbers (not MUI), move unit (use SetX, SetY), 0.05 seconds (should be 0.03), continously calling functions as a reference to a unit (should be a variable), using reversive if/else functions... sorry but I forgot the name :) I thought it was a reversive if/else but google sais not... he also doesn't what it is called. Anyway it just makes the code less readable.
Those are all (most) just optimizations and better feeling but it should be that way.

You can find good working missile/projectile systems on the web which can do what you want.

However, if you really want to make it yourself I will give you a (better) start:

1. Use arrays instead of groups. Groups are very limited and are hard to work with.
You should have an integer which tells you how many missiles are active in the game.
This integer increases when one is made and decreases when one is destroyed.
When you loop through your missiles, use "For integer TempInteger from 1 to "global_variable_missile_count" and do actions".
Then you can access each missiles own data with the TempInteger number.
(Using a variable instead of "Integer A" or "Integer B" is faster and therefor should be used.)

2. Loop every 0.03 seconds of gametime.
Using a higher amount would look laggy. (Even 0.04 could be noticeable by some people... I was told that Maker is one of them.)
Indeed you cannot make good calculations by "/33" but you can do "x0.03" which makes more sense too.
You can use a speed of 900*0.03 and use that one to apply speed rather than setting a raw speed like 27.

3. You have to think about what a missile would always (mostly) have as values.
Every projectile needs
  • a target (either location or object),
  • a speed (could also be a global speed),
  • an effect (is not required but well... you want to do something)
  • an object group with all the hit units. (where your problem is)
(Also stuff that you would like is stuff like on-hit-art, source, arc, abilityid, damage, etc.)
As you use arrays, you can create one variable array for each and every type of object that you need:
(all of these are arrays)
Target_Type : (could be integer where 1 is a unit and 2 is a location, 0 is the default and could be reserved or be an error)
Target_Unit : unit
Target_Location : point
Speed : real
Effect : (Any way you want to make them.)
Unit_Group : unit-group (Which are the units that have been hit.)

Then you can access those data by this: "Missile_System_Unit_Group[TempInteger]"
That makes it MUI as every single missile has its own unit group etc.

4. On-Hit:
You have to know when your missile has hit someone.
So you create a new unit group (for every missile every 0.03 seconds), which picks every unit in "range" (This could be a variable that changes for each missile or be a raw value.)
Then you filter units out by:
TempUnit is not in Missile_System_Unit_Group[TempInteger] equal to true.
TempUnit is alive equal to true
TempUnit is a structure equal to false (if you want that)
TempUnit is an enemy/an ally of player TempPlayer
etc, etc, etc.
Then you do the effects.

5. Remove a missile:
Every missile must also be removed.
When a missile is destroyed (either on hit or max duration/distance or maybe even dispell), it must be removed from the list.
First things first: Destroy the missile and all its effects.
Then you have to decrease the array length.
So you have 5 missiles:
1, 2, 3, 4, 5 - Amount = 5
Then missile 2 will be destroyed.
So now you have:
1, -, 3, 4, 5 - Amount = 5
You have to replace - with 5:
1, 5, 3, 4 - Amount = 5
To set missile 5 to the empty spot you do this:
Set Missile[TempInteger] = Missile[Missile_Amount]
Set Unit_Group[TempInteger] = Unit_Group[Missile_Amount]
Set Speed[TempInteger] = Speed[Missile_Amount]
etc etc etc
After that you also have to set TempInteger to one less to make it run the other missile too.
You also have to set Missile_Amount to one less so it will now run:
1, 5, 3, 4 - Amount = 4

If I missed something then tell me... I am also making one atm which is very in-depth (even replacing basic attacks) so I could use some more info myself too :D

EDIT:
When you use a reference multiple times (Picked Unit, Owner of (Unit), etc) you should make a variable of it and use that one instead.
1. It is faster.
2. You can modify the code easier.
3. It is more readable.
 

sentrywiz

S

sentrywiz

Your porblem propably is that the groups are not created. This one:
fb_unit_already_hit[fb_player_int].

You need to create them with the method I posted.

I wanted to create them at init. But I couldn't see a way.
In gui groups either exist or not. You don't create them.
That's why I got confused.

But I will try maker's solution

EDIT:

Tsunami will flood the world of warcraft EDITOR if not for maker's wisdom.

You were right. That was the trick.
I didn't do it like you said because idk jass and know little of custom scripts
but I created all array groups on init, filled them with dummy stats like "Units in Playable Map Area"
and when I created each unit for each player I emptied all array groups.
Works like a charm now.

Both maker and Wiet, can't give you rep. Have to spread it around :p
 
Last edited by a moderator:
Status
Not open for further replies.
Top