• 🏆 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] How to find units grouped together around a unit

Status
Not open for further replies.
Level 6
Joined
Jul 21, 2020
Messages
67
I'm creating an AOS hero AI and so far the one thing that I haven't figured out a good way to do is have the AI find units that are grouped together to cast an AOE spell. I'm currently trying to utilize base spells ID's to get the Built in WC3 AI to make decisions but there are a few spells I've built that don't really follow any of the built in spells. For example, a spell that creates an AOE affect in a selected area for 10 seconds that slows enemy units and speeds up allies. The spell works fine and I have AI that can handle everything else.

What I don't have is a way for an AI to recognize units grouped together to figure out the best point to cast the spell. Anyone have any thoughts? Really curious if someone else has solved this issue. Would be happy to explain more if you have any questions. GUI would be preferred still very noob when it comes to JASS although I can add a JASS line here and there no problem.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
The naive approach (and the least efficient) would be to make a group of ennemies unit within an AREA around the hero, then you use this GROUP.
For a better efficiency it would be better to use unit global arrays once this first group has been made, especially since you will use ForForce in GUI.
With each unit inside this GROUP you check the distance with all other units inside this group, if it's less or equal to your spell AREA affect you register this unit with the reference unit in an other group/unit array.
Then you take the group/unit array which has the most units.

It would be still good enough if you don't have hundred units on the map.

To be clear, let's say your hero is H, you decide to check if there are ennemies units around him at the DISTANCE max (could be something like "spell target distance + X", where X is maybe your spell area effect with an extra margin, or just the whole map, depends what you want to do), then you have filled your group.

You call a Forforce and fill an array of units, let's say there are 10 units.

UnitArray[0] = unit0 ; UnitArray[1] = unit1 ... UnitArray[9] = unit9.

Then you compare the distance between unit0 with unit1, unit2, ... unit9 and you fill an other array of units if the distance is less or equal than SPELL AREA EFFECT.
You do the same with unit1 and unit0,unit2,unit3,...unit9
Then with unit unit2 and unit0,unit1,unit3,...,unit9

When you have done comparing the distance between each units you take the unit array which has the most number of units.

You do all that with loops.

EDIT : in fact you need to check the distance between each units inside the GROUP only once.
And it will be done automatically with a loop, you remove the unit reference of the global unit array once you have done the distance checks with other units of the array.

It blows my mind to write it in GUI especially since i have not opened the editor since years but i hope you figured what i meant.

EDIT EDIT :
you don't even need to fill other unit arrays, just keep the unit reference and increase a counter which represent the number of units around it with the correct distance (less or equal to the spell area effect).
So most likely a global integer array where the indice is the same as the global unit array.

GlobalUnitArray[0] = unit0 ; GlobalIntegerArray[0] = counter of unit0.

And even that is not especially needed, what you need is just to keep the higher counter, you can erase the previous smaller counter, and if it's equal to the previous one you don't need to do anything.

Here i'm assuming the spell will be started without any delay though (units won't move and the hero can cast the spell right now)
 
Last edited:
Level 6
Joined
Jul 21, 2020
Messages
67
Thanks for the methodology.

I'm pretty sure I get what you're saying and in my head at least see how I can do this in GUI. I was starting to get to a similar place but your methodology (and subsequent edits) definitely seems more efficient that where I was going. I'm curious what the performance penalty would be for this. That was my biggest hesitation. I could have up to 11 computer AI's going at once and right now each computer player "looks" around itself for new information every 1.5s, but to balance out the CPU load, the trigger runs every 0.5s and only handles ⅓ of the AI's at a time. Not sure if that made sense. So, say I have 11 AI's and I'm calculating this for an area around 1000 around each hero every time the unit looks. (Could be anywhere between 0 and 40 units around a hero at once). But I guess since I'm only creating a unit group once and then just doing math from that point on it could work out.

I'm going to definitely try it out and see if I can get it to work. I really appreciate the help!
 
The easiest way to solve this is base your ability of the blizzard ability with no effect (set damage to zero, remove all art, change number of waves to 1) as a dummy ability, then trigger its effects via a cast event.

