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

Help with damage dealing blink

Status
Not open for further replies.
Level 9
Joined
Jun 10, 2013
Messages
473
Hey >:D happy new years eve ! and can any one help me trigger a spell based on blink which teleports the hero to pointA and deals X damage to all enemy units around pointA while dealing half the damage to units in a line from the hero's starting position to pointA and once the hero reaches pointA she will simultaneously get permanent invisibility while the previously mention damage once reaching pointA is carried out.

The exact description of the ability is below:

Woodland Magic:
The Avenger uses woodland magic to transform her self into a burst of thorns and leaves headed towards the target destination; dealing damage to all units around her while dealing half the damage to units along the way from her initial position as well as turning invisible for 30 seconds once reaching her destination.

level 1: 100 damage
level 2: 150 damage
level 3: 200 damage

I know i'd probably base it off of blink and once reaching her destination i'd trigger her getting permanent invisibility then wait 30 seconds and remove it and for the final destination damage i'd trigger some AOE damage ability to be casted how ever I've got know clue how to trigger the half damage to units in a line form her initial starting position to her destination nor do I got a great Idea on hoe to tie it all together in a trigger ?_? so any help would be appreciated, plus I am making a thread in the forums just so others who may one day want an ability like this would know how.
 
Last edited:
Level 12
Joined
May 22, 2015
Messages
1,051
Maybe sort of a separate question for anyone who reads this, is there a simple / good way to find all units that are in a path? It would basically be like shockwave except you take all the units it would hit if it moved instantly to the end and add them to a unit group. This would be tremendously useful for this kind of effect.

You could maybe spawn a dummy unit that cast carrion swarm along the path that you blink in. The problem is that it would always go the whole distance. The most robust solution is to use math to find out which units should be hit, but that is a bit tough.

I would do the bonus damage at the end by doing an additional chunk of half damage from another spell (thunderclap maybe) or trigger if you do the damage with triggers (probably best in the long run).

The cleanest solution is to find all the units that will get hit (kind of hard to do and I think it is an expensive calculation) and put them into a unit group. Then loop through the units and if they are a certain distance from the end point, do the full damage, otherwise, do the half damage.

I think your ideas for the rest will be fine.
 
Level 9
Joined
Jun 10, 2013
Messages
473
Maybe sort of a separate question for anyone who reads this, is there a simple / good way to find all units that are in a path? It would basically be like shockwave except you take all the units it would hit if it moved instantly to the end and add them to a unit group. This would be tremendously useful for this kind of effect.

The cleanest solution is to find all the units that will get hit (kind of hard to do and I think it is an expensive calculation) and put them into a unit group. Then loop through the units and if they are a certain distance from the end point, do the full damage, otherwise, do the half damage.

Well I hope some one can answer that :S other wise i'm willing to give the calculations a shot >:D
 
Level 9
Joined
Jun 10, 2013
Messages
473
wait I have a problem the distance between blink and shockwave can't be synced so if she teleports 200ft the shockwave's damage dealing distance will still be 600ft or what ever you set it, therefore they'll never really work how there supposed to unless there's a way to trigger the distance of the shockwave to what ever the distance of the blink is

note I have the JNGP but have no idea how to learn but if required and given guidance I gladly would how ever as a last resort
 
Last edited:
Level 9
Joined
Jun 10, 2013
Messages
473
Can't some thing be done similar to this http://www.hiveworkshop.com/forums/...-line-between-blink-start-destination-213321/
but instead of healing it would deal damage?

EDIT// alright I've got it to work by doing this

