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

Attack System v1.1 [vJass | + GUI Support]

This bundle is marked as awaiting update. A staff member has requested changes to it before it can be approved.
CUSTOM ATTACK SYSTEM

A custom attack system that aims to closely mimic the default Warcraft 3 attack system that is more dynamic and

provides full (almost) control over the launched attacks' behavior as well as events for the different phases in the
attacking process




THE SYSTEM CONTAINS:


AttackSystem
(Main)

- Allows you to do more attack-related operations than what is currently provided by Blizzard. It
does this primarily by using custom projectiles instead of the default game attack projectiles
(which are one of the most untouchable - meaning unreadable and non-modifiable, yet significant
things in the game). Unlike the game's default attack system, this one if very dynamic and does
not have much of a hard-coded limit.

Below are some cool things you can easily achieve using this system:

~ Switch a unit from being melee to a ranged attacker in an instant
~ Attach many special effects to ranged attacks
~ Make ranged attacks accelerate/decelerate
~ Destroy ranged attacks while in mid-air
~ Divert attacks to another target
~ Stop ranged attacks from moving (Especially in time-stop spells like Chronosphere, you must
stop projectiles as well!)
~ ... and the list goes on!

The things mentioned above are just the basic things you can achieve with this system. There are
so much more wonderful things that you can do with it. For more information, read the documentation
inside the test map.



EvasionSystem (Add-on library)

- Allows you to dynamically modify the evasion chance of units. Aside from that, you can also set the
accuracy of a unit, and of an attack.



AttackModifier (Add-on library)

- This library ensures the correct behavior when making an attack modifier. Use this for making
things like orb-effects, true-strikes, critical-strike, bash, etc. For more information on why you
should use this library and what are those issues it tries to solve, more documentation can be
found on this library's header inside the test map.



AttackMissileUtils (Add-on library)

- This library provides utility functions for enumerating ranged attacks' missiles with certain constraints.
This can be especially useful in creating spells (like chronosphere), force-fields, etc.



REQUIREMENTS:

JassHelper

Libraries

Optional Libraries



The complete documentation regarding the system can be found inside the map.
Feel free to report bugs and/or leave some feedback.




v1.0
- First Release

v1.0b
- Added a new add-on library 'AttackModifier'
- Fixed a bug affecting the enabling/disabling of attacks (as well as other bugs)
- Added a new event EVENT_ATTACK_DESTROY
- Changed some event firing behavior
- Added more function APIs for completeness
- Fixed some documentation errors
- Greatly improved the test map to showcase more of what the system can do
- Other changes

v1.0c
- Added a GUI support
- Added a short demo for the GUI plugin
- Added the function DestroyEventAttack()
- Fixed a number of bugs
- Other changes

v1.0d
- Not released

v1.0e
- Made compatible for patches 1.29+
- Fixed recursion problems on the GUI plugin
- Added an Evasion event callback handlers for the Evasion add-on lib
- Added a method for manual Attack allocation
- Added a boolean field for enabling an Attack missile's shadow
- Few API changes
- Bux fixes and other changes

v1.1
- Added a new add-on library named 'AttackMissileUtils'
- Fixed the bug regarding manual attack destruction
- Now truly compatible for patches 1.29.x
- Other changes

Previews
Contents

Attack System v1.1 (Map)

Reviews
IcemanBo
It's negliable, but maybe you could just cause 0 damage. In case the unit gets fully healed it stays at 100%, and extra trick removed here: call SetWidgetLife(target, GetWidgetLife(target) - attack.damage + 0.001) /*...
MyPad
Based from the inputs above, it would be safe to say that this should be set to Awaiting Update. Once all issues above are addressed in a sufficient manner or avoided entirely, another review will be released. Status: Awaiting Update

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
new natives
I haven't updated to patch 1.29 yet, because of slow and limited data access :(

I dont quite get what it does..
It is an alternative system to handle units' attacks. If you look at the test map, you can see that the footman's ranged attacks have multiple special effects used for its projectile (Something you can't do with the game's default attack system).
 