The AI will always try to cast the blizzard ability in the fashion you want on enemies.

Now for the beneficial effect, id suggest checking out Healing Spray in a similar fashion.

Keep in mind that this approach is not optimal as the AI will intentionally try to avoid hitting allies with blizzard or enemies with Healing Spray. As your spell does benefit allies and hurt enemies at the same time you actually dont want that.


So if you can afford to do some triggering, heres the better solution:

- periodically pick all units within casting range of the hero that has this ability
- for each unit picked, pick all units around the picked unit within the AoE range of the spell and count the number of units around each of them
- the unit with the highest number of units around it will be your preferred target

If you want your AI to act even smarter, you could add weights to unit types to determine what unit has themost valuable targets within AoE range. Pro-tip: the Unit Point value object data field is used for exactly that purpose by the default AI. A unit with a point value of 200 is worth two units of point value 100, etc.
 
Last edited:
Level 6
Joined
Jul 21, 2020
Messages
67
@Zwiebelchen - Currently doing the "Easiest" way you mentioned for those types of spellsbut as you mentioned, it has drawbacks and falls short in some areas. Wondering with that much iteration will that slow things down too much? Since currently it checks all of the heroes every 1.5 seconds. and could be up to 11 hero AI. I guess though maybe I have it have 2 checks. 1 that checks all of the basic stuff and figures out the danger level. (using the point value currently to calculate danger around the unit in combination with the Hero's weighted Life and Mana so they'll run away if they are in a dangerous spot). And a second check that happens every 3 seconds or so to do a thorough check of the AI's surroundings. I guess to if performance becomes an issue, I could have a cap of say checking 10 units and just picks the best target in those 10 even if say there are 50 units around. So it might not always be the most accurate it would still do a pretty good job and if there are a ton of units it'd be pretty easy to find a reasonable target no matter what.
 
If you care about performance you can distribute the performance hit by checking each hero on a different time frame.

Basically run a loop that increments a global integer by 1 every 0.2 seconds and perform the search only for one hero (that of the player associated with that integer). Then after another 0.2 seconds in checks the next, etc.

The amount of processing time needed is the same, but it evens out over time better.


If you care about performance, you can also reduce the processing time by only picking units around the caster once and storing all units in a unit array, looping through them and checking ranges instead of doing multiple area picks. Dont expect this to make a huge difference though. You have to check all units with all units regardless of implementation so it will always be O(n^2) complexity.

That is unless you are willing to sacrifice accuracy of the AI by implementing some kind of randomness.

My suggestion is: try out the thing i described earlier first before worrying about optimization. Depending on how many units you have on your map it might not even matter.
 
Level 6
Joined
Jul 21, 2020
Messages
67
HAHA!! It works. I feel like a madman. Did a few extra things as well. Thanks for the help guys, this was the biggest thing holding my back from making my AI do cooler things. Basically I did what you said about spacing out the AI triggers so basically if figures out how many AI's are on the map and then sets the interval to be ( number of AI / 1.5 ) then loops through, so if you have 1 AI or 11 AI they will still get hit every 1.5 seconds.