JASS:
//! zinc
library DamageBlink {
     constant integer ABILITY ='A01L';
     constant real SQUARE_WIDTH = 5625.;//75^2
     constant real DAMAGE = 150.;
     constant group G = CreateGroup();

     function onInit() {
         trigger trig = CreateTrigger();
         integer i = 0;
         do {
             TriggerRegisterPlayerUnitEvent(trig, Player(i),
                 EVENT_PLAYER_UNIT_SPELL_EFFECT, null);
             i += 1;
         } while (i < 16);
         TriggerAddCondition(trig,
             function() -> boolean {
                 return GetSpellAbilityId() == ABILITY;
             }
         );
         TriggerAddAction(trig,
             function() {
                 unit u = GetTriggerUnit(), u2;
                 player p = GetOwningPlayer(u);
                 real x = GetWidgetX(u), y = GetWidgetY(u),
                     tx = GetSpellTargetX(), ty = GetSpellTargetY(),
                     k = (y - ty) / (x - tx), b = y - k * x,
                     k1 = -1. / k, b1;
                 GroupEnumUnitsInRange(G, (x + tx) * .5, (y + ty) * .5,
                     SquareRoot((x - tx) * (x - tx) + (y - ty) * (y - ty)) * .5, null);
                 while (true) {
                     u2 = FirstOfGroup(G);
                     if (u2 == null) { break; }
                     GroupRemoveUnit(G, u2);
                     if (IsUnitEnemy(u2, p)) {
                         tx = GetWidgetX(u2);
                         ty = GetWidgetY(u2);
                         b1 = ty - k1 * tx;
                         x = (b1 - b) / (k - k1);
                         y = k * x + b;
                         if ((x - tx) * (x - tx) + (y - ty) * (y - ty) <= SQUARE_WIDTH) {
                             SetWidgetLife(u2, GetWidgetLife(u2) - DAMAGE);
                         }
                     }
                 }
                 u = null; p = null;
             }
         );
         trig = null;
     }
}
//! endzinc

how ever I don't know how to make the damage differ per level for example when 'A01L' is at level 1 damage should equal to 50 and increase by 50 each time the ability is leveled up (L1 - 50, L2 - 100, L3 150)
 
Last edited:
Level 9
Joined
Jun 10, 2013
Messages
473
DAMAGE should be 50.

Multiply DAMAGE by return value of GetUnitAbilityLevel.

Use UnitDamageTarget instead of SetWidgetLife.

Thanks a billion for responding and although I know how to do with the other points i'm very new to vjass (started it an hour ago) and so I don't really know where to add new things just edit simple things like changing the above trigger to deal damage instead of heal.

Also get this error when changing SetWidgetLife

Screenshot (268).png

and HAPPY NEW YEAR XD
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
I say do not use multiple languages unless it is necessary... and because everything is translated into JASS, neither C nor vJASS have anything that cannot be done in JASS itself. (except global variables)

SetWidgetLife is a bad way of dealing damage.
Dead units may not be damaged because of the sake of them being dead. (Trust me, you will cry.)
GetUnitX/Y > GetWidgetX/Y
It also doesnt deal damage in a proper angled rectangle (if I read the code correctly).
Condition > Action (Especially when used both)

I have given clear instructions on how to code this properly in GUI and JASS.
I recommend you to just follow that instead of fixing code that you dont understand.
(For everyone who asks where those instructions are, they are in a PM :D)
 
Level 12
Joined
Jan 2, 2016
Messages
973
There is a pretty simple way to get this skill working without Jass:
  • Set Temp_Point1 = position of triggering unit
  • Set Temp_Point2 = target point of ability being cast
  • Set Temp_Real = angle between Temp_Point1 and Temp_Point2
  • Set Temp_Integer = Distance between Temp_Point1 and Temp_Point 2/50
  • Loop Integer A from 1 to Temp_Integer
  • Set_Temp_Point = point centered at Temp_Point1 with offset 50*(Integer A) at angle Temp_Real
  • Select all units in range ~you decide what range it should have. I'd make it 150-200~ from Temp_Point and add them to Temp_Group1
  • //In the end you select all the units in a larger Area to deal the full damage to.
  • Select all units in range ~300-400, maybe?~ from Temp_Point2 and add them to Temp_Group2
  • Pick all units from Temp_Group1 and do actions:
  • If Picked unit is in Temp_Group2, Then Do nothing, Else cause triggering unit to damage picked unit for 25+25*Level of ability
  • Pick all units form Temp_Group2 and do actions:
  • Cause Triggering unit to damage picked unit for 50+50*Level of ability.
  • //And in the end you can make a dummy unit with 30 seconds invisibility and make it cast invi to your unit/hero.
  • //Clear variables and remove leaks.
