• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • It's time for the first HD Modeling Contest of 2025. Join the theme discussion for Hive's HD Modeling Contest #7! Click here to post your idea!

Creating a new RPG, a few wc3 editor noob questions

Status
Not open for further replies.
Level 4
Joined
May 28, 2023
Messages
36
Hey Hive dudes and gals. I've spent over 200 hours creating a new RPG for the people on Battlenet and wherever else you may play this glorious game. (WC3)

I only do wc 3 editor triggers as I did not find a need to go advanced scripting yet. (And I don't know how to anyway hehe)


Things progress without major issues, so I've only got a few simple questions, luckily! I'll attach a map overview for the curious and then a few screenshots of the triggers I have a few questions about. And I apologize if these questions have been answered in another thread, I will read if you post a link for me.

1. Attachment: cr init, respawn and setup. I found this "spanish trigger" somewhere on the internetz and copied it - it seems to work with the limited testing I did, but I want to know if it's actually a good respawn system for neutral hostile creeps?

2. Attachment: centaur spawn/target. Patrolling around a camp. They run from one zone to the next, in a circle. Is there a better way to do this with triggers or is this a good solution?

3. Attachment: only one race. I got 3 items that functions like the tiny great hall, they build 3 different Town Halls. The 3 town halls upgrade into the many different factions I've created as custom races. I want to limit the players to only have the town hall they pick be the only one they can build. Not build all 3 then upgrade them to different races... It's a item/town hall limit question and I'm looking for the best solution.

4. Attachment: uknown. A silly question: What is that upgrade used by the wisp? If I click edit on it, it takes me to the normal human upgrade screen, as if the upgrade does not exist.


Thank you in advance
Fosphor
 

Attachments

  • fosphor rpg map overview.png
    fosphor rpg map overview.png
    2.8 MB · Views: 34
  • only one race.png
    only one race.png
    58.4 KB · Views: 27
  • centaur target.png
    centaur target.png
    50.6 KB · Views: 15
  • centaur spawn.png
    centaur spawn.png
    59.3 KB · Views: 16
  • cr setup.png
    cr setup.png
    59.7 KB · Views: 17
  • cr respawn.png
    cr respawn.png
    52.3 KB · Views: 21
  • cr init.png
    cr init.png
    43.5 KB · Views: 27
  • uknown.png
    uknown.png
    96.5 KB · Views: 36
Last edited:
Level 22
Joined
Dec 4, 2007
Messages
1,537
Map looks fine and varied!

CR with custom value is alright for now, but keep in mind that you can't use another custom value system on top of it.
Such as Unit indexing (which opens a lot of neat methods to do stuff). So eventually you probably will look for a different respawn sys.

You don't need advanced scripting methods, but certainly an understanding about things that leak:
Mainly dynamic locations, like in your centaur spawn trigger.

3. should work fine.

4. custom upgrade that you deleted? What game version are you on?
 
Level 4
Joined
May 28, 2023
Messages
36
Map looks fine and varied!

CR with custom value is alright for now, but keep in mind that you can't use another custom value system on top of it.
Such as Unit indexing (which opens a lot of neat methods to do stuff). So eventually you probably will look for a different respawn sys.

You don't need advanced scripting methods, but certainly an understanding about things that leak:
Mainly dynamic locations, like in your centaur spawn trigger.

3. should work fine.

4. custom upgrade that you deleted? What game version are you on?
Thank you for the compliment on the map layout!

Yeah the CR custom value, I read I'm stuck on that for now, but as you say I can upgrade anytime I want :)

I will check out the leaking part to see if I can make my map as stable as possible.

Uh can you explain a bit more what you mean dynamic locations like in my spawn trigger? The "Unit facing" is leaking?

3. Ok, takes a long time to do though haha

4. It's on the normal wisp that I have not modified... I should be on the newest version. :eek:
 
Last edited:
Level 28
Joined
Sep 26, 2009
Messages
2,540
Ad 1
I don't think the CR triggers will work correctly - the respawn trigger refers to (Dying unit) after a 120.0 second wait. As far as I know, Dying Unit is a global variable, so its value may get changed over the course of the 120.0 second wait.
Using (Triggering unit) instead should resolve the issue.

Another potential problem is the respawn trigger is only fired for units owned by Neutral Hostile. That may be fine if your map does not have any way to change player owner of a unit (like Dark Ranger's Charm or Banshee's Possession) - but if you have such abilities in your map, then you may have issues: Imagine a situation, where a Neutral Hostile creep is charmed by a player and then that charmed creep dies - the condition that the owner of dying unit is Neutral Hostile would not be true, so the creep would never respawn. A solution could be that you keep that creep in a unit group and instead of checking Neutral Hostile, you check the unit group.

Also, CR Init should use 'Map initialization' event rather than the 0.1 second delay.

Ad 2
I am not sure if this is by design, but the centaur spawn trigger will only spawn units if all the conditions in the condition block are true. So for example the trigger will not spawn any unit if you have 0 shamans, 0 warriors, 0 raiders, 0 hunter and 25 youths.

Centaur Target has holes in its logic and can also be optimized. The issue in the trigger is that you only order the centaur once to attack-target a location, but the centaur may lose that order (for example by getting rooted by ability like Entangling Roots). Because you don't re-order the centaur to attack-move somewhere, it will remain standing in place.
The solution to that is to keep track where each centaur should be heading and periodically order the centaur to attack-move there.

The optimization comes from the fact that you can use array variables. Let's say you want the centaur to run from region A to region B, from region B to region C and from region C back to region A.
If you create a region array and set its values like so:
  • Set centaurRegions[1] = Region A
  • Set centaurRegions[2] = Region B
  • Set centaurRegions[3] = Region C
then each centaur can keep track of where he is heading by keeping track of the index. For example a centaur attack-moving to Region B will keep track of index 2. Once the centaur enters Region B, you can just increment the index by 1 and order him to attack-move the region under currently tracked index (3) which in this case would target Region C.
That way you can have only a single Centaur W Target trigger that will work the same way as your 6 triggers together.

Ad 3
If I understand this correctly, you have a list of buildings that you want to make unavailable for construction, except for one building from the list (and for each item that one building is different).
Instead of having an If/Then/Else and in each block have huge lists of buildings, I would just disable all buildings at the start of the trigger and then use an If/Then/Else to make only that one special building availabe for construction once again.
 
Level 4
Joined
May 28, 2023
Messages
36
Some very good suggestions, thank you very much!

Ad 1
I thought about the charm or banshee switching control would stop the unit from respawning, would ressurecting the corpse as a skeleton stop it aswell?
If I want to make it a unit group instead of 'neutral hostile', I would have to add every unit into that group, correct? Ugh haha

Ad 2
The centaurs loosing the order is true, the fix you suggest seems like a good idea. Now I just need to figure out how to do it

Ad 3
Yeah 3 items/buildings that upgrades into a bunch of different upgrades. Again, the fix you suggest is much simpler than what I was doing hah

Ad 4
You got nothing on this one? :D
 
Last edited:
Level 28
Joined
Sep 26, 2009
Messages
2,540
Ad 1
Yes, some other spells could cause problem. For example necromancer's Raise Dead spawns skeletons from corpse or Ghoul's Cannibalize devours the corpse. In both cases the corpse is completely removed from the game, so when you would want to create same unit type as the (dying unit) after the 120.0 second wait then no unit would be created as the dying unit would be completely removed from the game, leaving nothing to refer to.

You don't have to use a unit group - that was an example. Another way is to use a data structure like Hashtable and store a boolen there to mark the unit as Respawnable - this you would have to set at map start and any time you create/respawn a new creep.
In the trigger that reacts to creep's death, you would just check if the Respawnable flag == true and if so, then run the wait and create new creep.

You also already have the type, location and angle stored via the three variables in CR Setup. You could just add another variable there: CR_IsRespawnableCreep which would be a boolean array. The respawn trigger could look like this:
  • Respawn Creep
    • Events
      • Unit - A unit Dies
    • Conditions
      • CR_IsRespawnableCreep[(Custom value of (Triggering unit))] Equal to True
    • Actions
      • Custom script: local integer cv //declare local variable - local variable won't get overwritten during the wait
      • Set VariableSet customValue = (Custom value of (Triggering unit))
      • Custom script: set cv = udg_customValue //assign the value from global variable 'customValue' to local variable 'cv'
      • Wait CR_Time seconds
      • Custom script: set udg_customValue = cv //assign value back from local to global variable
      • Unit - Create 1 CR_Type[customValue] for Neutral Hostile at CR_Point[customValue] facing CR_Angle[customValue] degrees
      • Unit - Set the custom value of (Last created unit) to customValue
      • -------- .. continue on with the If/Then/Else --------
Do note that a variable declared in the world editor must have a udg_ prefix when used in Custom Script action

Ad 2
For keeping track you can use similar approach with Custom Value that you use in the creep respawn (provided that you assign the custom value to the unit or use a system for it).
Something like this could work (I omitted some details you have, it's just for you to get the general idea of how it could be achieved)

  • Map Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set VariableSet CentaurRegions[1] = Centaur 1 <gen>
      • Set VariableSet CentaurRegions[2] = Centaur 2 <gen>
      • Set VariableSet CentaurRegions[3] = Centaur 3 <gen>
      • Set VariableSet CentaurRegions[4] = Centaur 4 <gen>
      • Set VariableSet CentaurRegions[5] = Centaur 5 <gen>
      • Set VariableSet CentaurRegionCount = 5
  • Centaur Spawn
    • Events
      • Time - Every 90.00 seconds of game time
    • Conditions
    • Actions
      • For each (Integer A) from 1 to 2, do (Actions)
        • Loop - Actions
          • Unit - Create 1 Centaur Youth for Player 12 (Brown) at (Random point in Centaur 1 <gen>) facing Default building facing degrees
          • -------- // do stuff with assigning Custom Value to your created centaur --------
          • // Since the centaur in this case is created in Centaur 1 region, set the next target index as 2, which points to Centaur 2 region
          • Set VariableSet CentaurTargetRegionIndex[(Custom value of (Last created unit))] = 2
  • Centaur Enters Centaur Region
    • Events
      • Unit - A unit enters Centaur 1 <gen>
      • Unit - A unit enters Centaur 2 <gen>
      • Unit - A unit enters Centaur 3 <gen>
      • Unit - A unit enters Centaur 4 <gen>
      • Unit - A unit enters Centaur 5 <gen>
    • Conditions
      • // the condition here is just to check that the centaur entered the region he was meant to
      • (CentaurRegions[CentaurTargetRegionIndex[(Custom value of (Triggering unit))]] contains (Triggering unit)) Equal to True
    • Actions
      • Set VariableSet customValue = (Custom value of (Triggering unit))
      • Set VariableSet CentaurCurrentTarget = CentaurTargetRegionIndex[customValue]
      • Set VariableSet CentaurCurrentTarget = ((CentaurCurrentTarget mod CentaurRegionCount) + 1)
      • Set VariableSet CentaurTargetRegionIndex[customValue] = CentaurCurrentTarget
  • Centaur Periodic AttackMove
    • Events
      • Time - Every 3.00 seconds of game time
    • Conditions
    • Actions
      • // I used unit group here as example, but it could be something like what you have - picking all units of specific player, etc.
        • Unit Group - Pick every unit in Centaurs_Group and do (Actions)
          • Loop - Actions
            • Unit - Order (Picked unit) to Attack-Move To (Center of CentaurRegions[CentaurTargetRegionIndex[(Custom value of (Picked unit))]])
The "Enters region" trigger does not order the centaur to attack-move anywhere, it just updates the target region. The periodic trigger instead will keep ordering the centaur to attack somewhere.

Ad 4
There is nothing really for me to comment on. When you have an 'Unknown (...)' unit/ability/tech, it means you are referring to something which was not found - in your case in the Upgrades Used section you refer to upgrade which does not exist in your map. Hard to say what it belonged to originally.
 
Level 4
Joined
May 28, 2023
Messages
36
Hmm I get the idea behind these two edited triggers, but the variables and the custom scripting is where I get confused!
When I read it, it sounds simple enough. When I try to do it, many road blocks prevent me from progressing, mostly due to my inexperience...
A lot of the difficulty come from finding the correct option so the editor will allow me to do what I want haha


The boolean is easy to create but I don't rly know when to array these, which is very basic knowledge I guess

The conditions don't show the custom value option, unlike actions which allows me to make one equal to:
"CR_IsRespawnableCreep[(Custom value of (Triggering unit))] Equal to True"

(CentaurRegions[CentaurTargetRegionIndex[(Custom value of (Triggering unit))]] contains (Triggering unit)) Equal to TrueCentaur Target::
Can't seem to find the options to make this one

Set VariableSet customValue = (Custom value of (Triggering unit))
Also can't seem to find the option to make the = (Custom value of (Triggering unit))

Set VariableSet CentaurRegionCount = 5
What variable type is CentaurRegionCount?


Well, despite my inability to make these new triggers I learned new things messing with these triggers and variables. This seems like the logical next step for me to progress to create better triggers. Even if you ghosted me now Nichilus, I would still thank you for showing me these. :)
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
Set VariableSet CentaurRegionCount = 5
5 is an Integer, therefore CentaurRegionCount is an Integer variable. The value tells you the type. This logic applies to all variable types.

(CentaurRegions[CentaurTargetRegionIndex[(Custom value of (Triggering unit))]] contains (Triggering unit)) Equal to True
^ This is a Boolean Comparison since it's value is True (booleans are either true/false. boolean variables default as false).

The name of the function should be something along the lines of "Region contains unit", it can be hard to find but try to read carefully from top to bottom. The functions are also organized by category.

Set VariableSet customValue = (Custom value of (Triggering unit))
^ Again, the function is there, you just need to look harder. customValue is an Integer variable.

"CR_IsRespawnableCreep[(Custom value of (Triggering unit))] Equal to True"
^ This is a Boolean Comparison. You need to click on the [index], which is the number in the brackets, and you'll find the same list of functions that you found when setting the customValue variable. Again, the function is in there.

An Array is basically a way to turn a single variable into many. It enables a lot of neat tricks for storing information directly to Players/Units (or really anything you want). If you ever catch yourself copying and pasting a variable over and over again, ask yourself, should this be an Array instead? The answer is most likely yes. Learn how to use these asap as they're the most powerful tool in your modding arsenal.

Good luck!
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
5 is an Integer, therefore CentaurRegionCount is an Integer variable. The value tells you the type. This logic applies to all variable types...
Ok, I got the CentaurRegionCount integer and the 5 regions setup.

(CentaurRegions[CentaurTargetRegionIndex[(Custom value of (Triggering unit))]] contains (Triggering unit)) Equal to True
I still have trouble finding.

Will report back later how I progress.
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
It's all categorized in alphabetical order.

The Condition is checking if a Unit is contained inside of a Region so logic tells us that Unit - Unit In Region must be the solution you're looking for:

ex.png


The Function names in this list can be worded a bit differently than their trigger form, so a little bit of trial and error may be necessary.
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
It's all categorized in alphabetical order.

The Condition is checking if a Unit is contained inside of a Region so logic tells us that Unit - Unit In Region must be the solution you're looking for...

When I enter the 'Unit in Region' menu I'm looking for the custom value, but the 9 options in function does not seem to bring me closer to my goal (Or maybe I'm staring right at the correct option hehe)

