• 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.

Need a Spell [GUI or JASS or vJass]

Status
Not open for further replies.
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

blfh2vhyzbh2txwi1.png


In this image you see the full plan of my spell:

* Caster should cast an ability with damage and stunt on the target.
* When casting 2 firewaves ( the red lines ) are created at the caster position ( dummy unit because they should get permanent immolation )
*After those 2 firewaves reach the target, a fire circle is created around the target with the dummies in 200 AOE.
* The fire - wave dummies should stay for 3 seconds
* The fire - circle dummies should stay for 5 seconds
* MPI / MUI

===============================================
I tried it myself, but I was pissed after a longer time and delete this because it doesn't work, so I thought my one here can help me with that large spell ^^

The best would be vJass (ofc^^) but GUI / Jass is (ofc) welcome too!!

Greetings
~ The Bomb King > Dr. Boom
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
I might try to do this, but I'm not sure if I can complete this.

Are the firewaves homing? Ex: Do they follow the target unit or just stop at where the target was?

Does the fire circle move with the target or is it immobile?

Should there be two different immolation abilities for the two different fires?

Also, do you have any preferred name for this spell? Any preferred visuals?
 
Level 16
Joined
May 1, 2008
Messages
1,605
Moin moin =)

Yes the plan is that the wave are following the target until the wave reaches the target. ( Casting range should be 600 or 700 so in a 0.03 sec loop its fast ) When they reach the target the waves explode at the target position and creates a circle that stays at the creation region.

Also only 1 immolation ability and the name is just firewave - don't know a better one xD

Greetings
~ The Bomb King > Dr. Boom
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Hm, I'm not really proud of this one since the homing movement for the wave missiles can look strange depending on where the target unit is moving.
It's also probably inefficient compared to using an actual missile system, but I don't really know of an easy-to-use missile system that supports xy arcs.

Here's the code:
JASS:
//==========================================================================================
// Firewave v1.00 by watermelon_1234
//******************************************************************************************
// Libraries required: (Libraries with * are optional)
//  - ParabolicMovement
//  - TimerUtils
//  - xe system (xebasic, xefx, and *xepreload)
//##########################################################################################
// Importing:
//  1. Copy the abilities, Firewave and Firewave (Burn). Copy the buff Firewave Burn.
//  2. Copy this trigger.
//  3. Implement the required libraries.
//  4. Configure the spell.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Notes:
//  - You can modify the sfx for the fire in the Firewave Burn buff.
//  - z arc for wave missile isn't supported yet.
//  - Homing movement can be funky looking. It's probably because of the way I'm checking to
//    see if the wave missile reached the target
//==========================================================================================
scope Firewave initializer Init

    native UnitAlive takes unit id returns boolean // You can remove this line if you already have UnitAlive implemented or don't want to use it.
    
    // Provided in case you don't want to use UnitAlive
    private function IsUnitAlive takes unit u returns boolean
        return UnitAlive(u)
    endfunction
    
    globals
        private constant integer    SPELL_ID        = 'A000' // The raw id of the Firewave ability
        private constant integer    BURN_ID         = 'A001' // The raw id of the Firewave (Burn) ability
        private constant real       TIMER_LOOP      = 0.03 // How often the timer will loop for the spell's actions       
        // Wave settings
        private constant boolean    DO_PRELOAD      = true // Determines whether or not to preload the ability and the sfx. Needs xepreload if set to true.
        private constant string     WAVE_SFX        = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl" // The sfx for the wave missile.
        private constant real       WAVE_SCALE      = 1.5 // Scaling for wave missile
        private constant real       WAVE_HEIGHT     = 10 // The height for the wave missile
        private constant real       WAVE_FIRE_SPACE = 30 // The spacing there should be between each fire. How accurate the spacing is determined by TIMER_LOOP and the speed of the wave missiles.
        private constant integer    MAX_WAVE_NUMBER = 2 // The max number of wave missiles that can be created. 
        // Damage settings:
        private constant attacktype ATK_TYPE        = ATTACK_TYPE_NORMAL
        private constant damagetype DMG_TYPE        = DAMAGE_TYPE_UNIVERSAL
        private constant weapontype WPN_TYPE        = null
    endglobals
    
    // The damage dealt to the target upon impact.
    private constant function Damage takes integer lvl returns real
        return 15. + 85*lvl
    endfunction
    
    // The number of wave missiles that would be created.
    private constant function WaveNumber takes integer lvl returns integer
        return 2 + 0*lvl
    endfunction
    
    // The speed for the wave missile. In standard WC3 movement speed.
    private constant function WaveSpeed takes integer lvl returns real
        return 800. + 0*lvl
    endfunction
    
    // The xy arc for the wave. Bigger values make the waves wider.
    private constant function WaveXYArc takes integer lvl returns real
        return 200. + 0*lvl
    endfunction
    
    // The duration for the fire that's created from the wave.
    private constant function WaveDur takes integer lvl returns real
        return 3. + 0*lvl
    endfunction
          
    // The area of the ring of fire.
    private constant function RingArea takes integer lvl returns real
        return 200. + 0*lvl
    endfunction
    
    // The number of fires would be created in the ring.
    private constant function RingNumber takes integer lvl returns integer
        return 14 + 0*lvl
    endfunction
    
    // The duration for the fire created in a ring.
    private constant function RingDur takes integer lvl returns real
        return 5. + 0*lvl
    endfunction
    
    // Scaling for the fire sfx
    private constant function FireScale takes integer lvl returns real
        return 0.6 + 0*lvl
    endfunction