Sorry I didn't make the trigger to copy-paste it here properly, instead I just wrote it here.
However, you can also make some special effects if you want :p
 
Last edited:
Level 22
Joined
Feb 6, 2014
Messages
2,466
I say do not use multiple languages unless it is necessary... and because everything is translated into JASS, neither C nor vJASS have anything that cannot be done in JASS itself. (except global variables)

Why not? If he's comfortable in coding in ZINC then he'll code in ZINC.
Global Variables can be done in JASS (but the hard way)
A good reason to code in vJASS is to code easier, here are more reason to code in vJASS.
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
@Shadow Flux
JASS and vJASS are almost equal (except for struct syntax), C on the other hand is completely different.

Also, he isnt confortable in ZINC because he didnt understand what the code really did.
He didnt even knew it wasnt JASS.

I do not necessarily support structs or scopes but you can use it if you want to.
I do recommend libraries and globals though.

@WereElf
That is not a really nice way to pick units in a rectangle though.
 
Level 12
Joined
Jan 2, 2016
Messages
973
@WereElf
That is not a really nice way to pick units in a rectangle though.
Sure it's imperfect, but it works fine for practical needs.
if the radius is 150, it will have a wavy shape, but the max offset will be 150 and the minimum will be 147,9. If the radius is 200, the maximum will be 200 and minimum will be 198,43. I have noticed that in the game anything less than 20 units doesn't affect anything (if we are talking about units, not effects or floating text)
EDIT: I imagine using a tangent function would be the best way to select units in a rectangle, but I'm not really sure I've ever seen one in the Math functions (haven't really needed it before)
EDIT 2:
Turns out there really is a tangent function, but I kind of solved the equasion another way:
  • Trigger 1
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Blink
    • Actions
      • Set C_Point = (Position of (Triggering unit))
      • Set T_Point = (Target point of ability being cast)
      • Set Angle = (Angle from C_Point to T_Point)
      • Set Distance = (Distance between C_Point and T_Point)
      • Set TempPoint = (C_Point offset by (Distance / 2.00) towards Angle degrees)
      • Unit Group - Pick every unit in (Units within (Distance / 2.00) of TempPoint matching (((Owner of (Matching unit)) is an enemy of (Owner of (Triggering unit))) Equal to True)) and do (Actions)
        • Loop - Actions
          • Set U_Point = (Position of (Picked unit))
          • Set Temp_Angle = (((Angle from C_Point to U_Point) + 90.00) - Angle)
          • Set Temp_Distance = (Distance between C_Point and U_Point)
          • Set N_Point = (C_Point offset by Temp_Distance towards Temp_Angle degrees)
          • Set X_Point = (Point((X of N_Point), (Y of C_Point)))
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Distance between C_Point and X_Point) Less than or equal to 150.00
            • Then - Actions
              • Unit Group - Add (Picked unit) to HalfDmg_Group
            • Else - Actions
      • Unit Group - Add all units of (Units within 300.00 of T_Point) to FullDmg_Group
      • Unit Group - Remove all units of FullDmg_Group from HalfDmg_Group
      • Unit Group - Pick every unit in FullDmg_Group and do (Actions)
        • Loop - Actions
          • Unit - Cause (Triggering unit) to damage (Picked unit), dealing (50.00 + (50.00 x (Real((Level of (Ability being cast) for (Triggering unit)))))) damage of attack type Spells and damage type Normal
          • Unit Group - Remove (Picked unit) from FullDmg_Group
      • Unit Group - Pick every unit in HalfDmg_Group and do (Actions)
        • Loop - Actions
          • Unit - Cause (Triggering unit) to damage (Picked unit), dealing (25.00 + (25.00 x (Real((Level of (Ability being cast) for (Triggering unit)))))) damage of attack type Spells and damage type Normal
          • Unit Group - Remove (Picked unit) from HalfDmg_Group
      • Unit - Add Permanent Invisibility to (Triggering unit)
      • Countdown Timer - Start Timer as a One-shot timer that will expire in 30.00 seconds
      • Set Invi_Unit = (Triggering unit)
  • Trigger 2
    • Events
      • Time - Timer expires
      • Unit - A unit Is attacked
      • Unit - A unit Begins casting an ability
    • Conditions
      • Or - Any (Conditions) are true
        • Conditions
          • (Attacking unit) Equal to Invi_Unit
          • (Remaining time for Timer) Equal to 0.00
          • (Casting unit) Equal to Invi_Unit
    • Actions
      • Unit - Remove Permanent Invisibility from Invi_Unit
      • Set Invi_Unit = No unit
