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

Rupture v1.1

Changelog
* 1.0: Skill release
* 1.1: Now the skill works with CTL

This is the Rupture spell from DotA

Deals a mighty blow to the enemy causing any movement to result in bleeding and loss of life.

It's recommended that you use NewGen tool.
This spells REQUIRES CTL library.

JASS:
library Rupture requires CTL
    globals
        // Rawcode of the Rupture ability
        private constant integer RUPTURE_RAWCODE = 'A000'
        // Rawcode of the Rupture buff
        private constant integer RUPTURE_BUFF_RAWCODE = 'B000'
        // Period in that the extra damage will be done
        private constant real PERIOD = 0.25
        // Special effect (blood)
        private constant string SPECIAL_EFFECT = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
        // Special effect attachment
        private constant string ATTACHMENT_POINT = "chest"
        // Rupture initial damage
        private constant real INITIAL_DAMAGE = 150.
        // Rupture attack type
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
        // Rupture damage type (universal = "pure")
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL
        // Do you want preload the special effect?
        private constant boolean PRELOAD = true
    endglobals
    
    // Returns the distance covered by the target
    // a_x and a_y represents the actual position of the target
    // x and y represents the position of the unit in the beggining of the timer
    // Remember, the x and y variables are updated every time when timer expires
    private function getDistance takes real x, real y, real a_x, real a_y returns real
        return SquareRoot((a_x - x) * (a_x - x) + (a_y - y) * (a_y - y))
    endfunction
    
    // Returns the initial damage
    private function getInitialDamage takes integer level returns real
        return INITIAL_DAMAGE + (level * 50)
    endfunction
    
    // Returns the damage by the distance covered by the target
    private function getDamage takes real distance, integer level returns real
        return (distance * (20 * level)) / 100
    endfunction
    
    // Returns the affected units
    private function affectedUnit takes unit target returns boolean
        return true
    endfunction
    
    private keyword Init
    
    private struct Spell extends array
        // Caster
        unit caster
        // Rupture level
        integer level
        // Target
        unit target
        // a = actual (actual x of the target)
        real a_x
        // actual y
        real a_y
        // x of target
        real x
        // y of target
        real y
        // period, represents the period
        // that the extra damage will be done (default: 0.25)
        real period
        
        implement CTL
            // Distance covered by the target
            local real distance
        
        implement CTLExpire
            // If the target still has the Rupture buff and is not dead...
            if 0 < GetUnitAbilityLevel(this.target, RUPTURE_BUFF_RAWCODE) and not(IsUnitType(this.target, UNIT_TYPE_DEAD)) then
                // If the PERIOD seconds was pass...
                if PERIOD < this.period then
                    // Reset period to 0
                    set this.period = 0.
                    // Actual X and Y of the target
                    set this.a_x = GetUnitX(this.target)
                    set this.a_y = GetUnitY(this.target)
                    
                    set distance = getDistance(this.x, this.y, this.a_x, this.a_y)
                    
                    // Make the extra damage only if distance is greater than 0
                    // but less than 1300
                    if 0 < distance and distance < 1300 then
                        call DestroyEffect(AddSpecialEffectTarget(SPECIAL_EFFECT, this.target, ATTACHMENT_POINT))
                        call UnitDamageTarget(this.caster, this.target, getDamage(distance, this.level), false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                    endif
                    
                    // Refreshing the coordenates of the target
                    set this.x = this.a_x
                    set this.y = this.a_y
                else
                    // If the PERIOD seconds was not pass, add
                    // the period of the CTL timer (library)
                    set this.period = this.period + 0.031250000
                endif
            else
                set this.caster = null
                set this.target = null
                call this.destroy()
            endif
            
        implement CTLNull
        implement CTLEnd
        
        private static method run takes nothing returns boolean
            local thistype this
            
            // If the ability being cast is the Rupture and the target can be affected
            // (units that can be affected can be changed in the affectedUnit function)
            if GetSpellAbilityId() == RUPTURE_RAWCODE and affectedUnit(GetSpellTargetUnit()) then
                set this = thistype.create()
                set this.caster = GetTriggerUnit()
                set this.target = GetSpellTargetUnit()
                set this.level = GetUnitAbilityLevel(this.caster,RUPTURE_RAWCODE)
                set this.x = GetUnitX(this.target)
                set this.y = GetUnitY(this.target)
                
                // Make the initial damage
                call UnitDamageTarget(this.caster, this.target, getInitialDamage(this.level), false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
            endif
            
            return false
        endmethod
        implement Init
    endstruct
    
    private module Init
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t,Condition(function thistype.run))
            
            // Preload the special effect...
            static if PRELOAD then
                call Preload(SPECIAL_EFFECT)
            endif
            
            set t = null
        endmethod
    endmodule
endlibrary

NOTE: In the map, there are two spell. They are the same spell, but they works with diferents libraries. One works with TimerUtils, and the other works with CTL. You can choose what you want, but I recommended the spell that works with CTL library.

All tips/corrections/suggest are welcome :).
Greetings, enjoy it :D and sorry for my english :p