It's actually the same problem I got in all 3 of the triggers Nichilus linked. How do I set it to custom values?


region.png


Also totally unrelated question, but I should have realized Ajmun (first guy who commented here) hinted at my map having leaks. A look through the link he provided to a 2007 post tells me I got blacklisted triggers and units leak and whatnot - is this something I need to be afraid of in a large rpg like map?
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
You're under the Function category. The Regions you're trying to access are variables, so they'd be under the Variable category.

Once you've selected the correct variable, IF it's an array, you'll see brackets [] after it's name. Inside of those brackets is where you can put the Custom Value or any Integer value for that matter. This Integer value is called the [index] of the array and acts like a unique instance of the variable it belongs to.

Here's an example of a Region array variable being used to track multiple regions at once:
  • Set Variable MyRegionVar[1] = some region
  • Set Variable MyRegionVar[2] = some other region
  • Set Variable MyRegionVar[3] = some other other region
Each [index] can hold a single value. Here we're tracking 3 regions by storing the first one at index [1], the second at index [2], and the third at index [3].

Memory leaks are not the end of the world as long as you don't create too many. Pretty much every custom map you've ever played has had leaks, even the more advanced ones. That being said, it's wise to learn how they work so you can avoid them if possible. They can be particularly nasty when you have a trigger that runs very often, like say a trigger with a timer that runs 100 times per second and creates multiple leaks each cycle. Or a trigger with an Event like "A unit is attacked" which can happen very often in certain types of maps.
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
Ugh this is a lot of headache to get some centaurs to attack move around the place haha