I admit, that the shape of the selection still isn't a pure rectangle, it's more like: a (________) with closed top too, but I still think that this is good enough for practical purposes. Making it a rectangle would require even more variables :p

So now you can just add the special effects and enjoy your spell :)
NOTES:
1) You don't see the invisibility buff in the hero's stats. You could add a Timer window to indicate when would the spell expire.
2) The spell isn't MUI right now (only the invisibility part).
3) The unit can move while invisible right now. Add more events that break the invisibility in the 2-nd trigger if you want to limit its movement.
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,657
Isnt there a spell that makes the target unit invisible?
I guess that should be used over permanent invisibility.

Removing units from a group is not necessary.
There are two perfectly working functions to group units in a rectangle right here on the hive.

This is one:
JASS:
library IsPointInRectangle
    //determins if point P is in rectangle ABCD. (Either clockwise or rounterclockwise with AB, BC, CD and AD as edges.)
    function IsPointInRectangle takes real ax, real ay, real bx, real by, real cx, real cy, real dx, real dy, real px, real py returns boolean
        local real ex = bx - ax
        local real ey = by - ay
        local real fx = dx - ax
        local real fy = dy - ay

        if ((px - ax) * ex + (py - ay) * ey < 0.0) then
            return false
        endif

        if ((px - bx) * ex + (py - by) * ey > 0.0) then
            return false
        endif

        if ((px - ax) * fx + (py - ay) * fy < 0.0) then
            return false
        endif

        if ((px - dx) * fx + (py - dy) * fy > 0.0) then
            return false
        endif

        return true
    endfunction
endlibrary
This can check if a point is inside a rectangle.

