• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

Baradé's Ray 1.0

This bundle is marked as awaiting update. A staff member has requested changes to it before it can be approved.
Motivation
A simple ray spells system inspired by Ray of Frost and Disintegrate from Diablo III.
The rays can detect units, destructables and items for collisions as well as terrain height differences and pathing.
Warcraft III does not allow this by default.

This is how the Diablo III spell looks like:

The hero can still walk and attack while using ray spells with this system unlike in Diablo III.

Usage
You need to specify all options in the library RayConfig like in the demo map.
The demo map contains many example spells which you could use.
More will be added in the future.

Here is a demo video:


I have updated the system since the video and added delays for ray effects such as cyclone and resurrection as well as harvesting to make it a bit more balanced.


Features
  • Target detection for units, items and destructables.
  • Blocking by pathing and height differences.
  • Target Z detection.
  • Target unit collision size detection.
  • Hit duration per target detection.
  • Loop and target sounds.
  • Caster and target effects.
  • Mouse movement aiming.
  • Multiple different lightnings per spell.
  • Dummy support for target ability effects.

Future Work
- DONE: Polymorph/Hex Ray in the demo map.
- DONE: Neutralization Ray in the demo map.
- DONE: Charm Ray in the demo map.
- DONE: Caster and target effect with user-defined attachment points.
- DONE: Disable attacking during ray (Charm Ray etc.).
- DONE: Better aiming controls maybe while pressing shift or something where the hero only changes the direction.
- Allow one ray to hit multiple targets?
- More options to configure rays: Blocking pathing types, disallow moving/attacking, etc.
- Register destructable collision sizes for more accurate blocking/hitting.
- My issue for my own map for this system: https://github.com/tdauth/wowr/issues/2698

Credits
- Custom lightning effects by Spellbound: https://www.hiveworkshop.com/threads/spellbounds-custom-lightning-effects.292771/
Contents

Baradé's Ray 1.0 (Map)

Reviews
Antares
In the GetTargetUnit function, you can recycle the group and simply clear it at the end with GroupClear. Doing the check for the closest unit inside the filter is a bit confusing and using filters is also quite slow. You can create a group without a...
I was thinking about that too. I might be able to catch and interrupt move/target orders and only change the facing and could add a boolean flag for that.
I made a spell like that. I added a second, hidden channeling ability based on Channel to the hero when the original spell is cast, then whenever a movement command is given, it is replaced with casting the hidden spell at the target location.

To get the hold-down-right-mouse-button to change direction of the laser behavior, you'd need a click-and-hold system.
 
Level 26
Joined
Feb 2, 2006
Messages
1,698
How exactly does it work in Diablo? You hold a key for the spell and then ordering with the mouse will only rotate the caster? When you release the key the spell stops? I do not need to cast a new spell when the order is given but only rotate the hero. The ray will change the direction automatically to the facing of the hero.
 
Hope I'm remembering this right, been ten years.

You can bind a spell to the left- and right-mouse-button or to keys. Whatever key or button you bind it to, as long as you hold it down, your character will stop and channel the laser in the direction of your mouse-cursor.

You could make it so that holding down the spell hotkey makes the hero fire it, but you have to solve the issue that different players have different hotkey layouts.
 
Level 26
Joined
Feb 2, 2006
Messages
1,698
If you keep a key pressed for a spell it will be cast n times again and again by Warcraft III. I could just add a timer like 2 seconds or 1 second which checks if you still restart casting it (holding the key down). Then I do not need to know the hotkey but it would be limited to the spell's hotkey.

For attacks I could try adding mouse bindings but it will take some time to add this.

At least I got an option which stops the hero and only changes the hero's facing when ordering movement somewhere.

edit:
Update:
  • Frost Ray, Fire Ray and Frost and Fire Ray spells require holding their key and allow aiming with the mouse cursor like in Diablo III now.
  • Fix exploding barrels.
  • Increase the damage by ray spells.
  • Escape key allows reviving and refilling your heroes.
  • Refactoring and some optimization of code.
  • Library requires MouseUtils.
  • Custom libraries TreeUtils and MathUtils as clear requirements for the system.
 
