• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] Berserkers Leap ver. 0.01.01[BETA]

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
*******************************
Writer's note:
This is a spell I began working on about 7-8 months ago, near the end of my "career" in WC3, of course I didn't have anything approved here on hive, but I still found it fun to script. I thought of the idea for this spell mainly because I wanted to create a spell or ability that made the caster leap into the air and land, damaging enemy units near it, and doing some other stuff.
I stopped working on the spell mainly because I didn't understand how I could make it look like he was leaping, and I was getting bored with WC3 mapping. But then a couple of days ago a friend of mine got me back into this whole scripting thing again, so I thought "Hey, why not finish this spell?!" and so I began working on the roughly made spell once again, and now I feel like I can present a half-good, half-bad spell to you guys^^
*******************************

JASS:
library BerserkersLeap initializer Init needs TimerUtils
globals
    private     constant    integer     RAWCODE     =   'A000'//Put your spell's RawCode here:)
    private                 group       aGroup      =   CreateGroup()//Do not do anything with this:)
    private     constant    string      EFFECT      =   "Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl"
    private                 group       dGroup      =   CreateGroup()//Do not edit this
    private     constant    integer     DUMMY_ID    =   'h001'//Put the dummy RAWCODE here
    private     constant    integer     DA_RAWCODE  =   'A002'// Put the Dummy Abillity Rawcode here
    private     constant    real        SPEED       =   10.
    private                 timer       SpellTimer
    private                 location    SpellLoc    =   Location( 0., 0.)
    endglobals

private function Damage takes integer level returns real
    return (level * 125.)
endfunction




private struct leap
    private unit Caster
            integer level
            real CasterX
            real CasterY
            real TargetX
            real TargetY
            real Angle
            real RangeFromTarget
            real RangeCheck
            unit Target

    static method GetParabolaZ takes real x, real d, real h returns real
        return (4. * h * x * (d - x) / (d * d))
    endmethod

    static method Actions takes nothing returns nothing
        local thistype this = GetTimerData(SpellTimer)
        local unit Dummy//This is just a local we'll use in the DummyCreation.
        local real DummyX
        local real DummyY 
        local real CastX
        local real CastY
        local real DisMissle
        local real Degrees
        local real DummyAngle//This is the angle the Dummies are made to shoot towards, no need to do anything here...
        local integer int = 12//this is the ammount of dummies thats created that will shoot the shockwaves
        set .RangeCheck = .RangeCheck + SPEED
        set .CasterX = .CasterX + SPEED * Cos(.Angle * bj_DEGTORAD)
        set .CasterY = .CasterY + SPEED * Sin(.Angle * bj_DEGTORAD)
        call SetUnitX(.Caster, .CasterX)
        call SetUnitY(.Caster, .CasterY)
        set DisMissle = (.TargetX - .CasterX) + (.TargetY - .CasterY)
        if  0. >= DisMissle then
            set DisMissle = DisMissle * -1.
        endif
        call SetUnitFlyHeight( .Caster, GetParabolaZ( DisMissle, .RangeFromTarget, 550.), 0.)
        if(.RangeCheck >= .RangeFromTarget) then
            set Degrees = .Angle
            call SetUnitFlyHeight( .Caster, 0., 0)
            call SetUnitTimeScale( .Caster, 1.)
            call GroupEnumUnitsInRange(aGroup, .CasterX, .CasterY, 250., null)
            call DestroyEffect(AddSpecialEffect(EFFECT, .CasterX,.CasterY))
//****************************************************************************************
//***************************************** DUMMY*****************************************
//***************************************** CREATION**************************************
//*****************************************  Loop ****************************************
//****************************************************************************************
            loop
                set int = int - 1
                exitwhen int == 0
                set Degrees = Degrees + 30
                set DummyX = .CasterX + 100 * Cos(Degrees)
                set DummyY = .CasterY + 100 * Sin(Degrees)
                set Dummy = CreateUnit(GetOwningPlayer(.Caster), DUMMY_ID, DummyX, DummyY,  Cos(Atan2(DummyY - .CasterY, DummyX - .CasterX)))
                set CastX = DummyX + Cos(Atan2( DummyY - .CasterY, DummyX - .CasterX))
                set CastY = DummyY + Sin(Atan2( DummyY - .CasterY, DummyX - .CasterX))
                call UnitAddAbility( Dummy, DA_RAWCODE)
                call SetUnitAbilityLevel( Dummy, DA_RAWCODE, .level)
                call IssuePointOrder( Dummy, "shockwave", CastX, CastY)
                call UnitApplyTimedLife( Dummy, 'BTLF', 0.50)

            endloop