You're under the Function category. The Regions you're trying to access are variables, so they'd be under the Variable category...
Dude thanks for taking the time to help me, a noob like me :)
I feel like I'm getting very close thanks to your help and the other guys directions.

I'm on deep water and very clueless, but what I lack in strength and intelligence I make up for in tenacity hehe
It will be easier to show in pictures than explain how far I am, so I'll link my current progress.

1. attachment (variableAndSpawn) I need to make the value 2, but I'm limited to true or false. Close but no cigar yet.

2. attachment (centaurentersregion) he seems to have a variable called 'CentaurCurrentTarget'. I'm not sure if this is an option or what kinda variable he created. It would not be hard to create it, but I'm kinda just confused here. Maybe I missed something.

3. attachment (periodicattackmove) Here the only variable option I got is CR_Point from my respawn system. I'm looking for the other variable but I guess I did something wrong since it does not show up? I'm looking for one called CentaurTargetRegionIndex but ehh... yeah.

4. attachment is what Nichilus posted for me.

So yeah I'm progressing, but rather slowly I guess haha
 

Attachments

  • target.png
    target.png
    48.9 KB · Views: 8
  • periodicattackmove.png
    periodicattackmove.png
    31.5 KB · Views: 4
  • centaurentersregion.png
    centaurentersregion.png
    37.5 KB · Views: 7
  • variableAndSpawn.png
    variableAndSpawn.png
    33.4 KB · Views: 7

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
Your final picture (target) is looking good. There's only three problems I see:

1) You're never adding these Centaurs to the Centaurs_Group (unit group variable). This means that in your Centaur Periodic AttackMove trigger nothing is going to happen to the Centaurs because Centaurs_Group is empty. A Unit Group is basically a container in which you can add or remove Units to and from. It's how you can manage 100's of Units at once without needing to create a crazy convoluted trigger where you're managing each individual Unit and have 100's of Actions to do so.

The solution is simple, add this Action after creating a Centaur:
  • Unit - Create 1 Centaur Youth...
  • Unit Group - Add (Last created unit) to Centaurs_Group
2) You're never assigning a unique Custom Value to your Centaurs. By default a Unit's custom value will always be equal to 0, so in your case each Unit is sharing the same exact Custom Value. Now if you remember how I described Arrays and Indexes in my last post, each [index] can only hold a single value of data at a time. This means that if you're plugging the integer [0] into CentaurTargetRegionIndex[] for every single newly created Centaur then they're all going to be fighting over that same [index] which will cause problems once you have more than one Centaur on the map.

The solution is simple, add this system to your map:
It automatically handles assigning each Unit in your map a unique Custom Value. You literally copy and paste the Trigger Editor folder from the demo map into your own map and that's it, the system handles everything else. From that point on you can take advantage of the system by using Custom Value as the [index] in your arrays. This enables you to easily attach data to your individual Units which is extremely useful.

IMPORTANT:
Note that the system has an important requirement. You CANNOT EVER set Custom Value yourself. Since the system is automatically managing the assigning of Custom Value to Units it will break everything if you interfere. Luckily, the system literally makes setting Custom Value yourself obsolete, as you can now just use the system to achieve the same exact results. For example, an Integer array can be used to replace all instances of where you were Setting custom value yourself.