Last edited:
These massive if/then trees is not ideal. Why not store valid abilities in a hashtable so that this check is O(1)? It would also condense a lot of your code.
JASS:
public function IsValidAbility takes integer abilityId returns boolean
    if (abilityId == FROST_RAY) then
        return true
    elseif (abilityId == FIRE_RAY) then
        return true
    elseif (abilityId == HOLY_RAY) then
        return true
    elseif (abilityId == HARVEST_RAY) then
        return true
    elseif (abilityId == LOOT_RAY) then
        return true
    elseif (abilityId == WATER_RAY) then
        return true
    elseif (abilityId == DRAIN_RAY) then
        return true
    elseif (abilityId == FROST_AND_FIRE_RAY) then
        return true
    elseif (abilityId == CHAIN_RAY) then
        return true
    elseif (abilityId == MANA_RAY) then
        return true
    elseif (abilityId == RAISE_RAY) then
        return true
    elseif (abilityId == POISON_RAY) then
        return true
    elseif (abilityId == CHARM_RAY) then
        return true
    elseif (abilityId == NEUTRALIZATION_RAY) then
        return true    
    elseif (abilityId == HEX_RAY) then
        return true
    elseif (abilityId == RESURRECTION_RAY) then
        return true
    elseif (abilityId == WIND_RAY) then
        return true
    endif
    return false
endfunction
 
It could be worse :plol:

Yea, you can use a hashtable for the checks and for the effect calls a function interface. I also think that you should make it easy for the user to define their own on-hit callback. I'm thinking that the vast majority of people will want to use a damaging ray with flashy special effects attached to it and maybe some secondary effects like debuffs etc.
 
Level 26
Joined
Feb 2, 2006
Messages
1,698
I can provide some kind of struct RayType with function callbacks. Need some more time/work. It just grew this way.

For the moment, you just have to modify for example:

JASS:
public function OnHitUnit takes unit caster, unit target, integer abilityId, real duration returns nothing

I want to support multiple abilities per ray type in the future since you could have different hero/unit/item abilities with the same ray times.
I would need some function like
JASS:
function IsLootRay takes integer abilityId returns boolean
with the current version.

I can refactor it using some RayType struct and making the T struct public as RayData or something:

JASS:
struct RayData // exists already as struct T in library Ray
      integer abilityId
      unit caster
      unit target
      real duration

      ...

endstruct

function interface OnHitUnit takes RayData r returns nothing

struct RayType
      string casterEffect
      string hitEffect
      boolean mouseAiming
      OnHitUnit onHitUnit

      ...

endstruct

function AddRayType takes integer abilityId, RayType t returns nothing


I was also wondering if there were any standardized TreeUtils and MathUtils on Hive/which are used in other systems rather than my own libs.
 
Last edited:
In the GetTargetUnit function, you can recycle the group and simply clear it at the end with GroupClear. Doing the check for the closest unit inside the filter is a bit confusing and using filters is also quite slow. You can create a group without a filter, then loop through those units inside the GetTargetUnit function to find the closest (same for destructable and item).

You have a typo in your code, where BlzSetSpecialEffectY should be Z:
JASS:
call BlzSetSpecialEffectX(target.targetEffect, GetUnitX(target.u))
call BlzSetSpecialEffectY(target.targetEffect, GetUnitY(target.u))
call BlzSetSpecialEffectY(target.targetEffect, BlzGetUnitZ(target.u) + GetUnitFlyHeight(target.u))

The config is where most of the problems are buried. As you suggested, you can provide a RayType struct that holds all the data for the ray, such as spell id, lightning type, valid targets, and callbacks stored, and then simply provide templates for how to create new RayTypes or customize the ones you provided. This will make it much easier for the user to customize the system and create their own rays as well as make the system much more performant. You're looping through multiple giant if-then-else trees for each potentially valid target every frame, which is not ideal.

Hashtables wouldn't then be necessary, but could be useful to store the spell ids for IsValidAbility and to fetch the RayType for the spell id, which holds all further data. Also, the IsTree function should use a hashtable.

I was also wondering if there were any standardized TreeUtils and MathUtils on Hive/which are used in other systems rather than my own libs.
I think it's a good idea to reduce the number of dependencies when you're just using a few function as you do here. If someone uses a math library that has the same functions you defined, they can merge the libraries easily.

The sorceress's fire and frost rays are super fun to use and I hope you can improve and expand on those. It's a great system, but because of the aforementioned issues, I wouldn't approve it just yet.

Awaiting Update
 
Top