• 🏆 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!

Setting a spawn area.

Status
Not open for further replies.
Level 12
Joined
Dec 2, 2016
Messages
733
For the map I'm working on.

I've got a shop that spawns units.

I've set up 4 different spawn areas around the map. And using a hero I want the hero to have an ability that when selected if you press that ability on the spawn area it will set the spawn location of the shop.

But I don't just want it to be that you have to exactly select that specific spawn area, I'd like to have a regions system. That if you pressed the ability anywhere on the map it would chose the closest spawn area.

How would I go about doing this?
Thanks.
 
Level 13
Joined
May 10, 2009
Messages
868
First, you need a variable that stores each region; assign each region to an array when your map initializes. Then, every time a unit casts that spell, you store its targeted point.
Now compare which region is closer to the targeted point by looping through all regions, and checking the distance between that Targeted Point and the center of each region. You also need a REAL, which should be set to 99999 on top of the LOOP. Then you check if the distance between the current region in the loop and targeted point is closer (less) than the REAL variable. If yes, then you modify that REAL variable to that distance, and assign the current region to your "Spawn Location" variable.

So, if the next region is farther than the previous one, the condition won't allow the current distance to be assigned to the REAL variable.

How many times have I written "REAL"?
REAL REAL REAL REAL REAL LOL
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
BloodSoul's linear minimum search approach is the simplest and most recommended approach. Even for 100 points it will still work well.

A more complex but efficient approach would be to use a quad tree. This would allow one to only test reasonably close points to find the nearest. However I would only recommend this for a lot of points (hundreds, thousands).
What ability or spell can act as this though?
Channel? That is the usual dummy ability as far as I can tell.
And how to do you compare magnitude?
If then else statement with the comparison as a condition.
 
Level 12
Joined
Dec 2, 2016
Messages
733
I tried the channel ability, I added it to my hero but doesn't seem to have any effect. No where in the hero's box does it show an ability to be casted.

Also, when you use the event spell casted. Where do I find the target point of that? I can't seem to find that. Thanks.
 
Level 12
Joined
Dec 2, 2016
Messages
733
Look at most triggered abilities in the spell section, they use dummy abilities and cast events. Many are point targeted.
What do you mean by "most triggered abilities" I can't seem to find that section.


This is all that I've come up with.


Gyazo - ea56eb028f4390133a7d69b47ccee19b.png

I can't seem to find an action that can store the targeted point as the variable.
 
Last edited:
Level 12
Joined
Dec 2, 2016
Messages
733
  • Melee Initialization
    • Events
      • Unit - A unit Finishes casting an ability
    • Conditions
    • Actions
      • Set RealX = (X of (Target point of ability being cast))
      • Set RealY = (Y of (Target point of ability being cast))
      • Unit - Create 1 Footman for Player 1 (Red) at ((Point(RealX, RealY)) offset by (0.00, 0.00)) facing Default building facing degrees

^ This is what I'm testing. When I use the chain lighting ability. It doesn't spawn a footman though.
 
Level 13
Joined
May 10, 2009
Messages
868
That's not the best event for what you're trying to do, because your unit really needs to finish casting the spell completely (the green border around the spell icon must go away). The best event for that is "Unit - A unit Starts the effect of an ability" as it fires the trigger/actions as soon as the spell goes on cooldown, but the unit mana is about to be subtracted. Even if the player hits STOP button, it won't be prevented from running.

EDIT: Also, you are skipping a few steps. For example, don't forget such event runs for EVERY spell cast. You don't want to see a bunch of footmen being created all over your map.

A certain condition will help you out with that when you tell it to only allow to run the actions if a certain spell is cast, that is:

  • Events
    • Unit - A unit Starts the effect of an ability
  • Conditions
    • (Ability being cast) Equal to Chain Lightning
EDIT 2: Changed the event above from "Finished" to "Starts the effect..." - I didn't even notice.
 
Last edited:
Level 12
Joined
Dec 2, 2016
Messages
733
Which spell can I use that doesn't have any visual effects?
I just need someone that will activate the target point event.

I created a few regions, how do I when I use the spell on a certain region. What action do I use to store that specific region in my variable?
 
Last edited:
Level 12
Joined
Dec 2, 2016
Messages
733
Use starts effect of ability and not finishes casting.
I already am thanks. But my new question is.

"
Which spell can I use that doesn't have any visual effects?
I just need someone that will activate the target point event.

I created a few regions, how do I when I use the spell on a certain region. What action do I use to store that specific region in my variable?
"
 
Level 11
Joined
Jun 2, 2004
Messages
849
Which spell can I use that doesn't have any visual effects?
Channel.

I created a few regions, how do I when I use the spell on a certain region. What action do I use to store that specific region in my variable?
Well, there could be multiple regions in the same spot. You should probably loop through all the relevant regions and use the first one that contains the target point of ability being cast.
 
Level 12
Joined
Dec 2, 2016
Messages
733
Channel.


Well, there could be multiple regions in the same spot. You should probably loop through all the relevant regions and use the first one that contains the target point of ability being cast.
I already tried using "channel" I put it as an ability in my hero. And in game, the ability doesn't show up for my hero. I have no way of casting it.