Level 13
Joined
Mar 29, 2012
Messages
530
Can be super useful for a new kind of gameplay.

This makes me wonder if warcraft 3 battle gameplay can include a more realistic rushing, striking, and dodging than just watching every units strike each other with a static position and wait who dies first.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
UPDATED to v1.0b
- Added a new add-on library 'AttackModifier'
- Fixed a bug affecting the enabling/disabling of attacks (as well as other bugs)
- Added a new event EVENT_ATTACK_DESTROY
- Changed some event firing behavior
- Added more function APIs for completeness
- Fixed some documentation errors
- Greatly improved the test map to showcase more of what the system can do
- Other changes


Added more testing opportunities in the test map. More explanation and examples in the first post are also added.


EDIT:
GUI Plug-in coming soon (maybe).
 
Last edited:

Notes:

  • (Potential bug) In the Evasion System, even if you were to set evasion up a notch, it might still affect the unit. Experienced with buildings. Is this intentional?
  • When pausing the game, a unit whose attack is disabled will have the attack ability display a green icon. (Workaround is to export the disabled icon and treat it as an active icon.)

Nitpicks:

  • This takes up a bit more of resource than the internal attack system, and with more units, the performance drops quite a lot (nigh exponential). (Perhaps your MasterTimer library can come into play or Nes' Timer library)

    (Tested with the following specifications:
    Intel(R) Celeron(R) CPU N2840 @2.16 GHz
    2.00 GB RAM (1.88 GB usable)
    64 - bit Operating System, x64-based processor.
    Intel HD - Graphics

    Test Conditions:
    Google Chrome running in the background.
    File Explorer, Calculator, Control Panel, and World Editor and its' modules running.
    )

Status:

  • Awaiting Update
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
(Potential bug) In the Evasion System, even if you were to set evasion up a notch, it might still affect the unit. Experienced with buildings. Is this intentional?
You mean even with something like call SetUnitEvasion(target, 2.00), the target still has a chance of getting hit? Haven't tested it with buildings indeed so I'm gonna check it out.

When pausing the game, a unit whose attack is disabled will have the attack ability display a green icon. (Workaround is to export the disabled icon and treat it as an active icon.)
Right. Will be fixed next update.

This takes up a bit more of resource than the internal attack system, and with more units, the performance drops quite a lot (nigh exponential). (Perhaps your MasterTimer library can come into play or Nes' Timer library)
A major contributor to this might be the spamming of units for every ranged attack's missile (2 dummies per missile in fact). I hope I can update to 1.29+ soon to get rid of the need for dummies. As for using timer systems I'll just try to optimize my internal timer usage instead.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Updated to v1.0e
- Made compatible for patches 1.29+
- Fixed recursion problems on the GUI plugin
- Added an Evasion event callback handlers for the Evasion add-on lib
- Added a method for manual Attack allocation
- Added a boolean field for enabling an Attack missile's shadow
- Few API changes
- Bux fixes and other changes
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Man this looks cool AF. I will check this out soon and see what kind of crazy stuff you've added.

I dig the use of the new natives. I've barely seen any resources using them.

One thing I recommend is to split the projectile resource into its own library. I might, for example, not want to overhaul the entire attack engine of the game and prefer to use just custom projectiles.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Updated to v1.1
- Added a new add-on library named 'AttackMissileUtils'
- Fixed the bug regarding manual attack destruction
- Now truly compatible for patches 1.29.x
- Other changes

Man this looks cool AF. I will check this out soon and see what kind of crazy stuff you've added.

I dig the use of the new natives. I've barely seen any resources using them.

One thing I recommend is to split the projectile resource into its own library. I might, for example, not want to overhaul the entire attack engine of the game and prefer to use just custom projectiles.
Thanks. I used BPower's Missile lib at the beginning, but it doesn't support arcing movements for homing missiles and then there also comes the natives from the new patch which rendered the dummy method obsolete so I was forced to write an internal one. I wonder if there's any chance @BPower 's gonna update his lib.. would be nice =). If not, I'm not sure I can write a full projectile system.
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
If I was able to write Table, which was also mostly a spin-off at the beginning, then you can spin off your own projectile handler.

What you could consider doing is trying to imitate BPower's API, which would give it the same syntax (thus easier to integrate for users already on his missile system).

Btw, I have tested it on my Mac and have the following feedback:

Blood Mage attack cooldown interacts weirdly with its animation. You'll need to figure out how to make that work, as currently the timing is quite off (what Nestharus does is use a 0 damage, super fast projectile to detect when the launch should occur. You should try it)

Also the re-targeting is awful. I issue an Attack or Smart order and the BM takes almost a second or two to get the hint. Your engine should intrinsically know his attack cooldown is ready and that the missile should launch at the same time.

For the demo, you should implement a barrier-type thing which showcases how the attack projectiles work.

Lastly, maybe give the BloodMage a melee attack without the orbs, to show off that it can switch seamlessly as you put it.
 
  • Like
Reactions: AGD
It's negliable, but maybe you could just cause 0 damage. In case the unit gets fully healed it stays at 100%, and extra trick removed here:
JASS:
            call SetWidgetLife(target, GetWidgetLife(target) - attack.damage + 0.001)
            /*
            *   If the damage is negative, it's still needed to deal damage to the target to maintain the desired
            *   behavior of an attacked target (ex: units with 'build' ability should retreat from the attacker)
            */
            call UnitDamageTarget(u, target, 0.001, true, ranged, attack.attacktype, attack.damagetype, attack.weapontype)
Is there a a way to know if the dummy dealt damage in function DealDamage, or the original source unit did it? I'm not sure if it would be useful for user, like operating at an event with unit type of the source, which would not exist anymore. Maybe UnitTypeId information makes sense, too, to save as member of source attacker? - the user could still check for source's GetUnitTypeId if needed, I guess, to check if he needs to read it.

Even if a widget is targeted, maybe targetX/Y could be assigned to widgetX/Y then, instead of 0? (still a value, but wrong value) But sure user could read it out of widget natives.

imo Table(KEY). could be table = KEY -> table. but yeh haha..^^

attackOrderType could be a struct for tiny bit more readability. (in sense of an enum)

'ncop' could be on top config

Demo doesn't work for me... after some gooood time testing I found out it's not your system's fault, but because the a filter does return wrong result..:
JASS:
    private function TargetUnitFilter takes unit attacker, unit target returns boolean
        return attacker != target                                                                   and/*
            */ UnitAlive(target)                                                                    and/*
            */ GetUnitAbilityLevel(target, 'Aloc') == 0                                             and/*
            */ (IsUnitVisible(target, GetOwningPlayer(attacker)) or GetUnitTypeId(attacker) == 0)   and/*
            */ not IsUnitType(target, UNIT_TYPE_ETHEREAL)                                           and/*
            */ not BlzIsUnitInvulnerable(target)
        
    endfunction

BlzIsUnitInvulnerable works very wrong, and no attack was properly launched, and always canceled at some point -- auto acquire didn't work, too. With removing the invulnerable check, all seems to work, and demo is running, too. In patch notes 1.30 I then found "[World Editor] BlzIsUnitInvulnerable returns the correct boolean value" . :( I guess no problem ultimately for you, but it's not 1.29 compatible with it. (will personally patch soon anyways, after fixes)

A last remark, or just note.. but not sure myself how to handle it the best. When a unit teleports away ,for example, then the projectile follows to the target's new position, and it might look some ugly because the projectile might abruptly turn, change the curve looks, and change speed in extreme. Not sure if users should be notified about such extreme position changes, being able to cancel the peojectile flight, or what ever.. but yeh, maybe you had some thought about it already. Just as note.

I must say it's a very impressive piece of code you made there. Very clean, nicely structured, not unnecessarily complex. All at once is a bit big to read, but anyways good. :thumbs_up: Maybe the one or other comment could be added to ease the read even a bit more. A very definite 5/5 , keep doing!
 
  • Like
Reactions: AGD

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
If I was able to write Table, which was also mostly a spin-off at the beginning, then you can spin off your own projectile handler.

What you could consider doing is trying to imitate BPower's API, which would give it the same syntax (thus easier to integrate for users already on his missile system).
I might do this but it will be only after the other basic features are already stable.

Also the re-targeting is awful. I issue an Attack or Smart order and the BM takes almost a second or two to get the hint. Your engine should intrinsically know his attack cooldown is ready and that the missile should launch at the same time.
I think this is because of the dummy ability I used which is based off channel. I tested it and for some reason, even if you set both the casting time of the channel ability and the unit to 0, the spell will still have a short casting time. Anyway, I'll check that technique using attack with 0 damage.

For the demo, you should implement a barrier-type thing which showcases how the attack projectiles work.

Lastly, maybe give the BloodMage a melee attack without the orbs, to show off that it can switch seamlessly as you put it.
Will add

Is there a a way to know if the dummy dealt damage in function DealDamage, or the original source unit did it? I'm not sure if it would be useful for user, like operating at an event with unit type of the source, which would not exist anymore. Maybe UnitTypeId information makes sense, too, to save as member of source attacker? - the user could still check for source's GetUnitTypeId if needed, I guess, to check if he needs to read it.
One can know if the damage source is the dummy by checking if GetUnitTypeId(attack.source) == 0 is true. However, there is currently no way of knowing the unitId of the removed unit source. I'll add it as I also think it's necessary.

Even if a widget is targeted, maybe targetX/Y could be assigned to widgetX/Y then, instead of 0? (still a value, but wrong value) But sure user could read it out of widget natives.
The targetX/Y is intended for storing values of the target point when attacking a point. Before reaching to the target point, the unit may auto-acquire enemy targets on its way and therefore by doing that, it would overwrite the targetX/Y values and the users will no longer have access to the original target point.

A last remark, or just note.. but not sure myself how to handle it the best. When a unit teleports away ,for example, then the projectile follows to the target's new position, and it might look some ugly because the projectile might abruptly turn, change the curve looks, and change speed in extreme. Not sure if users should be notified about such extreme position changes, being able to cancel the peojectile flight, or what ever.. but yeh, maybe you had some thought about it already. Just as note.
The speed of the missile will not be affected by teleport but it does abruptly change its height and orientation though. The sudden change in orientation of fine I guess but the sudden change in height is really a problem.. Thanks for pointing this out. Will find a way for this.

Thanks for the input guys :)
 