3) The Centaur Enters CentaurRegion trigger is actually done perfectly, HOWEVER, there's an annoying Warcraft 3 bug that's going to make this a pain. When the Event "A unit enters region" happens the Unit isn't actually considered "Inside of the region" yet, so your Condition that checks if the "Region contains Unit" will fail. I have a solution in the attached map which you'll need to implement and configure. It's a single trigger that will adjust the Regions to work properly, but you need to Set the variables FixRegionCount and FixRegion to have the correct values (instructions are included).


Also, before doing any of this, make sure your map's Preferences are setup properly. This is under File/Preferences in the Editor:
1686310395181.png

The unchecked ones can be enabled if you'd like, those are just my personal preferences.
 

Attachments

  • Region Fixer 1.w3m
    17.3 KB · Views: 3
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
Your final picture (target) is looking good. There's only three problems I see...

Well now I'm adding a Unit Indexer to my map... This project is escalating more and more hehe

1) Oh a very easy solution!

2) And this is the simple one! This is going to take some reading. Could you tell me how to apply it in this case?

3) Preferences: I understand the uknown variable but why negative real values? It even gave me a warning (I'm just curious, it's not important to me)

The region fixer is interesting, I did not know that bug, strange! So if I understand correctly: I place my 5 (or x) centaur regions into the fixer, it then fixes the regions - And I do this as a solo trigger and then do other stuff with the regions in other triggers, correct?
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
Like I said on #2 about the Unit Indexer system:
The system automatically handles assigning each Unit in your map a unique Custom Value. You literally copy and paste the Trigger Editor folder from the demo map into your own map and that's it, the system handles everything else. From that point on you can take advantage of the system by using Custom Value as the [index] in your arrays. This enables you to easily attach data to your individual Units which is extremely useful.
So once you have the Unit Indexer trigger in your map you're finished. From then on you simply take advantage of what the system is doing.

Here's an example of taking advantage of the Unit Indexer system:
  • Unit - Create 1 Archmage...
  • -------- the unit indexer system kicks in and automatically assigns a unique custom value to the Archmage --------
  • Set Variable BonusSpellDamage[(Custom value of Last created unit)] = 100.00
  • Unit - Create 1 Bloodmage...
  • -------- the unit indexer system kicks in and automatically assigns a unique custom value to the Bloodmage --------
  • Set Variable BonusSpellDamage[(Custom value of Last created unit)] = 555.00
The Archmage has been assigned a value of 100.00 for it's BonusSpellDamage.
The Bloodmage has been assigned a value of 555.00 for it's BonusSpellDamage.

Note how useful this is, we now have a single variable (BonusSpellDamage) which can contain unique data for every unit.

Now let's put this variable to use:
  • Events
    • Unit - A unit Starts the effect of an ability
  • Conditions
    • (Ability being cast) Equal to Banish
  • Actions
    • Unit - Cause (Casting unit) to damage (Target unit of ability being cast) dealing BonusSpellDamage[(Custom value of (Casting unit))] damage...
Whenever a Unit casts the Banish ability it's BonusSpellDamage is dealt to the target as well.

This is just an example, you can use ANY type of variable array to attach ANY type of data you want to your Units.

3) Negative real values allow you to create interesting things like a negative armor Devotion Aura that targets enemies instead of allies. Shadow Fiend's Presence of the Dark Lord from DotA comes to mind. The warning is there because some abilities don't like having negative values, but I think it's pretty obvious when you can and can't do this.

You're 100% correct about the Region Fixer. It fixes an issue where the coordinates of the Region (min x, max x, min y, max y) are slightly offset.

Note how the Events for these systems happen during Map Initialization (the loading screen), the idea is that these systems happen BEFORE any of YOUR triggers will run. With that in mind, be careful when using these systems in your own triggers that run during Map Initialization as you could be trying to use them before they've been initialized.
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
Like I said on #2 about the Unit Indexer system...

So I've copied both the region fixer and the unit indexer into my map and the indexer seems to work (I accidently deleted my only unit when playing hehe)

As far as I understand the unit Indexer now will assign a custom value to any created unit that runs after it's initialization, so I simply run most unimportant triggers that needs to start when the map starts at around 0.1 - 1 sec after map start? Triggers like spawning units.

I'm still unsure about 'centaurentersregion' and 'periodicattackmove' triggers. The entersregion one is tricky to make.
3) The Centaur Enters CentaurRegion trigger is actually done perfectly, HOWEVER
You say it's perfect with it 'set to custom value to 0' ?
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
Oh, target is not a picture of your triggers. I thought that was your final product for some reason... I understand now -_-

The Unit Indexer also assigns a custom value to all preplaced units. It's safe to create units any time after this Event has passed:
  • Time - Elapsed game time is 0.00 seconds
CentaurTargetRegionIndex is supposed to be an Integer array not a Boolean array. Again, you can see it's value is a whole number (Integer) so you know it must be an Integer variable. If it's value was True/False then you'd know it's a Boolean. We know Custom Value is an Integer therefore a Variable being Set to it MUST be an Integer as well.

CentaurRegions is supposed to be a single Region array variable. At the moment you have five separate Region variables.
See the [index] after it's name? That means it's an array. Brackets = Array.