I've got a total of 5 regions. How can I loop through all the regions? And if I loop through them, how would I detect if it's the target point of the ability?
 
Level 13
Joined
May 10, 2009
Messages
868
Channel might seem to be a little bit tricky, because you have to config it properly prior to using it. Here's what you have to do:

- After creating an ability based on Channel, define how many levels and whether a hero or unit will use it. In this case, I bet you're trying to use a normal unit ability = 1 Level, it's not learned;

- All right, Will you use all of those predefined special effects in its fields? Choose the ones you want, or remove all of them. Don't forget to change the "Art - X/Y Button Position".

- The thing that matters the most for Channel based abilities: Choose if it targets or not a point or unit. Also, make sure you are making the spell visible for the unit: Set the field "Data - Options" to "Visible".

- Channel offers the option to pause the caster while it is being cast, but I don't think you want that thing enabled - set it to false ("Disable Other Abilities").

- Data - Base Order ID: This one is a VERY important thing to notice. Avoid having a unit with more than one channel based spells with the SAME order id. Otherwise, the unit might not cast the correct spell when ordered to do so. Choose any other string order, like: Carrion Swarm, Shockwave, MindRot, Acid Bomb, etc.

- Art - Follow Through Time: After a unit casts it, they will stay there as if they were "channeling" the spell. If "Disable Other Abilities" field is enabled, then your unit will be paused until that time expires.

- The rest is up to you: Cast Range, Cooldown, Mana Cost, Spell Name, Etc.


Regarding the triggers and regions.

Here's my example: 3 Regions

Untitled-2.png


The Triggers:
  • Register your rects
    • Events
      • Time - Elapsed game time is 0.00 seconds
    • Conditions
    • Actions
      • Set Spawn_Regions[0] = Spawn A <gen>
      • Set Spawn_Regions[1] = Spawn B <gen>
      • Set Spawn_Regions[2] = Spawn C <gen>
      • -------- For looping through 0 to 2 later. --------
      • Set Spawn_NumberOfRegions = 2
  • Casting Channel
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to My Channel Spell
    • Actions
      • Set LinearSearch_Max = 99999.00
      • For each (Integer tmp_integer) from 0 to Spawn_NumberOfRegions, do (Actions)
        • Loop - Actions
          • Set tmp_point[0] = (Target point of ability being cast)
          • Set tmp_point[1] = (Center of Spawn_Regions[tmp_integer])
          • Set tmp_real = (Distance between tmp_point[0] and tmp_point[1])
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • tmp_real Less than LinearSearch_Max
            • Then - Actions
              • Set LinearSearch_Max = tmp_real
              • Set THE_CHOSEN_ONE = Spawn_Regions[tmp_integer]
            • Else - Actions
          • Custom script: call RemoveLocation(udg_tmp_point[0])
          • Custom script: call RemoveLocation(udg_tmp_point[1])
      • -------- All right, after checking ALL regions and comparing the distance between TARGET POINT and THEIR CENTER. We now have our result, the variable THE CHOSEN ONE keeps the closest region. --------
      • -------- Now, do your stuff with it --------
      • Set tmp_point[0] = (Center of THE_CHOSEN_ONE)
      • Special Effect - Create a special effect at tmp_point[0] using Abilities\Spells\Human\ThunderClap\ThunderClapCaster.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: call RemoveLocation(udg_tmp_point[0])
 

Attachments

  • Linear Minimum Search.w3x
    18.5 KB · Views: 38
Level 12
Joined
Dec 2, 2016
Messages
733
Hey is there a way to make a variable local?
Like I'm pretty sure that I have to create 12 different variables for each possible player that is setting their own spawn portal. Or is there a way to make the variable local to each client? Like the variable isn't global and runs as a different thing for each player?

Does that make sense^
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
Hey is there a way to make a variable local?
Not in GUI. One can write JASS directly to be able to declare local variables.
Like I'm pretty sure that I have to create 12 different variables for each possible player that is setting their own spawn portal. Or is there a way to make the variable local to each client? Like the variable isn't global and runs as a different thing for each player?
That is not a local variable...

What you want is an array where the index is the player slot number. For example player 1 red will map to index 0 (1 in GUI) and player 2 blue to 1 (2 in GUI) etc. This guarantees each player a unique storage location, effectively a unique variable.
 
Level 12
Joined
Dec 2, 2016
Messages
733
Not in GUI. One can write JASS directly to be able to declare local variables.That is not a local variable...

What you want is an array where the index is the player slot number. For example player 1 red will map to index 0 (1 in GUI) and player 2 blue to 1 (2 in GUI) etc. This guarantees each player a unique storage location, effectively a unique variable.
Sorry what I meant is a local script I guess, something that runs independently for each client. But alright I'll do that.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
Anything that runs independently between clients will cause the clients to go out of sync if it alters game state.

To run script independently for a client use GetLocalPlayer native which returns the player corresponding to the client which executes it, so is a different player value when run by each client. Be warned that it is easy to cause out of sync errors when using that native due to it allowing code to be run only for a single client. Anything that alters the game state will cause an out of sync when not run on all clients.
 
