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

Don't blink out of specific region

Status
Not open for further replies.
Level 2
Joined
Aug 22, 2014
Messages
18
Hello guys. I've been making my own version of Angel Arena the Hell Arena and i wanted a little help with the blink skill. Is there a simple way to dissalow blink being cast on the outside of the arena (so that players won't roam outside) but without creating lots and lots of regions? The map also isn't in square shape so making a single region isn't possible. Thanks in advance! :)
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
So how do you define "inside" the arena? You have to transmit that definition into your realization. For example if you want to include those parts that are reachable by foot from a source point, you could find an algorithm for that to auto-generate the region. Or you could mark the unwanted areas by otherwise means than regions like blockers. Blink does not work on undiscovered terrain btw.
 
Level 2
Joined
Aug 22, 2014
Messages
18
By default in the map fog of war and black mask are removed. By inside the arena i mean there's a certain area which is not in a shape that would be easy to add a region for disabling blink outside of it. Also with pathing blocker i will have to add A LOT for it to work so it wouldn't be very good. All the heroes are marked as walking on foot so there are not flying heroes/minions.
 
Level 15
Joined
Oct 29, 2012
Messages
1,474
Hmmm, first it's impossible to do it without triggers. So you have to trigger like any blink spell ( You can find ones in Hive I guess )
Instead of creating regions, replace them with a specific tile which is outside the arena a,d this tile isn't used inside... So in the blink spell trigger, when the target point is stored, you use condition (tile type in (Target Point) Equal to Rough Dirt)... if yes, the blink is deactivated and the next spell triggers won't run.
 
Level 2
Joined
Aug 22, 2014
Messages
18
Thanks again for helping me out johnysone! This trigger works exactly as i want it only with one problem. The outise of the arena is a cliff and if you blink at the edge it won't stop the hero from blinking. I can't find cliff type or something like that in the conditions. Your help would be appreciated yet again! ^^
Also thanks everyone for your responses but johnysone's seems to work more the way i want it to! :)
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
Sigh WC3's GUI claims another victim with its stupidity and uselessness. Why they made GUI so useless is beyond me.

What GUI calls "Regions" are actually of type "rect". The type "region" is completely hidden from you. Unlike rects, regions are a collection of map cells so can assume any shape such as being filled from multiple rects or even with areas of the map filled in a circular manner (still limited to the granularity of a map cell).

What you can do is...
1. Fill a region with big rects of the area you do not want to blink to using
JASS:
native RegionAddRect takes region whichRegion,rect r returns nothing
2. Remove cut-out rects from the region using
JASS:
native RegionClearRect takes region whichRegion,rect r returns nothing
3. Test if a point is in the region using
JASS:
native IsLocationInRegion takes region whichRegion,location whichLocation returns boolean
or
JASS:
native IsPointInRegion takes region whichRegion,real x,real y returns boolean
 
Level 15
Joined
Oct 29, 2012
Messages
1,474
You would rather detect the target place of the normal blink since it's not bugged.
  • Events
    • Unit - A Unit starts the effect of an ability
  • Conditions
    • (Ability Being Cast) Equal To (Blink)
  • Actions
    • Blinker = (Triggering Unit)
    • BlinkCasterPoint = ( Position of Blinker )
    • BlinkTarget = (Target Point of Ability Being Cast)
    • If/Then/Else Multiple Actions
      • Conditions
        • (Tile type in BlinkTarget Equal To Rough Dirt) Equal to True
      • Then
        • Unit - Order Blinker to Stop
        • Unit - Move Blinker to BlinkCasterPoint instantly
      • Else
    • Custom script: call RemoveLocation(udg_BlinkCasterPoint)
    • Custom script: call RemoveLocation(udg_BlinkTarget)
 
Level 2
Joined
Aug 22, 2014
Messages
18
Sigh WC3's GUI claims another victim with its stupidity and uselessness. Why they made GUI so useless is beyond me.

What GUI calls "Regions" are actually of type "rect". The type "region" is completely hidden from you. Unlike rects, regions are a collection of map cells so can assume any shape such as being filled from multiple rects or even with areas of the map filled in a circular manner (still limited to the granularity of a map cell).

What you can do is...
1. Fill a region with big rects of the area you do not want to blink to using
JASS:
native RegionAddRect takes region whichRegion,rect r returns nothing
2. Remove cut-out rects from the region using
JASS:
native RegionClearRect takes region whichRegion,rect r returns nothing
3. Test if a point is in the region using
JASS:
native IsLocationInRegion takes region whichRegion,location whichLocation returns boolean
or
JASS:
native IsPointInRegion takes region whichRegion,real x,real y returns boolean