//==========================================================================================
// END OF CONFIGURATION
//==========================================================================================

    globals
        private constant real TWO_PI = 6.28319
    endglobals

    private constant function MissileDeviate takes integer n, integer tot returns real    
        if tot == 1 then
            return 0.
        else
            return -1. + (n*2.)/(tot-1.)
        endif
    endfunction
    
    // Struct for every fire instance that gets created.
    private struct Fire
        xefx fire
        timer tim
        
        static method create takes real x, real y, integer lvl, player p, real dur returns thistype
            local thistype this = thistype.allocate()
            set .fire = xefx.create(x,y,0)
            set .fire.abilityid = BURN_ID
            set .fire.abilityLevel = lvl
            set .fire.owner = p
            set .fire.scale = FireScale(lvl)
            
            set .tim = NewTimer()
            call SetTimerData(.tim,this)
            call TimerStart(.tim,dur,false,function thistype.onExpire)
            return this
        endmethod
        
        static method onExpire takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            call ReleaseTimer(.tim)
            call .fire.destroy()
            call .destroy()
        endmethod
    endstruct
    
    // Main struct with spell actions.
    private struct Data
        unit cast 
        integer lvl
        
        unit targ
        real targX
        real targY
        real targDist
        
        xefx array wave[MAX_WAVE_NUMBER]
        real array xyArc[MAX_WAVE_NUMBER]
        real x
        real y
        real dist = 0 // The distance the wave missiles have travelled.
        real count = 0 // Used to properly space out the fires
        integer num 
        real speed         
        
        timer tim
        
        static method create takes unit c, unit t returns thistype
            local thistype this = thistype.allocate()
            local real dx
            local real dy
            local real ang
            local integer i = 0   
            
            set .cast = c
            set .lvl = GetUnitAbilityLevel(.cast,SPELL_ID)
            set .x = GetUnitX(c)
            set .y = GetUnitY(c)
            
            set .targ = t   
            set .targX = GetUnitX(t)
            set .targY = GetUnitY(t)
            
            set dx = .targX-.x
            set dy = .targY-.y
            set .targDist = SquareRoot(dx*dx+dy*dy)
            
            set .num = WaveNumber(.lvl)
            set .speed = WaveSpeed(.lvl)*TIMER_LOOP
            set ang = Atan2(dy,dx)
            loop
                set .wave[i] = xefx.create(.x,.y,ang)
                set .wave[i].fxpath = WAVE_SFX
                set .wave[i].scale = WAVE_SCALE
                set .wave[i].z = WAVE_HEIGHT
                set .xyArc[i] = WaveXYArc(.lvl)*MissileDeviate(i,.num)
                set i = i + 1
                exitwhen i == .num
            endloop
            
            set .tim = NewTimer()
            call SetTimerData(.tim,this)
            call TimerStart(.tim,TIMER_LOOP,true,function thistype.onLoop)
            return this
        endmethod
        
        static method onLoop takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            local real newX
            local real newY
            local real ang
            local integer i = 0
            local real xyArc
            local boolean createFire = false

            if .targ != null then
                if not IsUnitAlive(.targ) then
                    set .targ = null                    
                else
                    set newX = GetUnitX(.targ)
                    set newY = GetUnitY(.targ)
                    
                    set .targDist = .targDist + SquareRoot((newX-.targX)*(newX-.targX)+(newY-.targY)*(newY-.targY))
                    set .targX = newX
                    set .targY = newY
                endif
            endif           
            if .dist + .speed < .targDist then 
                if .count == 0 then
                    set createFire = true
                endif
                
                set ang = Atan2(.targY-.y,.targX-.x)
                set .x = .x + .speed*Cos(ang)
                set .y = .y + .speed*Sin(ang)    
                
                loop
                    set xyArc = ParabolaZ(.xyArc[i],.targDist,.dist)
                    set .wave[i].x = .x + xyArc*Cos(ang+0.5*bj_PI)
                    set .wave[i].y = .y + xyArc*Sin(ang+0.5*bj_PI)
                    if createFire then
                        call Fire.create(.wave[i].x,.wave[i].y,.lvl,GetOwningPlayer(.cast),WaveDur(.lvl))
                    endif
                    set i = i + 1
                    exitwhen i == .num
                endloop
                
                set .dist = .dist + .speed
                set .count = .count + .speed
                if .count >= WAVE_FIRE_SPACE then
                    set .count = 0
                endif
            else
                if IsUnitAlive(.targ) then
                    call UnitDamageTarget(.cast,.targ,Damage(.lvl),false,true,ATK_TYPE,DMG_TYPE,WPN_TYPE)                    
                endif
                
                loop
                    set .wave[i].x = .targX
                    set .wave[i].y = .targY
                    call .wave[i].destroy()
                    set i = i + 1
                    exitwhen i == .num
                endloop
                
                set i = 0
                loop
                    set newX = .targX + RingArea(.lvl)*Cos(TWO_PI/RingNumber(.lvl)*i)
                    set newY = .targY + RingArea(.lvl)*Sin(TWO_PI/RingNumber(.lvl)*i)
                    call Fire.create(newX,newY,.lvl,GetOwningPlayer(.cast),RingDur(.lvl))
                    set i = i + 1
                    exitwhen i == RingNumber(.lvl)
                endloop
                call ReleaseTimer(.tim)
                call .destroy()
            endif
        endmethod
        
        static method spellActions takes nothing returns boolean
            if GetSpellAbilityId() == SPELL_ID then
                call thistype.create(GetTriggerUnit(),GetSpellTargetUnit())
            endif
            return false
        endmethod
    endstruct  
    
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,Condition(function Data.spellActions))
        
        static if DO_PRELOAD then
            call XE_PreloadAbility(BURN_ID)
            call Preload(WAVE_SFX)
            call PreloadStart()
        endif
    endfunction
endscope
 

Attachments

  • Firewave.w3x
    62.1 KB · Views: 55
Status
Not open for further replies.
Top