Spell Warp

Reaction score
341
Warp
TriggerHappy187

Spell Info:

Coding: vJASS
Requirements: TimerUtils
Description: Warps the unit to a point, damaging all the units that comes it the casters way.
Screenshot: (link)

attachment.php



Spell Code:

JASS:
library Warp initializer InitTrig requires TimerUtils

    globals
        private constant integer SPELL_ID = 'A000' // The raw ID of the spell
        
        private constant real TIMEOUT = 0.03 // How fast the timer runs
        private constant real FX_TIMEOUT = 0.05 // How fast the effects are created
        
        private constant real SPEED = 30 // How fast the caster is "Warped"
        private constant real DAMAGE_RADIUS = 300 // How close the units need to be to get damaged
        private constant real TARGET_RADIUS = 90 // How close to the destination the caster has to be for it to stop, just a safety global
        
        private constant string TRAIL_EFFECT = "Abilities\\Spells\\Human\\Invisibility\\InvisibilityTarget.mdl" // the warp effect
        
        private constant attacktype ATTACK = ATTACK_TYPE_MAGIC // the damage attack type
        private constant damagetype DAMAGE = DAMAGE_TYPE_UNIVERSAL // the damage damage type
    endglobals
    
    private constant function GetDamage takes integer level returns real
        return 5.*level
    endfunction
    
    private struct data
        unit caster
        
        real x
        real y
        
        real sin
        real cos
        
        real last
        
        static group g = CreateGroup()
        static data temp
        
        static real MapMaxX
        static real MapMinX
        static real MapMaxY
        static real MapMinY
        
        private static method True takes nothing returns boolean
            return true
        endmethod
        
        private static method mapbounds takes real x, real y returns boolean
            return x < data.MapMaxX or x > data.MapMinX or y < data.MapMaxY or y > data.MapMinY
        endmethod

        private static method fx takes nothing returns nothing
            local data d = GetTimerData(GetExpiredTimer())
            local real x1 = GetUnitX(d.caster)
            local real y1 = GetUnitY(d.caster)
            local real x = x1 + d.cos
            local real y = y1 + d.sin
            call GroupEnumUnitsInRange(data.g, d.x, d.y,  TARGET_RADIUS, Filter(function data.True))
            if not IsUnitInGroup(d.caster, data.g) then
                call DestroyEffect(AddSpecialEffect(TRAIL_EFFECT, x, y))
                return
            else
                call ReleaseTimer(GetExpiredTimer())
            endif
        endmethod
        
        private static method callback takes nothing returns nothing
            local data d = GetTimerData(GetExpiredTimer())
            local real x1 = GetUnitX(d.caster)
            local real y1 = GetUnitY(d.caster)
            local real x = x1 + d.cos
            local real y = y1 + d.sin
            local real dmg = GetDamage(GetUnitAbilityLevel(d.caster, SPELL_ID))
            local integer i = 0
            local unit u
            local real dis
            
            if data.mapbounds(x,y) then
                call SetUnitX(d.caster, x)
                call SetUnitY(d.caster, y)
            endif 

            set dis = SquareRoot((d.x - x1) * (d.x - x1) + (d.y - y1) * (d.y - y1))
            
            if dis <= TARGET_RADIUS or dis > (d.last+TARGET_RADIUS) then
                call ReleaseTimer(GetExpiredTimer())
                call d.destroy()
                return
            endif
            set d.last = dis
            
            call GroupEnumUnitsInRange(data.g, x1, y1,  DAMAGE_RADIUS, Filter(function data.True))
            
            loop
                set u = FirstOfGroup(data.g)
                exitwhen u == null
                call UnitDamageTarget(d.caster, u, dmg, true, false, ATTACK, DAMAGE, null)
                call GroupRemoveUnit(data.g, u)
            endloop
        endmethod
        
        static method create takes unit u, real x, real y returns data
            local data d = data.allocate()
            local real angle
            local timer t = NewTimer()
            local timer a = NewTimer()
            local real x1 = GetUnitX(u)
            local real y1 = GetUnitY(u)

            call SetTimerData(t, d)
            call SetTimerData(a, d)
            
            set d.x = x
            set d.y = y
            set d.caster = u
            
            call SetUnitX(d.caster, x1)
            call SetUnitY(d.caster, y1)
            call IssueImmediateOrder(d.caster, "stop")

            set x = x - x1
            set y = y - y1

            set d.last = SquareRoot(x*x+y*y)
            
            set angle = Atan2(y,x)
            set d.cos = SPEED * Cos(angle)
            set d.sin = SPEED * Sin(angle)
            
            call TimerStart(t, TIMEOUT, true, function data.callback)
            call TimerStart(a, FX_TIMEOUT, true, function data.fx)
            
            return d
        endmethod
        
    endstruct
    
    private function Actions takes nothing returns boolean
        local location l = GetSpellTargetLoc()
        if GetSpellAbilityId() == SPELL_ID then
            call data.create(GetTriggerUnit(), GetLocationX(l), GetLocationY(l))
        endif
        call RemoveLocation(l)
        set l = null
        return false
    endfunction

    //===========================================================================
    private function InitTrig takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(t, Condition(function Actions))
        set data.MapMaxX = GetRectMaxX(bj_mapInitialPlayableArea)-64.00
        set data.MapMaxY  = GetRectMaxY(bj_mapInitialPlayableArea)-64.00
        set data.MapMinY = GetRectMinX(bj_mapInitialPlayableArea)+64.00
        set data.MapMinX = GetRectMinY(bj_mapInitialPlayableArea)+64.0
    endfunction