The targetX/Y is intended for storing values of the target point when attacking a point. Before reaching to the target point, the unit may auto-acquire enemy targets on its way and therefore by doing that, it would overwrite the targetX/Y values and the users will no longer have access to the original target point.
I see.
The speed of the missile will not be affected by teleport but it does abruptly change its height and orientation though.
Ok, I probably falsly thought one can define like a max duration for the missile, so changing distance in large scale might have big efffect. In theory it would be probably a bit strange if a missile follows the unit though the whole map after a teleport and hits the enemy after 30 seconds.. or idk. :D

Will you drop 1.29 support? ( dealing with Invulnerable)
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Yeah I guess I don't have a choice but to drop support for 1.29.

Regarding the attack with 0 damage, my problem right now is that there's no way to dynamically change the missile speed of a unit via natives. Which means that you need to predetermine all the unittypes that you want to register to the system since you have to edit their projectile speed at the object editor. I need think of a workaround to dynamically set the projectile speed between normal speed and being instant. Any help with this would be nice =).
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Yeah I guess I don't have a choice but to drop support for 1.29.

Regarding the attack with 0 damage, my problem right now is that there's no way to dynamically change the missile speed of a unit via natives. Which means that you need to predetermine all the unittypes that you want to register to the system since you have to edit their projectile speed at the object editor. I need think of a workaround to dynamically set the projectile speed between normal speed and being instant. Any help with this would be nice =).
There's a thread for suggesting new natives to Blizzard. GetUnitArmor/DamageType (and hopefully Set) would be a huge plus. SetUnitProjectileSpeed would be cool, but an event which fires when a unit launches their projectile would be better, followed by the projectile being accessible as a Special Effect type (would probably need more complex natives for that though, such as start/stop projectile movement, set Target X/Y/widget)