I have never used JASS so it would be very hard for me to use it.
What i mean about blinking at the edge is that the edge of the cliff is not considered as rough dirt so the hero can blink there freely and then keep moving. When searching for terrain type there are also cliff types but the "Manmade Walls" as displayed in terrain editor isn't there. I'm using the dungeon terrain set.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
@johny: It will, but it won't impact performance that much, it doesn't need tons of rects anyway, I think about 16+ is needed and the region.
 
Level 2
Joined
Aug 22, 2014
Messages
18
Around eight terrain editor regions could do. Note that you can add multiple region events to the same trigger.

Eight terrain regions? The way i see it it looks like it will need a lot more than that that's why i asked if there was an easier way to do it with a trigger. The trigger for not allowing blink to the specific tile type works very well the way i want it because it also prevents blinking on the outside of some other areas. My only problem is that you can blink at the edge of the cliff and then keep moving normaly.
 
Level 15
Joined
Oct 29, 2012
Messages
1,474
Eight terrain regions? The way i see it it looks like it will need a lot more than that that's why i asked if there was an easier way to do it with a trigger. The trigger for not allowing blink to the specific tile type works very well the way i want it because it also prevents blinking on the outside of some other areas. My only problem is that you can blink at the edge of the cliff and then keep moving normally.


Yeah I saw this problem since the blink can target edges of cliffs. Try this below all blink ability triggers , this might move him off the cliff (Remove leaks too)
  • Unit - Move (Triggering Unit) to ((Position of (Triggering Unit) offset by 50 towards (180 + (Facing Of (Triggering Unit))))
 
Level 2
Joined
Aug 22, 2014
Messages
18
Yeah I saw this problem since the blink can target edges of cliffs. Try this below all blink ability triggers , this might move him off the cliff (Remove leaks too)
  • Unit - Move (Triggering Unit) to ((Position of (Triggering Unit) offset by 50 towards (180 + (Facing Of (Triggering Unit))))

Hmmm I can't find the move unit with offset. Isn't it the move unit (instantly)?
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
That won't help at all. Not only it doesn't even accurately teleport the unit to the selected point. All the player actually has to do is aim 50 range further than previously and the problem will still prevail.

You will actually need 11 or 12 regions (better called rects) to cover the area you outlined in your pic. Nobody said they can't cross one another.

Also I still don't understand why don't you use standard Blink ability and only check when its order is given if the target point is out of arena or not (once you're done with the regions anyway) - it will actually shorten the code jonhy posted and make more sense as the unit will be stopped immediately instead of going in range for blinking and then getting stopped.
 
Level 2
Joined
Aug 22, 2014
Messages
18
That won't help at all. Not only it doesn't even accurately teleport the unit to the selected point. All the player actually has to do is aim 50 range further than previously and the problem will still prevail.

You will actually need 11 or 12 regions (better called rects) to cover the area you outlined in your pic. Nobody said they can't cross one another.

Also I still don't understand why don't you use standard Blink ability and only check when its order is given if the target point is out of arena or not (once you're done with the regions anyway) - it will actually shorten the code jonhy posted and make more sense as the unit will be stopped immediately instead of going in range for blinking and then getting stopped.

11-12? Maybe i want to be more precise and that's why i think it will take up lots more. I will try it out and let you know. Also this might be a dump question but the regions should go on the outside right? Or is there a way to not allow a skill from being cast if the unit is targeting outside of some specified regions?
 
Last edited:
Level 26
Joined
Aug 18, 2009
Messages
4,097
The unit can always snap out of the arena if the next free space to walk on is there. Commonly you would stuff a lot of units in the corner and then aim at a point close to the border. Which is why it is better to actually catch the leaving of the playfield or block the pathing outside.

As I said before, it's fairly easy to write a simple fill algorithm, the issue would more be speed.

JASS:
scope fillReg initializer init
    globals
        private real minX
        private real maxX
        private real minY
        private real maxY
        private trigger fill_child_trig
        //resolution, smallest cell a region can have is 32, but that would result in many more iterations, 128 is terrain node size
        private constant real dist = 128
        //heavy iterations can easily break the op limit
        private constant integer maxIterationsPerThread = 2000
        private rect rec
        private hashtable xTable
        private hashtable yTable
        //private hashtable checkedTable
        
        private real array xStack
        private real array yStack
        
        private integer stackDepth = -1
        
        private region reg
    endglobals

    private function push takes real x, real y returns nothing
        set stackDepth = stackDepth + 1
        
        //may easily stackDepth > 8k
        call SaveReal(xTable, 0, stackDepth, x)
        call SaveReal(yTable, 0, stackDepth, y)
    endfunction

    private function add takes real x, real y returns nothing        
        if x < minX then
            return
        endif
        if x > maxX then
            return
        endif
        if y < minY then
            return
        endif
        if y > maxY then
            return
        endif
        
        //may be faster via hashtable
        //if LoadBoolean(checkedTable, R2I(x), R2I(y)) then
        //    return
        //endif
        if IsPointInRegion(reg, x, y) then
            return
        endif
        
        //actual condition for neighboring cells
        if GetTerrainCliffLevel(x, y) > 2 then
            return
        endif
        
        //call SaveBoolean(checkedTable, R2I(x), R2I(y), true)
        call SetRect(rec, x, y, x + dist - 32, y + dist - 32)
        
        call RegionAddRect(reg, rec)

        call push(x - dist, y)
        call push(x + dist, y)
        call push(x, y - dist)
        call push(x, y + dist)
    endfunction

    private function fill_child takes nothing returns nothing
        local integer c = 0
        local real x
        local real y
        
        loop
            exitwhen (c > maxIterationsPerThread)
            exitwhen (stackDepth < 0)
            
            set c = c + 1
            
            set x = LoadReal(xTable, 0, stackDepth)
            set y = LoadReal(yTable, 0, stackDepth)
            
            set stackDepth = stackDepth - 1
            
            call add(x, y)
        endloop
    endfunction

    public function fill takes region targetReg, real x, real y returns nothing    
        set x = R2I(x) / dist * dist
        set y = R2I(y) / dist * dist
        
        set reg = targetReg

        call push(x, y)
        
        loop
            exitwhen (stackDepth < 0)
            
            call TriggerEvaluate(fill_child_trig)
        endloop
    endfunction

    private function init takes nothing returns nothing
        local rect world = GetWorldBounds()
        
        set minX = GetRectMinX(world)
        set maxX = GetRectMaxX(world) - dist
        set minY = GetRectMinY(world)
        set maxY = GetRectMaxY(world) - dist
        
        set fill_child_trig = CreateTrigger()
        call TriggerAddCondition(fill_child_trig, function fill_child)
        
        set rec = Rect(0, 0, 0, 0)
        
        set xTable = InitHashtable()
        set yTable = InitHashtable()
        //set checkedTable = InitHashtable()
    endfunction
endscope

function start takes nothing returns nothing
    local region targetReg = CreateRegion()
    local rect sourceRect = gg_rct_sourceRect

    call fillReg_fill(targetReg, sourceRect)
endfunction
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
11-12? Maybe i want to be more precise and that's why i think it will take up lots more. I will try it out and let you know.
At the bottom of this post I attached the same pic you uploaded in one of your earlier posts here, but I also draw rects needed that fill the area you outlined in your pic. As you can see, there's really only 12 rects that fill the whole area. Of course, if you want to add other areas, it will be more than 12 rects.

Also this might be a dump question but the regions should go on the outside right? Or is there a way to not allow a skill from being cast if the unit is targeting outside of some specified regions?
They can go on the outside, but better is if they go in the inside.
What Dr. Super Good posted is probably the best solution as it will shorten your code and will be efficient, but if you don't want to use jass, then there's different approach.

See, your idea can basically be summarized into this: "If target point is in any of the following rects (= gui regions outside arena), then stop blink".
My idea is the inverse of yours: "If target point is in none of the following rects (= gui regions inside arena), then stop blink."

My approach requires 2 triggers.

First trigger
In first trigger you set every region of the arena into region array. This trigger fires only upon map initialization:

  • Map Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set Region_array[1] = Arena Region 01 <gen>
      • Set Region_array[2] = Arena Region 02 <gen>
      • Set Region_array[3] = Arena Region 03 <gen>
      • ... and so on...
Second trigger
Second trigger sets boolean value to false. This boolean value represents the statement "Target point is in arena". Now you loop through the region array and check if target point is in region. If yes, you set boolean to true, else do nothing.
After loop you check the boolean value. If it returns 'true', then the point is in at least 1 region. If 'false', it's in none of the regions, so it is safe to assume it is outside arena.

  • Blink Check
    • Events
      • Unit - A unit Is issued an order targeting a point
    • Conditions
      • (Issued order) Equal to (Order(blink))
    • Actions
      • Set TargetPoint = (Target point of issued order)
      • Set InsideArena_bool = False
      • For each (Integer loop_int) from 1 to *the highest index of the region array*, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Region_array[loop_int] contains TargetPoint) Equal to True
            • Then - Actions
              • Set InsideArena_bool = True
            • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • InsideArena_bool Equal to False
        • Then - Actions
          • Unit - Order (Triggering unit) to Stop
          • Game - Display to (All players) the text: Error! Outside Arena
        • Else - Actions
      • Custom script: call RemoveLocation(udg_TargetPoint)
      • Custom script: set udg_TargetPoint = null
 

Attachments

  • Regions.jpg
    Regions.jpg
    388.8 KB · Views: 59
Level 2
Joined
Aug 22, 2014
Messages
18
At the bottom of this post I attached the same pic you uploaded in one of your earlier posts here, but I also draw rects needed that fill the area you outlined in your pic. As you can see, there's really only 12 rects that fill the whole area. Of course, if you want to add other areas, it will be more than 12 rects.


They can go on the outside, but better is if they go in the inside.
What Dr. Super Good posted is probably the best solution as it will shorten your code and will be efficient, but if you don't want to use jass, then there's different approach.

See, your idea can basically be summarized into this: "If target point is in any of the following rects (= gui regions outside arena), then stop blink".
My idea is the inverse of yours: "If target point is in none of the following rects (= gui regions inside arena), then stop blink."

My approach requires 2 triggers.

First trigger
In first trigger you set every region of the arena into region array. This trigger fires only upon map initialization:

  • Map Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set Region_array[1] = Arena Region 01 <gen>
      • Set Region_array[2] = Arena Region 02 <gen>
      • Set Region_array[3] = Arena Region 03 <gen>
      • ... and so on...
Second trigger
Second trigger sets boolean value to false. This boolean value represents the statement "Target point is in arena". Now you loop through the region array and check if target point is in region. If yes, you set boolean to true, else do nothing.
After loop you check the boolean value. If it returns 'true', then the point is in at least 1 region. If 'false', it's in none of the regions, so it is safe to assume it is outside arena.

  • Blink Check
    • Events
      • Unit - A unit Is issued an order targeting a point
    • Conditions
      • (Issued order) Equal to (Order(blink))
    • Actions
      • Set TargetPoint = (Target point of issued order)
      • Set InsideArena_bool = False
      • For each (Integer loop_int) from 1 to *the highest index of the region array*, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Region_array[loop_int] contains TargetPoint) Equal to True
            • Then - Actions
              • Set InsideArena_bool = True
            • Else - Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • InsideArena_bool Equal to False
        • Then - Actions
          • Unit - Order (Triggering unit) to Stop
          • Game - Display to (All players) the text: Error! Outside Arena
        • Else - Actions
      • Custom script: call RemoveLocation(udg_TargetPoint)
      • Custom script: set udg_TargetPoint = null

This looks like exactly what i want. One question though, i'm not sure how to add this trigger function
  • (Region_array[loop_int] contains TargetPoint) Equal to True
And one more question, this will affect units that are outside of arena only if they cast blink right? Because there are some other regions you get through portals and i don't want the heroes to be considered outside if they go there as well.
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
What I posted only checks where the targeted point is, not where the caster is. Theoretically the caster could teleport from outside area into arena through wall and it would work ok, since the target point is in arena (the actual question would be: how did the caster get outside arena in the first place).

The condition is a Boolean comparison: Region - Region contains point.
It requires region variable/array and a point variable/array.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
I have never used JASS so it would be very hard for me to use it.
What i mean about blinking at the edge is that the edge of the cliff is not considered as rough dirt so the hero can blink there freely and then keep moving. When searching for terrain type there are also cliff types but the "Manmade Walls" as displayed in terrain editor isn't there. I'm using the dungeon terrain set.

Jass is not hard at all. Have you ever used custom script to remove leaks ? If you have then you have already used jass.
 
Level 12
Joined
May 20, 2009
Messages
822
If I remember correctly, the WC3 Trigger Editor can create regions with as many points as you want and in almost any shape.

Or maybe that was JASS. But I'm pretty sure that's still possible.

Basically, you just put points down and then I think there's a function that lets you make 4 or more points into a region.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
If I remember correctly, the WC3 Trigger Editor can create regions with as many points as you want and in almost any shape.

Or maybe that was JASS. But I'm pretty sure that's still possible.

Basically, you just put points down and then I think there's a function that lets you make 4 or more points into a region.
That is not WC3. SC2 allows you to make regions out of many primitive shapes however even that does not have fully free corner polygon based regions.
 
Status
Not open for further replies.
Top