Also, to clarify the logic of these triggers:
  • You create a Centaur at CentaurRegions[1].
  • You attach the value 2 to the Centaur using CentaurTargetRegionIndex[] and tell it to move to CentaurRegions[2].
  • Why 2? Because the Centaurs next destination is CentaurRegions[2].
  • Once the Centaur reaches CentaurRegions[2] you increase it's CentaurTargetRegionIndex by 1 and tell it to move to CentaurRegions[3].
  • Why increase it by 1? Because the Centaurs next destination is CentaurRegions[3].
  • This pattern makes the Centaur patrol from CentaurRegions[1] to [2] to [3] to [4] to [5] and then back to [1] again restarting the whole process.
But I realize this may be confusing:
  • Set Variable customValue = (Custom value of (Triggering unit))
  • Set Variable CentaurCurrentTarget = CentaurTargetRegionIndex[customValue]
  • Set Variable CentaurCurrentTarget = ((CentaurCurrentTarget mod CentaurRegionCount) + 1)
  • Set Variable CentaurTargetRegionIndex[customValue] = CentaurCurrentTarget
This is what is going to increase CentaurTargetRegionIndex by 1. The mod (a math function known as modulo) is there to make sure that when it reaches the final destination [5] it goes back down to [1]. Nichilus is too smart for us, I would've used an If Then Else statement and just checked if it was > 5.

You could also get rid of the CentaurCurrentTarget variable and do it like this:
  • Set Variable customValue = (Custom value of (Triggering unit))
  • Set Variable CentaurTargetRegionIndex[customValue] = ((CentaurTargetRegionIndex[customValue] mod CentaurRegionCount) + 1)
customValue and CentaurCurrentTarget are really only there to help make things easier to read. They aren't actually necessary.

These triggers are designed in a way that allows everything to be very adaptive. This way you don't have to change much if say you wanted to introduce a 6th CentaurRegion. It also allows you to always know where a Centaur should be going, so if it somehow got lost you can easily resume it's patrol route at any given moment.
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
It sounds good, hard to get right.

Ah good explanation on the CentaurTargetRegionIndex,

If I want to copy the 'Target' trigger then CentaurRegions can't be be a region variable? Otherwise I have to set a index as seen in the attachment to the right - I'm not sure what to choose here.

I'll work more on this later tonight!
 

Attachments

  • variables.png
    variables.png
    38.4 KB · Views: 7

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
That's not quite right.

All you have to do is delete these five variables:
CentaurRegions1 = ...
CentaurRegions2 = ...
CentaurRegions3 = ...
CentaurRegions4 = ...
CentaurRegions5 = ...

And replace them with one Region Array variable that uses five [indexes]:
CentaurRegions[1] = ...
CentaurRegions[2] = ...
CentaurRegions[3] = ...
CentaurRegions[4] = ...
CentaurRegions[5] = ...

CentaurTargetRegionIndex is now an Integer, so you did that correctly, but you forgot to make it an Array. Remember, the array is what allows us to store data directly to our units as well as track multiple regions with a single variable.

CentaurRegionsCount is supposed to be an Integer. It represents how many Regions we have which is why we Set it to 5.
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
That's not quite right.
Ah yes, it wasnt quite right at all! I deleted the variables and fixed it, now it looks like the 'Target' trigger.

It's very confusing though, right now I got 4 global variables only to do this! And it seems like I need to make another one called 'CentaurCurrentTarget' when looking at Nichilus 'CentaurEntersRegion' trigger. Current target, so it checks what region the centaur is currently moving to, what kinda variable would I use for that?

I'm not sure when or what to set the initial value to in the global variables. I read a guide on it but he did not mention it or maybe I missed it. Should be a fairly simple question: When and what do I set the initial value to?

In the first attachment is the completed region array and the 5 regions setup. Second attachment is the CentaurPeriodicAttackmove trigger that I finally solved.

Now I'm working on the 'CentaurEntersRegion' trigger, but he uses so many custom values that I can't find...

  • Set_VariableSet_CustomValue = (Custom Value of (Triggering Unit))
How do I even make this one? Or is this where I use the indexer?
 

Attachments

  • variablearrayregions.png
    variablearrayregions.png
    39.9 KB · Views: 5
  • anotheronedown.png
    anotheronedown.png
    9.3 KB · Views: 7
Last edited:
Level 28
Joined
Sep 26, 2009
Messages
2,540
CentaurCurrentTarget is an integer. It's not a configuration variable, it's just a helper variable when computing the next target region's index (in same way like the customValue variable).

  • Set VariableSet customValue = (Custom value of (Triggering unit))
  • Set VariableSet CentaurCurrentTarget = CentaurTargetRegionIndex[customValue]
  • Set VariableSet CentaurCurrentTarget = ((CentaurCurrentTarget mod CentaurRegionCount) + 1)
  • Set VariableSet CentaurTargetRegionIndex[customValue] = CentaurCurrentTarget
Here the CentaurCurrentTarget is assigned to the centaur's target region's index, then the modulo operation is performed on it, then it's incremented by 1. All of this is done to make the value "cycle" between min index and max index in the region's array (1-5).
Finally, the updated value is set back to the array CentaurTargetRegionIndex.

