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

[vJass] Demon Slash

Demon Slash fully MUI and in vJass (requires JNGP to work well)
created for Nightbrowlers request

How to import? very easy....
simply copy the trigger into your map, create a dummy unit for the demon and adjust the variables in the setup part so they fit your map :D

The hero channels some time while a demon rises behind him...
then he slashes with the demons power through his enemies, slaughtering them.

Demon Slash
After summoning a demon, supporting him with power, the hero slashes through numerous enemys dealing aoe damage.
If the hero hits an obstacle he stops.
v.2.0: Major Update: code reworked and improved many things, changed the name and added things like pathability check...
v.3.0: Reworked the whole code cause it was crap :D Fixed some bugs too


JASS:
library DemonSlash requires RegisterPlayerUnitEvent, T32
// Demon Slash by The_Witcher
//       The hero slashes through numerous enemys dealing aoe damage.
//       When the hero crashes into an obstacle he stops.
//
// well not much to say look through/edit the setup part for your wishes
//
// The SETUP part
    globals
    // the rawcode of the ghost/demon appearing behind the caster when channeling
        private constant integer DEMON_DUMMY_ID = 'h000'
                  
    // the rawcode and the order string of the Demon Slash ability
        private constant integer ABILITY_ID = 'A000'
        private constant string ORDER_STRING = "absorb"
      
    // the size the dummy will be when fully grown (2 = 200%)                 
        private constant real MAX_SIZE = 2
    
    //the effect created when a unit is hit         
        private constant string BLOOD_EFFECT = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
    
    //the effect created on the weapon of the caster
        private constant string WEAPON_EFFECT = "Abilities\\Weapons\\ZigguratMissile\\ZigguratMissile.mdl"
    
    //the effect created on the body of the caster            
        private constant string BODY_EFFECT = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilMissile.mdl"
    
    //the effect created when the dummy disappears cause of abort      
        private constant string ABORT_EFFECT = "Abilities\\Spells\\Undead\\CarrionSwarm\\CarrionSwarmDamage.mdl"
    endglobals

    private function GetDamage takes integer level returns real
        return 120.00 + 50 * (level - 1) //120 on level 1, 170 level 2, 220 level 3, ...
    endfunction

    private function GetAOE takes integer level returns real
        return 100.00 + 20 * level //120 on level 1, 140 level 2, 160 level 3, ...
    endfunction

    private function GetSlashDistance takes integer level returns real
        return 500.0 + 100 * level //600 on level 1, 700 level 2, 800 level 3, ...
    endfunction
    
    private function GetSlashSpeed takes integer level returns real
        return 700.0 + 100 * level //800 on level 1, 900 level 2, 1000 level 3, ...
    endfunction

    private function GetChannelTime takes integer level returns real
        return 4.00 - level / 2 //3, 5 on level 1, 3 level 2, 2, 5 level 3, ...
    endfunction