@MindWorX would be your only hope, but he's on Blizzard's payroll not ours, so we don't know what he's got time to implement.
 
Regarding the attack with 0 damage, my problem right now is that there's no way to dynamically change the missile speed of a unit via natives.
Not sure I understand how it is related, could you elaborate? Also, what do you mean with changing projectile speed is not possible - you do set its motion via call BlzSetSpecialEffectPosition(sfx, x, y, z), don't you?
 
Level 7
Joined
Feb 9, 2021
Messages
301
Sadly no, it can only be used in patches 1.30+.
Here, I found something similar that works on 1.26 Burst Laser v3.1. Does it mean it is possible to create on 1.26?

Another question is if I want a shield that block ranged auto-attack, is there a way to do it on 1.26? Similar question regarding the time stop spells that stop ranged auto-attacks.
 

AGD

AGD

Level 16
Joined
Mar 29, 2016
Messages
688
Another question is if I want a shield that block ranged auto-attack, is there a way to do it on 1.26? Similar question regarding the time stop spells that stop ranged auto-attacks.
For a shield that only blocks damage, yes you can do it (Damage Engine would suffice). But for stopping the movement of projectiles, you have to use a custom attack system that uses a custom projectile (just like this lib) in order to do that.

Here, I found something similar that works on 1.26 Burst Laser v3.1. Does it mean it is possible to create on 1.26?
I noticed there was an older version that supported older patches, how far did that work below 1.29 and also would anyone still have it?
The earliest patch supported was up to 1.29 only (I lost the copy), but the current version of this system can be recreated to work for 1.26 too. However, as others have pointed out above, the agro, target acquisition, attack animation, backswing, damage point, etc. is different and inferior compared to the built-in attack system of the game, since this system literally rebuilt these things from scratch.
In order to make this system work seamlessly with the built-in attack system of the game instead, one has to recreate this using patch 1.31.1 or above. I already have a pretty good idea how to do it by utilizing the natives introduced in the newer patches but right now I still don't have much time to do these things without other distractions.
 