I wrote a function that actually groups units in a rectangle with a slightly less efficient method... I have to change it sometime :D
JASS:
    //Return wether point ("px", "py") is in a rectangle of size ("width", "height") on point ("x", "y")
    //  angled to "angle" radians(Rad)/degrees(Deg).
    function IsPointInAngledRectangleRad takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
        local real halfWidth = width/2
        local real halfHeight = height/2
        local real distance = DistanceBetweenCoordinates(rx, ry, px, py)
        local real newPX
        local real newPY
        set angle = angle - AngleBetweenCoordinatesRad(rx, ry, px, py)
        set newPX = distance * Cos(angle)
        set newPY = distance * Sin(angle)
        
        return newPX > -halfWidth and newPX < halfWidth and newPY > -halfHeight and newPY < halfHeight
    endfunction
    function IsPointInAngledRectangleDeg takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
        return IsPointInAngledRectangleRad(rx, ry, width, height, angle * DEGTORAD, px, py)
    endfunction
    //Deprecated function pointing at "IsPointInAngledRectangleRad()" for backwards compatibility.
    function IsPointInAngledRectangle takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
        return IsPointInAngledRectangleRad(rx, ry, width, height, angle * DEGTORAD, px, py)
    endfunction
    
    //Ex functions for calls where angle is already calculated as radian.
    //Use "angle * DEGTORAD" to convert degrees to radians.
    function IsPointInAngledRectangleEx takes real rx, real ry, real width, real height, real angle, real px, real py returns boolean
        local real halfWidth = width/2
        local real halfHeight = height/2
        local real distance = DistanceBetweenCoordinates(rx, ry, px, py)
        local real newPX = distance * Cos(angle)
        local real newPY = distance * Sin(angle)
        return newPX > -halfWidth and newPX < halfWidth and newPY > -halfHeight and newPY < halfHeight
    endfunction
    
    //Groups all units in a rectangle of size ("width", "height") on point ("x", "y") angled to "angle" degrees(Deg)/radians(Rad).
    //Returns "whichGroup" for easy usage: "local group g = GroupEnumUnitsInRectangle(CreateGroup(), x, y, w, h, a)".
    function GroupEnumUnitsInRectangleRad takes group whichGroup, real x, real y, real width, real height, real angle returns group
        local unit FoG
        local group g = CreateGroup()
        local real ux
        local real uy
        
        call GroupEnumUnitsInRange(g, x, y, SquareRoot(width*width + height*height)*0.5, null)
        loop
            set FoG = FirstOfGroup(g)
            exitwhen FoG == null
            call GroupRemoveUnit(g,FoG)
            
            set ux = GetUnitX(FoG)
            set uy = GetUnitY(FoG)
            if IsPointInAngledRectangleEx(x, y, width, height, angle - AngleBetweenCoordinatesRad(x, y, ux, uy), ux, uy) then
               call GroupAddUnit(whichGroup, FoG)
            endif
        endloop
        
        call DestroyGroup(g)
        set g = null
        return whichGroup
    endfunction
    //Deprecated function pointing at "GroupEnumUnitsInRectangleRad()" for backwards compatibility.
    function GroupEnumUnitsInRectangleDeg takes group whichGroup, real x, real y, real width, real height, real angle returns group
        return GroupEnumUnitsInRectangleRad(whichGroup, x, y, width, height, angle * DEGTORAD)
    endfunction
    //Deprecated function pointing at "GroupEnumUnitsInRectangleRad()" for backwards compatibility.
    function GroupEnumUnitsInRectangle takes group whichGroup, real x, real y, real width, real height, real angle returns group
        return GroupEnumUnitsInRectangleRad(whichGroup, x, y, width, height, angle * DEGTORAD)
    endfunction
 
Level 12
Joined
Jan 2, 2016
Messages
973
Yeah.. Well, I still haven't started learning JASS.. I just suggested a way it can be done without JASS. Otherwise, if people want a perfect rectangle with my trigger, they'd need to increase the range of the 1-st selection from distance/2 to something bigger (like distance/2 + 150 (the AoE of the spell)); and then add 2 more conditions, (Y of N_Point must be bigger than or equal to Y of C_Point; and Y of N_Point must be less than or equal to ((Y of C_Point)+Distance)

As for the invisibility, I tried to make a dummy unit cast invisibility on triggering unit, but it wasn't working for some reason.
I suppose it would've been easier to base the spell on shock wave and move the unit with to the desired location with the trigger, and then add the invisibility (with the dummy), but I didn't try to do it this way, instead I just added the permanent invisibility.
 
Last edited:
Level 12
Joined
May 22, 2015
Messages
1,051
Just a note on shockwave, use carrion swarm instead. Shockwave has terrain deformation which causes some lag. If you use many shockwaves to make it cover variable distance, you will probably see frame rate drops to 10 or less. Using multiple shockwaves also will probably cause overlaps at certain points (which, in this case, will cause extra damage) or gaps (similar to checking multiple circles for units).

I'll take a look at that IsPointInRectangle code. I could probably use that for my map.
 
Status
Not open for further replies.
Top