//****************************************************************************************
//***************************************** TARGET****************************************
//***************************************** DAMAGING**************************************
//*****************************************  Loop ****************************************
//****************************************************************************************
            loop
                set .Target = FirstOfGroup(aGroup)
                exitwhen (.Target == null)
                if(IsUnitEnemy(.Target, GetOwningPlayer(.Caster)) == true) then
                    call UnitDamageTarget(.Caster, .Target, Damage(.level), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
                endif
                call GroupRemoveUnit(aGroup, .Target)
                set .Target = null
            endloop
            call ReleaseTimer(SpellTimer)
            set Dummy = null
        endif
    endmethod
    
    static method create takes nothing returns thistype
        local thistype this = thistype.allocate()
        set SpellTimer = NewTimer()
        set .Caster = GetTriggerUnit()
        set .CasterX      = GetUnitX(.Caster)
        set .CasterY      = GetUnitY(.Caster)
        set .TargetX      = GetSpellTargetX()
        set .TargetY      = GetSpellTargetY()
        set .level        = GetUnitAbilityLevel(.Caster, RAWCODE)
        set .Angle        = bj_RADTODEG * Atan2(.TargetY - .CasterY, .TargetX - .CasterX)
        set .RangeFromTarget = SquareRoot((.CasterX - .TargetX) * (.CasterX - .TargetX) + (.CasterY - .TargetY) * (.CasterY - .TargetY))
        call MoveLocation( SpellLoc, .TargetX, .TargetY)
        call UnitAddAbility(.Caster, 'Arav')
        call UnitRemoveAbility(.Caster, 'Arav')
        call SetTimerData(SpellTimer, this)
        call SetUnitTimeScale( .Caster, 50. * 0.01)
        call TimerStart(SpellTimer, 0.01, true, function leap.Actions)
        return this
    endmethod
endstruct

private function C takes nothing returns boolean
    if (GetSpellAbilityId() == RAWCODE) then
        call leap.create()
    endif
    return false
endfunction


//===========================================================================
function Init takes nothing returns nothing
    local trigger Berserk = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( Berserk, EVENT_PLAYER_UNIT_SPELL_CAST)
    call TriggerAddCondition( Berserk, Condition(function C))
    call Preload(EFFECT)
    set bj_lastCreatedUnit = CreateUnit(Player(15), 'h001', 0., 0., 270.)
    call UnitAddAbility(bj_lastCreatedUnit, RAWCODE)
    call UnitRemoveAbility(bj_lastCreatedUnit, RAWCODE)
    call RemoveUnit(bj_lastCreatedUnit)
endfunction
endlibrary


Spell Description:
Berserkers Leap
The hero leaps towards a point, damaging the units close to the landing spot, dealing damage and sends out twelve shockwaves, each dealing damage.

Initial Damage:
Lvl 1: 150
Lvl 2: 300
lvl 3: 450

Shock wave damage:
lvl 1: 50
lvl 2: 100
lvl 3: 150


Needs Jass NewGen Pack for vJASS Link: http://www.wc3c.net/showthread.php?t=90999

Uses the script called TimerUtils by Vaxarion Link: http://www.wc3c.net/showthread.php?t=101322
Uses the GetParabolaZ function by D4RK_GANDALF

Credits:
Vaxarion for TimerUtils and vJASS
D4RK_GANDALF for his awesome Parabola function
and xDardas for pointing me in the direction of the Parabola function^^

You are allowed to use the spell in any map, credits may be given but are not necessarily.
DO NOT DISTRIBUTE TO OTHER WEBSITES WITHOUT MY PERMISSION!


Thanks for looking at my spell^^

Change log:
ver. 0.01.01: Changed the few things written in the comments so far^^
ver 0.01: Uploaded to Hiveworkshop.

Keywords:
berserker, leap, jump, high, Warcraft, damage, spell, I, Wuw, you
Contents

Berserkers Leap (Map)

Reviews
12th Dec 2015 IcemanBo: For too long time as NeedsFix. Rejected. 04:35, 12th Dec 2015 IcemanBo:

Moderator

M

Moderator

12th Dec 2015
IcemanBo: For too long time as NeedsFix. Rejected.

04:35, 12th Dec 2015
IcemanBo:
 
Level 17
Joined
Mar 17, 2009
Messages
1,350
Some minor issues that don't even matter whether you fix them or not, just for the sake of pointing them out to you:

To start off with, I don't think you need to remove the ability of a preloaded unit before removing it from the game, just remove the unit ;)

JASS:
call SetUnitTimeScale( .Caster, 100 * 0.01)
100 * 0.01 = 1... just put 1 :p

JASS:
            loop
                set int = int - 1
                exitwhen int == 0
                set Degrees = Degrees + 30
                set DummyX = .CasterX + 100 * Cos(Degrees)
                set DummyY = .CasterY + 100 * Sin(Degrees)
                set Dummy = CreateUnit(GetOwningPlayer(.Caster), DUMMY_ID, DummyX, DummyY,  Cos(Atan2(DummyY - .CasterY, DummyX - .CasterX)))
                set CastX = DummyX + Cos(Atan2( DummyY - .CasterY, DummyX - .CasterX))
                set CastY = DummyY + Sin(Atan2( DummyY - .CasterY, DummyX - .CasterX))
                call UnitAddAbility( Dummy, DA_RAWCODE)
                call SetUnitAbilityLevel( Dummy, DA_RAWCODE, .level)
                call IssuePointOrder( Dummy, "shockwave", CastX, CastY)
                call UnitApplyTimedLife( Dummy, 'BTLF', 0.50)
                set Dummy = null
            endloop

no need to null the Dummy local in the loop as it will be overwritten when you use it...
just null locals at the very end of the function you're using them in :)

JASS:
WEAPON_TYPE_WHOKNOWS
just use null ;)