endlibrary
 

Attachments

  • warp.jpg
    warp.jpg
    48 KB · Views: 737
  • Warp.w3x
    28.4 KB · Views: 303

trb92

Throwing science at the wall to see what sticks
Reaction score
142
In the "callback" method, you have
JASS:
call GroupEnumUnitsInRange(data.g, x1, y1,  90, Filter(function data.True))
call ForGroup(data.g, function data.damage)

Why don't you use this global there?
JASS:
private constant real DAMAGE_RADIUS = 300 // How close the units need to be to get damaged
 

Kenny

Back for now.
Reaction score
202
JASS:
library Warp initializer InitTrig requires TimerUtils


You do not need a library. I don't know why people think that they need to do that. Scopes are automatically put below libraries. I see little need in it to be honest.

JASS:
private constant function GetDamage takes real modifier, real level returns real
    return level*modifier
endfunction


Thats a bit messed up. Users can't currently change the damage as easily as they should be able to. You should make a the "modifier" a real value that can be changed and not have the 100 in the spell script below. Something like:

JASS:
private constant function GetDamage takes real level returns real
    return 100.00 * level
endfunction


JASS:
private static method damage takes nothing returns nothing
    local data d = data.temp
    local unit u = GetEnumUnit()
    local real dmg = GetDamage(100, GetUnitAbilityLevel(d.caster, SPELL_ID))
    call UnitDamageTarget(d.caster, u, dmg, true, false, ATTACK, DAMAGE, null)
endmethod


First off, You don't null u. Secondly, you should just do those functions in a FirstOfGroup() loop. Due to the (lack of) complexity of what is being done with the group, it would be easier and more efficient.

As its already been stated, you need to fix the radius of the GroupEnum functions to actually use a global value.

Your way of checking when to finish the spell is odd. In the (incredibly unlikely) situation that someone uses a speed of like 300 instead of a smaller number, the caster could just "skip" the target point and never stop.

And seeing as this spell has no SafeX/Y functions for border safety then that could become a problem. I guess that already is a little bit of a problem with this type of spell.

JASS:
private static method callback takes nothing returns nothing
    local data d = GetTimerData(GetExpiredTimer())
    local real x1 = GetUnitX(d.caster)
    local real y1 = GetUnitY(d.caster)
    local real x = x1 + d.cos
    local real y = y1 + d.sin
            
    call DestroyEffect(AddSpecialEffect(TRAIL_EFFECT, x, y))
    call GroupEnumUnitsInRange(data.g, d.x, d.y,  150, Filter(function data.True))
    call SetUnitX(d.caster, x)
    call SetUnitY(d.caster, y)

    if IsUnitInGroup(d.caster, data.g) then
        call ReleaseTimer(GetExpiredTimer())
        call d.destroy()
    endif
            
    // These things:
    set data.temp = d
    call GroupEnumUnitsInRange(data.g, x1, y1,  90, Filter(function data.True))
    call ForGroup(data.g, function data.damage)
endmethod


If d.destroy() is called, the stuff below my commented line are still called as well, and seeing as d does not exist anymore, that is a problem. Maybe just add a return or something under d.destroy().

JASS:
set angle = bj_RADTODEG * Atan2(y - y1, x - x1)
set d.cos = SPEED * Cos(angle * bj_DEGTORAD)
set d.sin = SPEED * Sin(angle * bj_DEGTORAD)


Take away the bj_DEGTORAD and bj_RADTODEG's...

You should also make weapontype configurable just for kicks :).

This spell would benefit from something like GTrigger (well all spells would). Maybe you should try implementing it. It would turn your init function to something like:

JASS:
private function InitTrig takes nothing returns nothing
    call GT_AddSpellEffectAction(function Actions,SPELL_ID)
endfunction


This spell is pretty basic, but if a few changes are made to it, it would be a nice resource.
 

BlackRose

Forum User
Reaction score
239
Strange, first time I tested it, it bugged and didn't stop moving at all. But now I cannot recreate this bug at all.

Anyways, hotkey doesn't work. It is B not W......?
The effect is ok, appealing XD
 
Reaction score
341
You do not need a library. I don't know why people think that they need to do that. Scopes are automatically put below libraries. I see little need in it to be honest.

It's just so if the user doesn't have the library a "missing requirement" error is easier to find the problem then "undefined function".

Everything else added, except for GTrigger. I don't want to add any more system requirements.
 

simonake

New Member
Reaction score
72
Maybe make the caster play an animation.

When it casted, she just stand here....
Maybe attack, slam?
 

Viikuna

No Marlo no game.
Reaction score
265
Yea, animation is must.

Also, you need to make it possible for users to have different effect creation timeout than dashing timeout. ( I always use .025 for moving units, and I dont wanna create effects every .025 seconds because it looks ugly as hell )

Aslo, you might check if unit is already damaged by the spell, so it wont get damaged many times: example

Unles you want it to damage units many times, which is kinda cool, because you need to do some aiming to deal as much damage as you can.
 
Reaction score
341
Also, you need to make it possible for users to have different effect creation timeout than dashing timeout.

Change the SPEED constant :p

Aslo, you might check if unit is already damaged by the spell, so it wont get damaged many times

I had that before the spell was released, just complicated the spell more. An easy way around this is just to make the damage lower.
 

Viikuna

No Marlo no game.
Reaction score
265
What I meant was that spell should maybe use different timer for creating effects, do we can have it to move unit every .025 sec and create effects every .045 or something like that.

Period for movement should be .03 or .025, otherwise it will look bad. Speed depends on gameplay stuff like balance and spell theme and everything. It still needs some way to change effect period without changing these.
 

Romek

Super Moderator
Reaction score
964
> GetDamage takes real level
I haven't seen a level 2.5 spell before.
(Level shouldn't be a real)

Also, instead of pointlessly using a library, how about making it clear that the spell requires TU, in the actual code?
 
Reaction score
341
I don't see the big deal in not using a library, it cleary states what it needs, and if you don't have that library it pJASS will tell you so.

Instead of a 'Undefined function' error.

I haven't seen a level 2.5 spell before.

Fixed.

Code updated, added FX_TIMEOUT constant.
 

Azlier

Old World Ghost
Reaction score
461
You should really calculate the distance upon casting, and slide the caster a certain direction until s/he(it) slides that distance exactly. Checking if the caster has reached the target spot is simple, yet totally breaks if you throw other slides and teleports into the mix.
 
Reaction score
341
Hotkey is still B, not W?

fixed.

You should really calculate the distance upon casting, and slide the caster a certain direction until s/he(it) slides that distance exactly. Checking if the caster has reached the target spot is simple, yet totally breaks if you throw other slides and teleports into the mix.

Added something similar to that.
 

Jesus4Lyf

Good Idea™
Reaction score
397
JASS:
            set d.last = SquareRoot((x - x1) * (x - x1) + (y - y1) * (y - y1))
            
            call SetUnitX(d.caster, x1)
            call SetUnitY(d.caster, y1)
            call IssueImmediateOrder(d.caster, "stop")
            
            set angle = bj_RADTODEG * Atan2(y - y1, x - x1)
            set d.cos = SPEED * Cos(angle * bj_DEGTORAD)
            set d.sin = SPEED * Sin(angle * bj_DEGTORAD)

Change to...
JASS:
            call SetUnitX(d.caster, x1)
            call SetUnitY(d.caster, y1)
            call IssueImmediateOrder(d.caster, "stop")

            set x=x-x1
            set y=y-y1

            set d.last = SquareRoot(x*x+y*y)
            
            set angle = Atan2(y,x)
            set d.cos = SPEED * Cos(angle)
            set d.sin = SPEED * Sin(angle)

In fact...
JASS:
            local real x1 = GetUnitX(u)
            local real y1 = GetUnitY(u)

Get rid of these and inline them into the
JASS:
            set x=x-x1
            set y=y-y1

lines.

Edit: Oh, and your constants are not stand-alone. They're interdependant. Changing the speed will change the damage, changing the timeout will change the speed, etc... =/
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • Monovertex Monovertex:
    How are you all? :D
    +1
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top