Level 12
Joined
Dec 2, 2016
Messages
733
So I'm trying to make the chosen one variable an array. I want to have an if statement that checks if triggering unit is equal to player1(red), player2(blue) etc.

I get this far


Gyazo - 329f02361a3254b20e4d8c3b2aca5e4b.png

if Owner of Triggering unit Equal to Player(Red) then Set The_Chosen_One[1] = Value

I cannot set the vault to the destination point being the tmp_integer

How do I go about this if I cannot store integers in a region array.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,188
that checks if triggering unit is equal to player1(red), player2(blue) etc.
Not possible. A unit is not a player so they will logically never be equal even if the statement would not out right throw a syntax error due to type mismatch.
if Owner of Triggering unit Equal to Player(Red) then Set The_Chosen_One[1] = Value
I do not see a reason to use an array in such a case. One generally only uses an array if the index is itself variable. Eg mapping a value to a player where the index is the player slot number.
I cannot set the vault to the destination point being the tmp_integer

How do I go about this if I cannot store integers in a region array.
A region (JASS rect) is not an integer. One can only store region handles into a region array. Maybe you mean to use tmp_integer as the index into the region array to get a region from?
 
Level 12
Joined
Dec 2, 2016
Messages
733
Not possible. A unit is not a player so they will logically never be equal even if the statement would not out right throw a syntax error due to type mismatch.I do not see a reason to use an array in such a case. One generally only uses an array if the index is itself variable. Eg mapping a value to a player where the index is the player slot number.A region (JASS rect) is not an integer. One can only store region handles into a region array. Maybe you mean to use tmp_integer as the index into the region array to get a region from?


Okay, this would work right?

Gyazo - 861ffb55752c16d51b67444b91bd4217.png

I haven't tested it, but I'll create 12 different if statements checking the color, and if that color set The_Chosen_One's specific index to the chosen region.
 
Level 12
Joined
Dec 2, 2016
Messages
733
I'm checking if the triggering player is a specific colour and then setting the corrosponding chosen one array variable to the chosen region.

Like if player red is triggering unit owner chosen one[1] = the chosen region.

If player blue is triggering unit, chosen one[2] = the chosen region.

Does that make sense or?
 
Level 13
Joined
May 10, 2009
Messages
868
You don't need to spam if statements in order to find out who tried to select a new region.

First, you need to rename that "Chosen_One" variable to a proper name, and make it an array. Then, use the GetPlayerNumber function in your favor, so you can assign the value to the correct index.

For example, I renamed it to "Player_CurrentSpawnArea", then:

  • Selecting closest rect
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to My Channel Spell
    • Actions
      • Set tmp_point[0] = (Target point of ability being cast)
      • Set LinearSearch_Max = 99999.00
      • For each (Integer tmp_integer) from 0 to Spawn_NumberOfRegions, do (Actions)
        • Loop - Actions
          • Set tmp_point[1] = (Center of Spawn_Regions[tmp_integer])
          • -------- The distance between TARGET POINT and the current REGION --------
          • Set tmp_real = (Distance between tmp_point[0] and tmp_point[1])
          • -------- Check if the distance is smaller than the LinearSearch_Max variable. If so, choose the current region for now, and modify the variable to the current distance too. --------
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • tmp_real Less than LinearSearch_Max
            • Then - Actions
              • -------- If any other region is closer to the TARGET POINT, then this part will be redefined. Otherwise, this is the closest region --------
              • Set LinearSearch_Max = tmp_real
              • Set tmp_region = Spawn_Regions[tmp_integer]
            • Else - Actions
          • Custom script: call RemoveLocation(udg_tmp_point[1])
      • Custom script: call RemoveLocation(udg_tmp_point[0])
      • Set Player_CurrentSpawnArea[(Player number of (Triggering player))] = tmp_region
If player 1 (red) casts that spell the (Player number of (Triggering player)) will return 1, which is the same as Set Player_CurrentSpawnArea[1] = value; The same for the others: Player 2? (Player number of (Triggering player)) = 2, etc...

NOTES:
- Player_CurrentSpawnArea has no initial value. You have to assign a region to each index. Otherwise, units will spawn in the middle of the map until the player selects a new region.
- I've made some changes related to the code as it was overdoing a few things, like resetting "tmp_point[0]" in the loop, which was needless.
 

Attachments

  • Linear Minimum Search.w3x
    18 KB · Views: 47
Last edited:
Level 12
Joined
Dec 2, 2016
Messages
733
Thank you, when I try to create a unit at the coordinates of " Player_CurrentSpawnArea"

It does not allow me to set a region as the position, I can only do it with a point array. Is there a way to convert the variable to a readable position ^ or should I just make it a point array instead.
 
Level 13
Joined
May 10, 2009
Messages
868
You can use a temporary point variable and get the center of a region (jass rect), or even its random position within it (if that's somehow useful). However, it's up to you - you can convert it to a point data type if you feel like.
 
Status
Not open for further replies.
Top