//============================================================================== 
//=========================   SETUP END   ====================================== 
//============================================================================== 

    private struct spell
        static group g
        static item ite
        static unit Temp
        static boolexpr BoolExpr
        unit u
        unit dummy
        real v
        real d
        real vx
        real vy
        real phase
        real temp
        integer level
        effect bodyFX
        effect weaponFX
        group damaged
        
        method IsCoordPathable takes real x, real y returns boolean
            local real xx
            local real yy
            call SetItemVisible(.ite, true)
            call SetItemPosition(.ite, x, y)
            set xx = GetItemX( .ite ) - x
            set yy = GetItemY( .ite ) - y
            call SetItemVisible(.ite, false)
            if xx < 1 and xx > -1 and yy < 1 and yy > -1 then
                return true
            endif
            return false
        endmethod

        method periodic takes nothing returns nothing
            local unit k = null
            if .phase == 0 then // phase 1
                if GetUnitCurrentOrder(.u) == OrderId(ORDER_STRING) then
                    call SetUnitVertexColor(.dummy, 255, 255, 255, R2I(.temp / 100 * 255))
                    call SetUnitScalePercent(.dummy, .temp * MAX_SIZE, .temp * MAX_SIZE, .temp * MAX_SIZE)
                    set .temp = .temp + 100 / GetChannelTime(.level) * T32_PERIOD
                    if .temp >= 100 then
                        set .phase = 1
                        set .temp = 0
                        set .weaponFX = AddSpecialEffectTarget(WEAPON_EFFECT, .u, "weapon")
                        set .bodyFX = AddSpecialEffectTarget(BODY_EFFECT, .u, "chest")
                        call IssueImmediateOrder(.u,"stop")
                        call PauseUnit(.u, true)
                        call SetUnitInvulnerable(.u, true)
                        call SetUnitAnimation(.u, "attack")
                        call SetUnitAnimation(.dummy, "attack")
                        call QueueUnitAnimation(.dummy,"stand")
                    endif
                else
                    call DestroyEffect(AddSpecialEffect(ABORT_EFFECT, GetUnitX(.dummy), GetUnitY(.dummy)))
                    call RemoveUnit(.dummy)
                    call DestroyGroup(.damaged)
                    call .stopPeriodic()
                    call .destroy()
                endif
            else // phase 2
                call SetUnitVertexColor(.dummy, 255, 255, 255, R2I((100 - .temp) / 100 * 255))
                set .temp = .temp + 400 / GetChannelTime(.level) * T32_PERIOD
                if .d > 0 and IsCoordPathable(GetUnitX(.u) + .vx, GetUnitY(.u) + .vy) then
                    call SetUnitX(.u, GetUnitX(.u) + .vx )
                    call SetUnitY(.u, GetUnitY(.u) + .vy )
                    set .d = .d - .v
                    set .Temp = .u
                    call GroupEnumUnitsInRange(.g, GetUnitX(.u), GetUnitY(.u), GetAOE(.level), .BoolExpr)
                    loop
                        set k = FirstOfGroup(.g)
                        exitwhen k == null
                        call GroupRemoveUnit(.g, k)
                        if not IsUnitInGroup(k, .damaged) then
                            call GroupAddUnit(.damaged, k)
                            call UnitDamageTarget( .u, k, GetDamage(.level), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS )
                            call DestroyEffect(AddSpecialEffectTarget(BLOOD_EFFECT, k, "chest"))
                        endif
                    endloop
                else
                    call PauseUnit(.u, false)
                    call SetUnitAnimation(.u, "stand")
                    call SetUnitInvulnerable(.u, false)
                    call DestroyEffect(.weaponFX)
                    call DestroyEffect(.bodyFX)
                    call RemoveUnit(.dummy)
                    call DestroyGroup(.damaged)
                    call .stopPeriodic()
                    call .destroy()
                endif
            endif
        endmethod
        
        implement T32x

        private static method create takes unit caster, real tx, real ty returns spell
            local spell this = spell.allocate()
            local real x = GetUnitX(caster)
            local real y = GetUnitY(caster)
            local real r = Atan2(ty - y, tx - x)
            set .u = caster
            set .level = GetUnitAbilityLevel(.u, ABILITY_ID)
            set .v = GetSlashSpeed(.level) * T32_PERIOD
            set .vx = .v * Cos(r)
            set .vy = .v * Sin(r)
            set x = x + 200 * Cos(r - bj_PI)
            set y = y + 200 * Sin(r - bj_PI)
            set .dummy = CreateUnit(GetOwningPlayer(caster), DEMON_DUMMY_ID, x, y, r * bj_RADTODEG)
            call PauseUnit(.dummy, true)
            call SetUnitVertexColor(.dummy, 255, 255, 255, 0)
            set .phase = 0
            set .temp = 0
            set .d = GetSlashDistance(.level)
            set .damaged = CreateGroup()
            call .startPeriodic()
            return this
        endmethod
        
        private static method cast takes nothing returns nothing
            if GetSpellAbilityId() == ABILITY_ID then
                call spell.create(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
            endif
        endmethod

        private static method AllyFilter takes nothing returns boolean
            return ( IsUnitAlly(GetFilterUnit(), GetOwningPlayer(.Temp)) == false ) and not (IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) or GetUnitTypeId(GetFilterUnit()) == 0 )
        endmethod

        private static method onInit takes nothing returns nothing
            call RegisterPlayerUnitEvent( EVENT_PLAYER_UNIT_SPELL_CAST, function spell.cast )
            set .BoolExpr = Condition(function spell.AllyFilter)
            set .ite = CreateItem( 'wolg', 0, 0 )
            call SetItemVisible(.ite, false)
            set .g = CreateGroup()
        endmethod

    endstruct

endlibrary


//Code indented using The_Witcher's Script Language Aligner
//Download the newest version and report bugs at www.hiveworkshop.com

Keywords:
one, piece, oni, giri, demon, ghost, slash, strike, vjass, mui, mpi
Contents

Demon Slash (Map)

Reviews
00:27, 31st Dec 2009 TriggerHappy: You still need to use a global group. But whatever.

Moderator

M

Moderator

00:27, 31st Dec 2009
TriggerHappy:

You still need to use a global group. But whatever.
 
Level 15
Joined
Jul 6, 2009
Messages
889
The only problem I have with your coding (Well, that I can see right now, haven't checked thoroughly) is the layout. Global constants should be capitals, its a NAMING_CONVENTION.
JASS:
    private constant boolean pause = false // VERY IMPORTANT: false = when the caster channels the spell, you can still give him orders.
                                                                      // when you give an order the caster stops channeling and aborts the spell
                                                                      // BUT the caster must have [Can Flee = False] in the object editor
                                                                      // true = the caster will be paused while channeling, you can't order him and the spell
                                                                      // can't be aborted
You don't think it'd look better as:
JASS:
    private constant boolean pause = false 
    // VERY IMPORTANT: false = when the caster channels the spell, you can still give him orders.
    // when you give an order the caster stops channeling and aborts the spell
    // BUT the caster must have [Can Flee = False] in the object editor
    // true = the caster will be paused while channeling, you can't order him and the spell
    // can't be aborted
 
Level 8
Joined
Apr 8, 2009
Messages
499
in Rpg's its quite possible to bug with this spell, imagine flying over/trough mountains, out/in of dungeons.

needs fixing.

anyways, gj on spell, i'm probably also gonna use it my map :)
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
The spell could use ome improvements:

  • You can't charge through items, even though items do not block unit pathing. You need to hide items around the pathing item temporarily
  • SetItemPosition makes items visible automatically
  • The pathing could do this: return xx < 1 and xx > -1 and yy < 1 and yy > -1
  • Use the native for setting the scale of the unit, SetUnitScale
  • Don't pause the unit. Pause unit is not for spells. It pauses buffs for example. Use SetUnitPropWindow(unit, 0) and SetUnitTurnSpeed(unit, 0) for example to disable moving and turning
  • Null the destroyed groups
  • Null the unit struct memebers before calling destroy()
  • The dummy doesn't need invulnerability ability, it has locust
  • The dummy's death type hould be can't raise, does not decay. Now it stays there for over 90 seconds after dying for no reason
  • The dummy uses upgrades and gives lot of vision
  • You could utilize the Casting time for Channel ability for the channeling time as it is mean just for that and use different channel animation
  • Put some effort in tooltips
 
Top