Then, I basically went all in and built it to do everything I wanted it to be able to do; find the best clump, and using the square root of the point value to weight it (Basically even though I want it to target high value units, it should favor quantity, so I think that's a good way to bring it a little more in line). and it seems like it's working without really bogging down. Going to do a test soon with worse case scenario settings to make sure.

Then to further optimize, I added some more toggles to the heroes. Basically each hero has AI attributes I can set per hero to swing the the AI around to cater to it's needs, so basically if a hero is never going to need this function, it's just going to skip looking for clumps. The code is still a little rough, had to restructure quite a bit but here's the trigger that starts the AI for each here in the loop. Basically, this trigger is the intelligence trigger and then I have other triggers that then use this intelligence to change the AI's state.

  • AI MAIN SNAPS
    • Events
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • AI_B_Alive[AI_Loop] Equal to True
        • Then - Actions
          • -------- --------
          • -------- Reset Unit Groups --------
          • -------- --------
          • Set VariableSet AI_T_HeroesInRangeFriendly = (Units of type No unit-type)
          • Set VariableSet AI_T_HeroesInRangeEnemy = (Units of type No unit-type)
          • -------- --------
          • -------- Get Start Variables --------
          • -------- --------
          • Set VariableSet AI_T_HeroPosition = (Position of AI_Hero[AI_Loop])
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Or - Any (Conditions) are true
                • Conditions
                  • AI_B_Fleeing[AI_Loop] Equal to True
                  • AI_B_Low_Health[AI_Loop] Equal to True
            • Then - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (AI_HealDestination[AI_Loop] is alive) Equal to True
                • Then - Actions
                  • Set VariableSet AI_T_DestinationPosition = (Position of AI_HealDestination[AI_Loop])
                • Else - Actions
                  • Trigger - Run AI Go To Closest Heal <gen> (checking conditions)
            • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • AI_B_Chasing[AI_Loop] Equal to True
                • Then - Actions
                  • Set VariableSet AI_T_DestinationPosition = (Position of AI_ChaseHero[AI_Loop])
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (AI_Destination[AI_Loop] is alive) Equal to True
                    • Then - Actions
                      • Set VariableSet AI_T_DestinationPosition = (Position of AI_Destination[AI_Loop])
                    • Else - Actions
                      • Trigger - Run AI Attack a Base <gen> (checking conditions)
          • -------- --------
          • -------- --------
          • -------- Get Units / Heroes in Range --------
          • -------- Get Unit Value --------
          • -------- --------
          • -------- --------
          • -------- Find Units around AI --------
          • Set VariableSet AI_T_Units = (Units within 1000.00 of AI_T_HeroPosition matching ((((Matching unit) is alive) Equal to True) and ((Matching unit) Not equal to AI_Hero[AI_Loop])).)
          • Unit Group - Pick every unit in AI_T_Units and do (Actions)
            • Loop - Actions
              • -------- --------
              • -------- Get Attributed of selected Unit --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Picked unit) is A Hero) Equal to True
                • Then - Actions
                  • Set VariableSet TEMP_A_INT[1] = ((Hero level of (Picked unit)) x 75)
                  • Set VariableSet TEMP_A_INT[2] = 1
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • ((Picked unit) belongs to an ally of (Owner of AI_Hero[AI_Loop]).) Equal to True
                    • Then - Actions
                      • Unit Group - Add (Picked unit) to AI_T_HeroesInRangeFriendly
                    • Else - Actions
                      • Unit Group - Add (Picked unit) to AI_T_HeroesInRangeEnemy
                • Else - Actions
                  • Set VariableSet TEMP_A_INT[1] = (Point-value of (Picked unit))
                  • Set VariableSet TEMP_A_INT[2] = 1
              • -------- --------
              • -------- --------
              • Set VariableSet TEMP_A_UNIT[1] = (Picked unit)
              • Set VariableSet TEMP_Pos2 = (Position of (Picked unit))
              • Set VariableSet TEMP_A_REAL[1] = (Distance between AI_T_HeroPosition and TEMP_Pos2)
              • Set VariableSet TEMP_A_REAL[2] = (Percentage life of (Picked unit))
              • Set VariableSet TEMP_A_REAL[3] = (Unit: (Picked unit)'s Weapon Real Field: Attack Range ('ua1m') at Index:0)
              • -------- Temp Clumb Size --------
              • Set VariableSet TEMP_A_REAL[4] = 0.00
              • -------- --------
              • -------- --------
              • -------- Get General Calculations (Danger, Powerful Unit, Units very close) --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • ((Picked unit) belongs to an ally of (Owner of AI_Hero[AI_Loop]).) Equal to True
                • Then - Actions
                  • -------- --------
                  • -------- If PICKED UNIT is an Ally of AI --------
                  • -------- --------
                  • -------- Check if unit is more powerful than the current Allies --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TEMP_A_INT[1] Greater than (Point-value of AI_T_PowerfulUnitAlly)
                    • Then - Actions
                      • Set VariableSet AI_T_PowerfulUnitAlly = (Picked unit)
                    • Else - Actions
                  • -------- --------
                  • -------- Unit is Closer than 500 away from AI Add 3 to close Enemies --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TEMP_A_REAL[1] Less than or equal to 500.00
                    • Then - Actions
                      • Set VariableSet AI_T_CloseCountFriendly = (AI_T_CloseCountFriendly + TEMP_A_INT[2])
                    • Else - Actions
                  • -------- --------
                  • -------- Calculate Ally Danger Levels --------
                  • -------- Hero Calc ( HERO_LEVEL x 50 ) x ( LIFE% / 100 ) / ( DISTANCE_FROM_HERO / ATTACK_RANGE ) --------
                  • -------- Unit Calc (POINT_VALUE ) x ( LIFE% / 100 ) / ( DISTANCE_FROM_HERO / ATTACK_RANGE ) --------
                  • Set VariableSet AI_T_PowerFriendly = (AI_T_PowerFriendly + (Integer((((Real(TEMP_A_INT[1])) x (TEMP_A_REAL[2] / 100.00)) / (TEMP_A_REAL[1] / TEMP_A_REAL[3])))))
                • Else - Actions
                  • -------- --------
                  • -------- --------
                  • -------- If PICKED UNIT is an ENEMY of AI --------
                  • -------- --------
                  • -------- Check if unit is more powerful than the current Enemies --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TEMP_A_INT[1] Greater than (Point-value of AI_T_PowerfulUnitEnemy)
                    • Then - Actions
                      • Set VariableSet AI_T_PowerfulUnitEnemy = (Picked unit)
                    • Else - Actions
                  • -------- --------
                  • -------- Unit is Closer than 500 away from AI Add to Close Enemy Count --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TEMP_A_REAL[1] Less than or equal to 500.00
                    • Then - Actions
                      • Set VariableSet AI_T_CloseCountEnemy = (AI_T_CloseCountEnemy + TEMP_A_INT[2])
                    • Else - Actions
                  • -------- --------
                  • -------- Calculate Enemy Danger Levels --------
                  • -------- Hero Calc ( HERO_LEVEL x 50 ) x ( LIFE% / 100 ) / ( DISTANCE_FROM_HERO / ATTACK_RANGE ) --------
                  • -------- Unit Calc (POINT_VALUE ) x ( LIFE% / 100 ) / ( DISTANCE_FROM_HERO / ATTACK_RANGE ) --------
                  • Set VariableSet AI_T_PowerEnemy = (AI_T_PowerEnemy + (Integer((((Real(TEMP_A_INT[1])) x (TEMP_A_REAL[2] / 100.00)) / (TEMP_A_REAL[1] / TEMP_A_REAL[3])))))
              • -------- --------
              • -------- --------
              • -------- Find Unit Clumps --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • Or - Any (Conditions) are true
                    • Conditions
                      • AI_Strat_CalculateClumpAlly[AI_Loop] Equal to True
                      • AI_Strat_CalculateClumpComb[AI_Loop] Equal to True
                      • AI_Strat_CalculateClumpEnemy[AI_Loop] Equal to True
                • Then - Actions
                  • -------- --------
                  • -------- Temp Clumb Size ALLY --------
                  • Set VariableSet TEMP_A_REAL[4] = 0.00
                  • -------- Temp Clumb Size ENEMY --------
                  • Set VariableSet TEMP_A_REAL[5] = 0.00
                  • -------- --------
                  • Set VariableSet TEMP_UnitGroup = (Units within AI_Strat_CalculateClumpRange[AI_Loop] of TEMP_Pos2.)
                  • Unit Group - Pick every unit in TEMP_UnitGroup and do (Actions)
                    • Loop - Actions
                      • -------- --------
                      • -------- Ally Clumps --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked unit) belongs to an ally of (Owner of AI_Hero[AI_Loop]).) Equal to True
                          • ((Picked unit) is A structure) Equal to False
                          • ((Picked unit) is alive) Equal to True
                          • (Picked unit) Not equal to AI_Hero[AI_Loop]
                          • Or - Any (Conditions) are true
                            • Conditions
                              • AI_Strat_CalculateClumpAlly[AI_Loop] Equal to True
                              • AI_Strat_CalculateClumpComb[AI_Loop] Equal to True
                        • Then - Actions
                          • Set VariableSet TEMP_A_REAL[4] = (TEMP_A_REAL[4] + (Square root((Real((Point-value of (Picked unit)))))))
                        • Else - Actions
                      • -------- --------
                      • -------- Enemy Clumps --------
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked unit) belongs to an enemy of (Owner of AI_Hero[AI_Loop]).) Equal to True
                          • ((Picked unit) is A structure) Equal to False
                          • ((Picked unit) is alive) Equal to True
                          • (Picked unit) Not equal to AI_Hero[AI_Loop]
                          • Or - Any (Conditions) are true
                            • Conditions
                              • AI_Strat_CalculateClumpComb[AI_Loop] Equal to True
                              • AI_Strat_CalculateClumpEnemy[AI_Loop] Equal to True
                        • Then - Actions
                          • Set VariableSet TEMP_A_REAL[5] = (TEMP_A_REAL[5] + (Square root((Real((Point-value of (Picked unit)))))))
                        • Else - Actions
                  • Custom script: call DestroyGroup ( udg_TEMP_UnitGroup )
                  • -------- --------
                  • -------- Check to see if Ally Score is higher than Stored Score --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TEMP_A_REAL[4] Greater than AI_T_ClumpAllyScore
                      • Or - Any (Conditions) are true
                        • Conditions
                          • AI_Strat_CalculateClumpAlly[AI_Loop] Equal to True
                          • AI_Strat_CalculateClumpComb[AI_Loop] Equal to True
                    • Then - Actions
                      • Set VariableSet AI_T_ClumpAllyScore = TEMP_A_REAL[4]
                      • Set VariableSet AI_T_ClumpAllyUnit = TEMP_A_UNIT[1]
                    • Else - Actions
                  • -------- --------
                  • -------- Check to see if Enemy Score is higher than Stored Score --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • TEMP_A_REAL[5] Greater than AI_T_ClumpEnemyScore
                      • Or - Any (Conditions) are true
                        • Conditions
                          • AI_Strat_CalculateClumpEnemy[AI_Loop] Equal to True
                          • AI_Strat_CalculateClumpComb[AI_Loop] Equal to True
                    • Then - Actions
                      • Set VariableSet AI_T_ClumpEnemyScore = TEMP_A_REAL[4]
                      • Set VariableSet AI_T_ClumpEnemyUnit = TEMP_A_UNIT[1]
                    • Else - Actions
                  • -------- --------
                  • -------- Check to see if Combined Score is higher than Stored Score --------
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (TEMP_A_REAL[4] + TEMP_A_REAL[5]) Greater than AI_T_ClumpCombinedScore
                      • AI_Strat_CalculateClumpComb[AI_Loop] Equal to True
                    • Then - Actions
                      • Set VariableSet AI_T_ClumpCombinedScore = (TEMP_A_REAL[4] + TEMP_A_REAL[5])
                      • Set VariableSet AI_T_ClumpCombinedUnit = TEMP_A_UNIT[1]
                    • Else - Actions
                • Else - Actions
              • Custom script: call RemoveLocation ( udg_TEMP_Pos2 )
          • -------- --------
          • -------- --------
          • -------- Get Current Life (Health + Mana) --------
          • -------- --------
          • -------- Update historical Health information --------
          • For each (Integer TEMP_IntLoop1) from 1 to 3, do (Actions)
            • Loop - Actions
              • Set VariableSet AI_Snaps_Health[((AI_Loop x 3) + (3 - TEMP_IntLoop1))] = AI_Snaps_Health[((AI_Loop x 3) + (2 - TEMP_IntLoop1))]
          • Set VariableSet AI_Snaps_Health[(AI_Loop x 3)] = (Percentage life of AI_Hero[AI_Loop])
          • -------- --------
          • -------- Health + Mana + Weighted Health and Mana --------
          • Set VariableSet AI_T_HealthCurrent = (Life of AI_Hero[AI_Loop])
          • Set VariableSet AI_T_ManaCurrent = (Mana of AI_Hero[AI_Loop])
          • Set VariableSet AI_T_SnapLifeCurrent = ((AI_T_HealthCurrent x AI_Strat_Heal_HealthFactor[AI_Loop]) + (AI_T_ManaCurrent x AI_Strat_Heal_ManaFactor[AI_Loop]))
          • Set VariableSet AI_T_SnapLifeMax = (((Max life of AI_Hero[AI_Loop]) x AI_Strat_Heal_HealthFactor[AI_Loop]) + ((Max mana of AI_Hero[AI_Loop]) x AI_Strat_Heal_ManaFactor[AI_Loop]))
          • Set VariableSet AI_T_SnapLifePercent = ((AI_T_SnapLifeCurrent / AI_T_SnapLifeMax) x 100.00)
          • -------- --------
          • -------- Average Damage over last three cycles and since last cycle --------
          • Set VariableSet AI_T_HealthLost1 = (AI_Snaps_Health[((AI_Loop x 3) + 1)] - AI_Snaps_Health[((AI_Loop x 3) + 0)])
          • Set VariableSet AI_T_HealthLostAll = (AI_Snaps_Health[((AI_Loop x 3) + 2)] - AI_Snaps_Health[((AI_Loop x 3) + 0)])
          • -------- --------
          • -------- Boost enemy power based on AI's current Weighted Health --------
          • Set VariableSet AI_T_PowerEnemy = (Integer(((Real(AI_T_PowerEnemy)) x (((100.00 - AI_T_SnapLifePercent) / 20.00) + 0.50))))
          • Set VariableSet AI_T_PowerCount = (AI_T_PowerEnemy - AI_T_PowerFriendly)
          • -------- --------
          • -------- Give Hero confidence boost (Higher the level the more confidence.) --------
          • Set VariableSet AI_Strat_Power_Base[AI_Loop] = (AI_Strat_Power_Base[AI_Loop] + (0.25 x (Real((Hero level of AI_Hero[AI_Loop])))))
          • Set VariableSet AI_T_PowerHero = ((Integer(AI_Strat_Power_Base[AI_Loop])) + ((Integer(AI_Strat_Power_LevelFactor[AI_Loop])) x (Hero level of AI_Hero[AI_Loop])))
          • -------- --------
          • Game - Display to (All players) the text: (Ally: + ((String(AI_T_PowerFriendly)) + ( Enemy: + (String(AI_T_PowerEnemy)))))
          • Game - Display to (All players) the text: (Hero: + (String(AI_T_PowerHero)))
          • Game - Display to (All players) the text: (Combined Clump: + ((String(AI_T_ClumpAllyScore)) + ( Unit: + (Name of AI_T_ClumpAllyUnit))))
          • Special Effect - Create a special effect attached to the overhead of AI_T_ClumpAllyUnit using Abilities\Spells\Other\TalkToMe\TalkToMe.mdl
          • Special Effect - Destroy (Last created special effect)
          • -------- --------
        • Else - Actions
 