Keywords:
rupture, dota, bloodseeker, blood, seeker
Contents

Just another Warcraft III map (Map)

Reviews
9th Nov 2011 Bribe: "affectedUnit" is a pointless function. If the "affectedUnit" returns false then the spell still fires its mana and cooldown. I recommend just remove that part from the script. I recommend SpellEffectEvent so your "run"...

Moderator

M

Moderator

9th Nov 2011
Bribe: "affectedUnit" is a pointless function. If the "affectedUnit" returns false then the spell still fires its mana and cooldown. I recommend just remove that part from the script.

I recommend SpellEffectEvent so your "run" function doesn't evaluate for every spell that is cast.

Otherwise looks good! Approved.
 
Actually, nevermind, use this:
http://www.hiveworkshop.com/forums/submissions-414/system-unit-movement-201449/

Btw, I'd recommend using T32 here. The 0.25 period could be changed to be 0.03125 (better)

But, since Unit Movement requires CTL, you might as well use it.
It works like this:

JASS:
struct YourSpell extends array
    unit caster
    unit target
    integer level
    implement CTL
        // local variables for the periodic event here
    implement CTLExpire
        // timer expire code here
    implement CTLNull
        // null local variables here
    implement CTLEnd
endstruct

You can't create the methods create and destroy. (They come when you implement CTL)
The method create adds an instance of the spell to the timer loop, so it's done like this:

JASS:
function actions takes nothing returns boolean
    local SpellStruct this = SpellStruct.create()
    set this.caster = GetTriggerUnit()
    set this.target = GetSpellTargetUnit()
    set this.level = GetUnitAbilityLevel(this.caster, 'A000')
    // ....
    return false
endfunction

Under CTLExpire, you should put all the code that executes after the timer expires.
You don't need to create a timer by the way. It comes with the system.

When you want to destroy an instance of the struct, just call destroy() and null all the members of the struct.
Under CTLNull, you'd null the LOCALS.
 
Actually, nevermind.. UnitMovement doesn't allow you to get the original x,y and the current x,y..
IsUnitMoving lets you do it, but it's deprecated.
Just use CTL and find the distances yourself :p

edit

Your spell is supposed to look like this:

JASS:
library Rupture requires CTL
    globals
        private constant integer RUPTURE_RAWCODE = 'A000'
        private constant integer RUPTURE_BUFF_RAWCODE = 'B000'
        private constant string SPECIAL_EFFECT = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
        private constant string ATTACHMENT_POINT = "chest"
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL
        private constant boolean PRELOAD = true
    endglobals
    
    private function GetInitialDamage takes integer level returns real
        return 150 + level * 50
    endfunction
    
    private function GetDamage takes real distance, integer level returns real
        return distance * 20 * level / 100
    endfunction
    
    private keyword Init
    
    private struct Spell extends array
        unit caster
        unit target
        integer level
        real x
        real y
        implement CTL
        	local real nx
        	local real ny
        	local real distance
        implement CTLExpire
            set nx = .x-GetUnitX(.target)
            set ny = .y-GetUnitY(.target)
            set distance = SquareRoot(nx*nx+ny*ny)
            if 0<GetUnitAbilityLevel(.target,RUPTURE_BUFF_RAWCODE) and 0.405<=GetWidgetLife(.target) then
                if 0<distance and distance<=1300 then
                    call DestroyEffect(AddSpecialEffectTarget(SPECIAL_EFFECT,.target,ATTACHMENT_POINT))
                    call UnitDamageTarget(.caster,.target,GetDamage(distance,.level),false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
                endif
                set .x = .x-nx
                set .y = .y-ny
            else
                call .destroy()
                set .caster = null
                set .target = null
            endif
        implement CTLNull
        implement CTLEnd
        private static method run takes nothing returns boolean
        	local thistype this
       	 	if GetSpellAbilityId() == RUPTURE_RAWCODE then
        		set this = thistype.create()
        		set .caster = GetTriggerUnit()
        		set .target = GetSpellTargetUnit()
        		set .level = GetUnitAbilityLevel(.caster,RUPTURE_RAWCODE)
        		set .x = GetUnitX(.target)
        		set .y = GetUnitY(.target)
        		call UnitDamageTarget(.caster,.target,GetInitialDamage(.level),false,false,ATTACK_TYPE,DAMAGE_TYPE,null)
        	endif
        	return false
        endmethod
        implement Init
    endstruct
    
    private module Init
    	private static method onInit takes nothing returns nothing
       		local trigger t = CreateTrigger()
        	call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        	call TriggerAddCondition(t,Condition(function thistype.run))
	        static if PRELOAD then
    	    	call Preload(SPECIAL_EFFECT)
    	    endif
    	    set t = null
    	endmethod
    endmodule
endlibrary
 
Last edited:
Level 10
Joined
Sep 19, 2011
Messages
527
0.405<=GetWidgetLife(.target)

->>
not IsUnitType(.target, UNIT_TYPE_DEAD)
? :p

Is not more faster the first?

JASS:
set distance = SquareRoot(nx*nx+ny*ny)
if 0 < distance and distance <= 1300 then

// ->>
set distance = nx*nx+ny*ny
if 0 < distance and distance <= 1690000 then

Why the 1690000 o_O?

Haha I've made this one as well! Rupture

Btw skimmed the code very roughly and this:

1300. > distance

Must be configurable.

Thanks, I saw it and was very useful :thumbs_up:

edit

Your spell is supposed to look like this:

Ok, if CTL if more faster than T32 and TimerUtils I will try to do the spell with it :grin:

I want to benchmark SquareRoot and Pow to see if Pow(x,0.5) is faster :p

I don't understand, Pow is more faster than Square Root?

Thanks to all :D.

Greetings
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
0.405<=GetWidgetLife(.target)

->>
not IsUnitType(.target, UNIT_TYPE_DEAD)
? :p

Well the one using UNIT_TYPE_DEAD is said to be better than the first.. that's what ppl say & not something i'm sure of :p

JASS:
set distance = SquareRoot(nx*nx+ny*ny)
if 0 < distance and distance <= 1300 then

// ->>
set distance = nx*nx+ny*ny
if 0 < distance and distance <= 1690000 then
lucky guess, is that 1,690,000 is 1,300^2...
all he did here is avoid using squareroot for that very little bit of speed juice...
although i find that a bit toooo speed-oriented and sort of needless, if u do want to squeeze every little bit of speed u could use it :) but don't forget to add a comment of what the value stands for :p


@Magtheridon:
if the spell works fine why would he want to use any of the 2 movement libraries u mentioned?
 
Level 10
Joined
Sep 19, 2011
Messages
527
Well, I make the spell with the CTL library and taking the base that Magtheridon96 gives to me. This was the result:

JASS:
library Rupture requires CTL
    globals
        // Rawcode of the Rupture ability
        private constant integer RUPTURE_RAWCODE = 'A000'
        // Rawcode of the Rupture buff
        private constant integer RUPTURE_BUFF_RAWCODE = 'B000'
        // Period in that the extra damage will be done
        private constant real PERIOD = 0.25
        // Special effect (blood)
        private constant string SPECIAL_EFFECT = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
        // Special effect attachment
        private constant string ATTACHMENT_POINT = "chest"
        // Rupture initial damage
        private constant real INITIAL_DAMAGE = 150.
        // Rupture attack type
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
        // Rupture damage type (universal = "pure")
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_UNIVERSAL
        // Do you want preload the special effect?
        private constant boolean PRELOAD = true
    endglobals
    
    // Returns the distance covered by the target
    // a_x and a_y represents the actual position of the target
    // x and y represents the position of the unit in the beggining of the timer
    // Remember, the x and y variables are updated every time when timer expires
    private function getDistance takes real x, real y, real a_x, real a_y returns real
        return SquareRoot((a_x - x) * (a_x - x) + (a_y - y) * (a_y - y))
    endfunction
    
    // Returns the initial damage
    private function getInitialDamage takes integer level returns real
        return INITIAL_DAMAGE + (level * 50)
    endfunction
    
    // Returns the damage by the distance covered by the target
    private function getDamage takes real distance, integer level returns real
        return (distance * (20 * level)) / 100
    endfunction
    
    // Returns the affected units
    private function affectedUnit takes unit target returns boolean
        return true
    endfunction
    
    private keyword Init
    
    private struct Spell extends array
        // Caster
        unit caster
        // Rupture level
        integer level
        // Target
        unit target
        // a = actual (actual x of the target)
        real a_x
        // actual y
        real a_y
        // x of target
        real x
        // y of target
        real y
        // period, represents the period
        // that the extra damage will be done (default: 0.25)
        real period
        
        implement CTL
            // Distance covered by the target
            local real distance
        
        implement CTLExpire
            // If the target still has the Rupture buff and is not dead...
            if 0 < GetUnitAbilityLevel(this.target, RUPTURE_BUFF_RAWCODE) and not(IsUnitType(this.target, UNIT_TYPE_DEAD)) then
                // If the PERIOD seconds was pass...
                if PERIOD < this.period then
                    // Reset period to 0
                    set this.period = 0.
                    // Actual X and Y of the target
                    set this.a_x = GetUnitX(this.target)
                    set this.a_y = GetUnitY(this.target)
                    
                    set distance = getDistance(this.x, this.y, this.a_x, this.a_y)
                    
                    // Make the extra damage only if distance is greater than 0
                    // but less than 1300
                    if 0 < distance and distance < 1300 then
                        call DestroyEffect(AddSpecialEffectTarget(SPECIAL_EFFECT, this.target, ATTACHMENT_POINT))
                        call UnitDamageTarget(this.caster, this.target, getDamage(distance, this.level), false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
                    endif
                else
                    // If the PERIOD seconds was not pass, add
                    // the period of the CTL timer (library)
                    set this.period = this.period + 0.031250000
                endif
                
                // Refreshing the coordenates of the target
                set this.x = this.a_x
                set this.y = this.a_y
            else
                set this.caster = null
                set this.target = null
                call this.destroy()
            endif
            
        implement CTLNull
        implement CTLEnd
        
        private static method run takes nothing returns boolean
            local thistype this
            
            // If the ability being cast is the Rupture and the target can be affected
            // (units that can be affected can be changed in the affectedUnit function)
            if GetSpellAbilityId() == RUPTURE_RAWCODE and affectedUnit(GetSpellTargetUnit()) then
                set this = thistype.create()
                set this.caster = GetTriggerUnit()
                set this.target = GetSpellTargetUnit()
                set this.level = GetUnitAbilityLevel(this.caster,RUPTURE_RAWCODE)
                set this.x = GetUnitX(this.target)
                set this.y = GetUnitY(this.target)
                
                // Make the initial damage
                call UnitDamageTarget(this.caster, this.target, getInitialDamage(this.level), false, false, ATTACK_TYPE, DAMAGE_TYPE, null)
            endif
            
            return false
        endmethod
        implement Init
    endstruct
    
    private module Init
        private static method onInit takes nothing returns nothing
            local trigger t = CreateTrigger()
            
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t,Condition(function thistype.run))
            
            // Preload the special effect...
            static if PRELOAD then
                call Preload(SPECIAL_EFFECT)
            endif
            
            set t = null
        endmethod
    endmodule
endlibrary

What do you think?

Greeting and thanks to all :D

------------------

EDIT: Other thing, can you tell me if I screw up in the english? :D thanks xD
 
JASS:
set this.a_x = GetUnitX(this.target)
set this.a_y = GetUnitY(this.target)

You really don't need these :p
You could declare 2 locals instead :p

And keep this in mind:

When you declare locals using CTL and you're going to set them to a value while depending on this, make sure you set them after implement CTLExpire ;)
(This is for future reference and could come in handy some day :p

Anyways, Good Job :)

Suggestions:
- Remove this global: private constant real PERIOD = 0.25 cause it isn't used anywhere >:p
 
Last edited:
Level 2
Joined
May 30, 2019
Messages
25
Hey all can you show me how to implement this spell to map. I dont know to import this spell to map and get error in trigger
 
Top