You can achieve the same with a single line, I chose the more descriptive way with a helper variable
  • Set VariableSet CentaurTargetRegionIndex[Custom value of (Triggering unit)] = ((CentaurTargetRegionIndex[Custom value of (Triggering unit)] mod CentaurRegionCount) + 1)
 

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
Ah yes, it wasnt quite right at all! I deleted the variables and fixed it, now it looks like the 'Target' trigger.

It's very confusing though, right now I got 4 global variables only to do this! And it seems like I need to make another one called 'CentaurCurrentTarget' when looking at Nichilus 'CentaurEntersRegion' trigger. Current target, so it checks what region the centaur is currently moving to, what kinda variable would I use for that?

I'm not sure when or what to set the initial value to in the global variables. I read a guide on it but he did not mention it or maybe I missed it. Should be a fairly simple question: When and what do I set the initial value to?

In the first attachment is the completed region array and the 5 regions setup. Second attachment is the CentaurPeriodicAttackmove trigger that I finally solved.

Now I'm working on the 'CentaurEntersRegion' trigger, but he uses so many custom values that I can't find...

  • Set_VariableSet_CustomValue = (Custom Value of (Triggering Unit))
How do I even make this one? Or is this where I use the indexer?
You shouldn't touch the Size or Initial Value for ANY of these variables. Often times that's unnecessary.

Variables have default values (aka Initial Values), an Integer is equal to 0 by default, a Real is equal to 0.00, a Boolean is equal to False, and a String is blank "". So when you set the Initial Value you're changing what it will default to, but that's not necessary here because these variables are going to be Set in the triggers to specific things based on the circumstances of the trigger.

Long story short, don't even look at the Initial Value and Size properties of a variable, just pretend they don't exist for now.

If you were to do this all again the process would go:

Step 1: Create all of the variables you see being used in our triggers. This means giving them the correct name, the correct type, and checking the Array checkbox if they have an [index] or leaving it unchecked if they do not.

Step 2: Now that you have created all of the variables, proceed to create the triggers. Create all of the triggers as blank slates and give them the proper names.

Step 3: Choose a trigger to start with, the order shouldn't really matter, and proceed to create the Events, Conditions, and Actions following our examples.

Step 4: Repeat Step 3 until you've created everything. Then come back here and complain when it doesn't work :p

Try not to overcomplicate or overthink it!
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
CentaurCurrentTarget is an integer...
Ah the customValue is a global variable? That is why I could not figure out how to make that trigger haha, makes sense.

So I tried to copy the single line but the last part with "mod CentaurRegionCount) +1" how did you get that extra part?
I'll post an attachment but I guess you already know what I'm asking about.

A big quest you sent me on haha
 

Attachments

  • uhhmod.png
    uhhmod.png
    17.4 KB · Views: 5
Level 28
Joined
Sep 26, 2009
Messages
2,540
The right side of the "Set CentaurTargetRegionIndex[Custom value of (Triggering unit)] = ..." is set as follows:
  1. "Arithmetic" - by default this should be something like "Value + 1". Leave the "+ 1" part as is, click the red "Value"
  2. "Math - Modulo" - by default this should be something like "Dividend mod Divisor"
    1. Click Divident and set there CentaurTargetRegionIndex[Custom value of (Triggering unit)]
    2. Click Divisor and set there CentaurRegionCount
 
Level 4
Joined
May 28, 2023
Messages
36
The right side of the "Set CentaurTargetRegionIndex[Custom value of (Triggering unit)] = ...
Woah Arithmetic and Math Modulo, never used these before.

Alright so the final trigger should look like this: (Maybe with a condition or two)

Thank you very much for your help, both you and Uncle :)
 

Attachments

  • centaurentersregionss.png
    centaurentersregionss.png
    11.3 KB · Views: 4
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
Uh so I encountered a strange behaviour from both the centaurs and another group of razomen from another simple trigger (in attachment)
Both groups seems to be moving towards the center of my map (a island) moving for 3 seconds, stops for 1 sec then moving again.

What would cause this? Both the centaurs and the razomen got specific regions assigned to their orders...
 

Attachments

  • pigpatrol.png
    pigpatrol.png
    17.1 KB · Views: 7

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
If SW Pig Patrol is near the center of the map then (Random point in SW Pig Patrol) should be working correctly. If a Point doesn't exist then it will default to the very center of the map.

The unit stuttering is due to a limitation associated with issuing orders to too many units owned by the same player (via triggers). The solution is to divide the units between different computer players so that they can "split the load". I found that ~60 units is a safe number for each cpu, but I think it depends on collision size (smaller collision allows for more units).