Good to hear that you got it working.

Honest words though: at this level of complexity, you should really make the switch to Jass or Lua. Its worth the time investment to learn the basics and will save you so much time in the long run. The performance gain is also a nice added bonus.
 
Last edited:
Level 6
Joined
Jul 21, 2020
Messages
67
Biggest thing I have stopping me from that is figure out the tool to start creating in. It seems like half of the Jass editors out there for warcraft are broken or just don't have good syntax highlighting or code completion. Which for me has been a huge hurtle into trying to do more than basics in it.
 
Biggest thing I have stopping me from that is figure out the tool to start creating in. It seems like half of the Jass editors out there for warcraft are broken or just don't have good syntax highlighting or code completion. Which for me has been a huge hurtle into trying to do more than basics in it.
Vscode works well so far and can be set up to actually edit the maps .j files directly so you dont have to copy and paste your code in.
It also has autocomplete and a function browser. The only thing you are missing out on is plug-and-play syntax checking via save & test from the original editor.
 
Level 6
Joined
Jul 21, 2020
Messages
67
I didn't realize that. I've used VScode for a few other things, I'll definitely check that out. Now I just need to understand the workflow for doing this but I think you're right, it's time I learned how to do this properly. I've read some good things about Lua but from what I've gathered, it's quite a big change if I want to take my existing map which is set to JASS. (Only use custom script steps for cleaning up variables and a few other things that I couldn't do in GUI). Do you think it's worth the pain of switching to Lua? Or should I just stick with JASS?
 
Level 6
Joined
Jul 21, 2020
Messages
67
I've done a little research and am finding only bits and pieces of setting things up the way you're mentioning. Wondering if you could point me in the right direction to set that up.

I have done a little experiment though.

So I just decided to transform this trigger to JASS using the convert thing in the world editer and copied it into VSCode with a code completion thing I found, and I see what you're saying about it being inefficient. The way it handles if statements is crazy. I know other programming languages so I get the jist for the most part of what's happening here. I gotta go find some tutorials because while I can obviously see some things that are not efficient, I'm sure there are a 1000 other things I could use.

Wow, just getting rid of all of the extra dumb functions that GUI adds when converted to custom text and doing it for just this one trigger, performance on my map went from 20 fps on my windows VM box to 30 fps.

Again though if you could help me figure out the editing the file directly bit, that would be awesome so I don't have to copy / paste everything.

Thanks Again! Even if you don't respond.
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
Where GUI is really inefficient is not especially because it use many dummy functions for a condition or just a BJ instead of a native function,
in some way vJass does the same when it converts to jass. (i'm not trolling, vjass is great)

It's more because it creates many handles for nothing (and you have to care about destroying them or you will have a memory leak), like locations, groups.
For example you don't need locations to check distances between units, you can use GetUnitX/Y directly.
Also you can't loop through a group without using a ForForce which creates a "new thread" for each unit "enumed", and so one.

Anyway, as you know, writing code is way much flexible and easy to use again later than a Graphic User Interface.
 
Level 6
Joined
Jul 21, 2020
Messages
67
Thanks for the info. Now that I've made it a lot cleaner looking, I'm starting to go through now and figure out what I can make local variables, and converting ForForce things to straight up loops, good to know about checking distances, I'll check on that. Now that I have it kinda working in vsCode, it's actually a lot easier to pick up than I anticipated. Going through some basic tutorials to try to understand the things that I should change to make it more native in JASS. One question I had, Locals are MUI right? Because they get created at each instance that the function is triggered? And can I use delays now? or do I still need to stick to the way that I've done spells to be MUI using the GUI?

Once I get the hang of the functions and stuff, I can definitely seeing this get a lot faster to use than GUI. I starting making maps as a teenager back in the day, and always saw JASS as being super complicated but yeah, it's time to learn and I know a lot more than I did back then. lol

There are some suggestions in this thread: Current vJass coding meta?

Also, thanks for that thread link. Super helpful info. Looks like HiveWE is going to pretty much make this all work once it releases.
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
Yeah about MUI, even if some Get... are already MUI by nature, like GetTriggeringUnit IIRC
I made a complete test of each Get... once, to know if it was MUI or not, however it does matter only from a GUI point of view, and even with GUI i guess shadowing a local variable local ... udg_... did the trick, but hmm not really on a second though, since you mentionned conditions of if which use intermediate functions.
Well, just forget GUI lol.

Also the only way to have accurate wait is to use timers (and the wait doesn't continue to expire while game is paused, unlike TriggerSleepAction).
It splits the code though.
And PolledWait is not accurate enough because of the partial usage of TriggerSleepAction.

Using several waits in a same funtion is a pain in the ass, i haven't even think a little about it for now but it should be easier in lua with all the built in features provided by the language
 
Last edited:
Status
Not open for further replies.
Top