Didn't test it but that's what i got from skimming the code :)
 
Just skimmed through the code:

- Since this has requirements, I'd recommend using a library instead of a scope.
- structMembersShouldBeWrittenLikeThis
- Use null instead of WEAPON_TYPE_WHOKNOWS. They both do the same thing but WEAPON_TYPE_WHOKNOWS consumes RAM unlike 'null'
- Use a local trigger in the Init function cause using the global is way too messy and depends on the name of the trigger.
- 0 == int is faster than int == 0 for unknown reasons, but it's most likely due to Hardware
 
Level 10
Joined
Jan 24, 2009
Messages
606
Just skimmed through the code:

- Since this has requirements, I'd recommend using a library instead of a scope.
- structMembersShouldBeWrittenLikeThis
- Use null instead of WEAPON_TYPE_WHOKNOWS. They both do the same thing but WEAPON_TYPE_WHOKNOWS consumes RAM unlike 'null'
- Use a local trigger in the Init function cause using the global is way too messy and depends on the name of the trigger.
- 0 == int is faster than int == 0 for unknown reasons, but it's most likely due to Hardware

So let me see, the 0 == int is in the Absolute if/then/else and why do I have to write struct members in that way? I haven't seen any requirements for it anywhere, but I can do it, I just don't see why.

I'll use the Local trigger inside the init function, I usually do but I don't know why I didn't here, obviously I did not^^

Update: I updated the spell with the things you guys said, and I now hope you're happy^^
 
• There are some casts that don't land the hero back, unless he casts the spell again. What is more, the parabola doesn't always happen.

• You had better make the shockwave order a global and the amount of dummies to cast the shockwave(s) (which by extension requires the modification of angle: 360/NumberOfDummies).

JASS:
        call UnitAddAbility(.Caster, 'Arav')
        call UnitRemoveAbility(.Caster, 'Arav')
I suggest viewing this tutorial: http://www.hiveworkshop.com/forums/tutorial-submission-283/how-give-unit-ability-fly-201936/

Important: Check if the SpellTargetX() and SpellTargetY() are equal to GetUnitX(.caster) and GetUnitY(.caster), because it moves him out of map's boundaries.

• Make the dummies face Degrees variable, no need for that double function call.
 
Level 10
Joined
Jan 24, 2009
Messages
606
• There are some casts that don't land the hero back, unless he casts the spell again. What is more, the parabola doesn't always happen.

• You had better make the shockwave order a global and the amount of dummies to cast the shockwave(s) (which by extension requires the modification of angle: 360/NumberOfDummies).

JASS:
        call UnitAddAbility(.Caster, 'Arav')
        call UnitRemoveAbility(.Caster, 'Arav')
I suggest viewing this tutorial: http://www.hiveworkshop.com/forums/tutorial-submission-283/how-give-unit-ability-fly-201936/

Important: Check if the SpellTargetX() and SpellTargetY() are equal to GetUnitX(.caster) and GetUnitY(.caster), because it moves him out of map's boundaries.

• Make the dummies face Degrees variable, no need for that double function call.

hmm... Well I'll do that, but I don't really know why the parabola doesn't always happen, I have a small clue why though, I think it's because sometime it's a negative - a positive coordinate which makes the parabola not work properly, I think I can make it work though, but it needs testing so can take a while.
and I'm not really sure what you meant by the important notice, I think you meant when the spell was complete but I am not sure^^

Hmm I would like if you explained a bit more on the dummies/shockwave thing but I might know what you mean, I believe I know what you mean.

And Thanks for the Pheed back, I love it^^

Update: Hmm, I find that strange, I just added a BJDebugMsg and then suddenly the code stopped working as it should, It would never stop moving the unit. then I put the BJDebugMsg into a comment and all ran just fine. I wonder why...
 
Last edited:
0.01 for the timeout ? You don't need something so fast!

1) Don't use TimerUtils for something so low of a timeout

2) That should be configurable.

variablesAndMethodsAreWrittenLikeThis NotLikeThis.

Your indentation is messed up.

You don't need "call UnitRemoveAbility(bj_lastCreatedUnit, RAWCODE)" in the init function.

The type of dummy unit should be configurable.
 
Top