Level 7
Joined
Feb 9, 2021
Messages
301
For a shield that only blocks damage, yes you can do it (Damage Engine would suffice). But for stopping the movement of projectiles, you have to use a custom attack system that uses a custom projectile (just like this lib) in order to do that.



The earliest patch supported was up to 1.29 only (I lost the copy), but the current version of this system can be recreated to work for 1.26 too. However, as others have pointed out above, the agro, target acquisition, attack animation, backswing, damage point, etc. is different and inferior compared to the built-in attack system of the game, since this system literally rebuilt these things from scratch.
In order to make this system work seamlessly with the built-in attack system of the game instead, one has to recreate this using patch 1.31.1 or above. I already have a pretty good idea how to do it by utilizing the natives introduced in the newer patches but right now I still don't have much time to do these things without other distractions.
Well, by the shield, I meant similar to the Yasuo's wall. So, if there is a shield (or wind wall) between the attacker and attacked unit, the attacker's ranged attack gets blocked by the shield (disappear when encountering the shield).
 
Level 7
Joined
Feb 9, 2021
Messages
301
For a shield that only blocks damage, yes you can do it (Damage Engine would suffice). But for stopping the movement of projectiles, you have to use a custom attack system that uses a custom projectile (just like this lib) in order to do that.



The earliest patch supported was up to 1.29 only (I lost the copy), but the current version of this system can be recreated to work for 1.26 too. However, as others have pointed out above, the agro, target acquisition, attack animation, backswing, damage point, etc. is different and inferior compared to the built-in attack system of the game, since this system literally rebuilt these things from scratch.
In order to make this system work seamlessly with the built-in attack system of the game instead, one has to recreate this using patch 1.31.1 or above. I already have a pretty good idea how to do it by utilizing the natives introduced in the newer patches but right now I still don't have much time to do these things without other distractions.
Will be looking forward to the new system. I think I can make it work for 1.26 with the memory hack. Why don't you use Relativistic Missiles for that?
 
Top