You can change the color/name of your Computer players so that they all look to be exactly the same. Then in your Create Unit triggers you simply change who you create each Unit for. If the units are preplaced then you could use a Loop at the start of the game that changes their owner:
  • Divide Computer Units
    • Events
      • Time - Elapsed game time is 0.01 seconds
    • Conditions
    • Actions
      • -------- Setup the computer players: --------
      • Set VariableSet CPU_Index = 1
      • Set VariableSet CPU[1] = Player 21 (Coal)
      • Set VariableSet CPU[2] = Player 22 (Snow)
      • Set VariableSet CPU[3] = Player 23 (Emerald)
      • Set VariableSet CPU[4] = Player 24 (Peanut)
      • -------- --------
      • -------- Change colors/names: --------
      • For each (Integer A) from 1 to 4, do (Actions)
        • Loop - Actions
          • Player - Change color of CPU[(Integer A)] to Brown, Changing color of existing units
          • Player - Set name of CPU[(Integer A)] to Enemy
      • -------- --------
      • -------- Change ownership of preplaced units: --------
      • Unit Group - Pick every unit in (Units owned by Player 21 (Coal).) and do (Actions)
        • Loop - Actions
          • Unit - Change ownership of (Picked unit) to CPU[CPU_Index] and Change color
          • Set VariableSet CPU_Counter = (CPU_Counter + 1)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • CPU_Counter Equal to 60
            • Then - Actions
              • Set VariableSet CPU_Counter = 0
              • Set VariableSet CPU_Index = (CPU_Index + 1)
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • CPU_Index Greater than 4
                • Then - Actions
                  • Set VariableSet CPU_Index = 1
                • Else - Actions
            • Else - Actions
Note that this design can change how your Events and other Triggers are handled. For example, "A unit owned by Player 21 dies" will only work for ONE of the four CPUs. Instead, you can rely on Generic events like "A unit dies" and in your Conditions check for something special about the unit that would let you know that it was owned by one of the four CPUs. There's many ways of "marking" the unit, I like to use hidden passive abilities based on Storm Hammers (it does nothing) and then give this to ALL of my units in the Object Editor that belong to the CPUs. Then in my conditions I can just check for this ability to determine that a Unit belongs to one of the four CPUs:
  • Conditions
    • (Level of CPU Classification for (Triggering unit)) Equal to 1
It's like a pseudo-classification system hence why I named the ability that. Alternatively, you can use the Unit Indexer method to mark these units which could serve useful if a Unit-Type could be owned by both a CPU and a User.
 

Attachments

  • Divide Units.w3m
    25.9 KB · Views: 6
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
If SW Pig Patrol is near the center of the map then (Random point in SW Pig Patrol) should be working correctly. If a Point doesn't exist then it will default to the...
Ah ok, the stuttering trick, I'll try to spread out the moving units to different ai colors then.

The region "SW Pig Patrol" is far to the south west of the map and I double checked it's still there.
Also Neutral Extra should not be able to use the patrol command so I'm very confused why they are moving at all, aswell as why the centaurs are not following the regions we previously setup!
 
Level 4
Joined
May 28, 2023
Messages
36
Neutral units have their own AI and leash ranges and mechanics built around them since they're intended to be creeps and what not. I would use Computers instead. Also, I updated my last post with more info.
I thought you were testing my new skills so I was creating the trigger from scratch.. But you posted the trigger in a map, how kind of you :)
I'll change the CPU's to 13-14-15 and 16 because I do not think I want to make this a 20 player map, even if this map is big!

Will spreading the creeps out to different CPU ai's help with the strange centaur and razoman moving towards the center thing?
 
Last edited:

Uncle

Warcraft Moderator
Level 71
Joined
Aug 10, 2018
Messages
7,520
I'd say the best move it to have the computers closer towards Player 24. You want room to add new users using the next Player up, for example, in your 12 player map users are Players 1-12, so if you add a new user you'd want them to be Player 13. This logic is nice since now you can take advantage of things like For Loops which loop from 1 to X (essentially looping over all of your Users if you follow my advise). Remember that each Player also has a Player Number (Red = 1, Blue = 2, Teal = 3, etc) so sticking with this design can serve useful.

Also, remember that you can change the color of a Player so if your decision for using a particular Player Slot is because of it's Color then I'd advise against it.

Spreading the creeps out will fix the stuttering. There's a lot of threads on here that discuss it.
 
Level 4
Joined
May 28, 2023
Messages
36
I'd say the best move it to have the computers closer towards Player 24...
Okay, you did not let me down so far so I'll take your advice and keep the divide unit trigger as it is. I read a bit about the unit stuttering and as you suggest using different ai users to spread out the units is a good idea.

A few questions:
Does this apply to neutral hostiles creep camps aswell?
The Centaurs is run by player 12, they only got 1-5 units on the map, so it can't be because they have too many units that cause this wierd behaviour?
The centaurs still run towards the center of the map for some reason...

I tried deleting most of my triggers, including the pig patrol and my respawn system - so now I only got the triggers we discussed here, some levers and other misc triggers who doesn't do anything to units (except gold mine and doodads) and creep camp spawner for neutral hostile.
The centaurs still move towards the center despite the regions we setup...

Edit: It spawns 2 centaurs even though I currently have it set to only spawn 1 every 30 seconds... it seems I must have made a mistake in the triggers or something.
 
Last edited:
Level 4
Joined
May 28, 2023
Messages
36
It sounds like you have some other triggers that are interfering, can you send me your map? You can use Pastebin and PM me the link if you're not comfortable with posting here.
I'll PM you, never know if there is any thieves here :D
 
Level 4
Joined
May 28, 2023
Messages
36
After much learning, I'm happy to announce everything works as it should. Took so long cuz I'm stupid haha

My map project is still a long way from completion. I will post the 'finished map' on this website for beta testing later.
 
Status
Not open for further replies.
Top