Simple Missile Spell

jhnam95

Active Member
Reaction score
12
Could anyone help me (or better yet show me a sample) of creating a simple missile spell in JASS? I can do it using GUI by using a periodic timer event, but that requires 2 separate triggers (and is detrimental to learning JASS :( ). I'm looking for a method of creating one using Timers instead. I tried opening a few maps but they're all protected (no surprise there) and I tried looking at a few systems such as Projectile, but it proved too be too diffcult.

I'm looking for a projectile that goes through the targets like Shockwave, but it won't matter if it's stops at the target since I (hopefully) can change it.
 

jhnam95

Active Member
Reaction score
12
BUMP. I don't necessarily need a template. Just a "how to" for using Timers would be good enough. Or a link to a useful tutorial. Most JASS tutorials don't cover how to use Timers.
 

Laiev

Hey Listen!!
Reaction score
188
some spell made by BlackRose (i think D: ) and edited 'a bit'


JASS:
scope MissileLineBomb initializer Init //requires KT

native UnitAlive takes unit id returns boolean //Comment this if already got it in your map

globals
                                                //ID of Ability
    private constant integer    SPELL_ID        = 'A000'
    
                                                //ID of Dummy
    private constant integer    MISSILE_ID      = 'h000'
    
                                                //Effect when hit the target, use "" to no effect
    private constant string     DAMAGE_SFX      = "Abilities\\Spells\\NightElf\\SpiritOfVengeance\\SpiritOfVengeanceOrbs3.mdl"
                                                //Same /\
    private constant string     DAMAGE_SFX2     = "Abilities\\Spells\\NightElf\\SpiritOfVengeance\\SpiritOfVengeanceOrbs5.mdl"
                                                //Attachment position
    private constant string     ATH_POINT       = "chest"
    
                                                //Timer count to the timer, don't change if you don't know
    private constant real       TIMER_INTERVAL  = 0.035
    
                                                //Distance base
    private constant real       DISTANCE        = 800.
                                                //Speed of missile
    private constant real       SPEED           = 30.
                                                //Area of Effect which will get random unit
    private constant real       AOE             = 140.
    
                                                //Attack type
    private constant attacktype ATK_TYP         = ATTACK_TYPE_NORMAL
                                                //Damage type
    private constant damagetype DMG_TYP         = DAMAGE_TYPE_MAGIC
                                                //Weapon type
    private constant weapontype WPN_TYP         = null
endglobals
    
private function GetDamage takes integer Level returns real
    return Level * 90. //Damage per level
endfunction

private function GetDistance takes integer Level returns real
    return Level * 300 + DISTANCE //Distance per level
endfunction

  //==========================================================================\\
 //========================== Don't Touch Below This ==========================\\
//==============================================================================\\
globals
    private group G = CreateGroup()
    private player TempPlayer
endglobals

private function Cond takes nothing returns boolean
    return GetSpellAbilityId() == SPELL_ID
endfunction

private struct data
    unit Missile
    
    real FailSafeDistCounter = 0
    
    real TargX
    real TargY
    real Angle
    real CX
    real CY
    
    real Cosine
    real Sine
    
    boolean MissileDone = false

    unit Caster
    player Owner
    
    static method create takes nothing returns thistype
        local thistype d = thistype.allocate()
        local real dx
        local real dy
        
        set d.Caster = GetTriggerUnit()
        set d.Owner = GetOwningPlayer(d.Caster)
        
        set d.CX = GetUnitX(d.Caster)
        set d.CY = GetUnitY(d.Caster)
        
        set dx = GetSpellTargetX() - GetUnitX(d.Caster)
        set dy = GetSpellTargetY() - GetUnitY(d.Caster)
        
        if SquareRoot(dx * dx + dy * dy) <= 20 then
            set d.Angle = GetRandomReal(GetUnitY(d.Caster), GetUnitX(d.Caster))
        else
            set d.Angle = Atan2( GetSpellTargetY() - d.CY, GetSpellTargetX() - d.CX )
        endif
        
        set d.Cosine = Cos(d.Angle)
        set d.Sine   = Sin(d.Angle)
        set d.TargX  = d.CX + GetDistance(GetUnitAbilityLevel(d.Caster, SPELL_ID)) * d.Cosine
        set d.TargY  = d.CY + GetDistance(GetUnitAbilityLevel(d.Caster, SPELL_ID)) * d.Sine
        
        set d.Missile = CreateUnit(d.Owner, MISSILE_ID, d.CX, d.CY, bj_RADTODEG * d.Angle)
        
        return d
    endmethod
endstruct

private function FuncFilter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), TempPlayer) and UnitAlive(GetFilterUnit())
endfunction

private function Callback takes nothing returns boolean
    local data d = KT_GetData() //Restoring values of struct
    local real ax = GetUnitX(d.Missile)
    local real ay = GetUnitY(d.Missile)
    local real nx = ax + SPEED * d.Cosine
    local real ny = ay + SPEED * d.Sine
    
    local unit target
    local unit stunner
    local real dx
    local real dy
    
    call SetUnitX(d.Missile, nx)
    call SetUnitY(d.Missile, ny)
    
    set d.FailSafeDistCounter = d.FailSafeDistCounter + SPEED
    set TempPlayer = d.Owner
    call GroupEnumUnitsInRange(G, nx, ny, AOE, Condition(function FuncFilter))
    set target = GroupPickRandomUnit(G)
    
    set dx = d.CX - nx
    set dy = d.CY - ny
    
    if target != null then        
        call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX, target, ATH_POINT))
        call DestroyEffect(AddSpecialEffectTarget(DAMAGE_SFX2, target, ATH_POINT))
        
        call UnitDamageTarget(d.Caster, target, GetDamage(GetUnitAbilityLevel(d.Caster, SPELL_ID)), false, false, ATK_TYP, DMG_TYP, WPN_TYP)
        call KillUnit(d.Missile)
        
        set d.MissileDone = true
    elseif SquareRoot(dx * dx + dy * dy) > GetDistance(GetUnitAbilityLevel(d.Caster, SPELL_ID)) or d.FailSafeDistCounter > GetDistance(GetUnitAbilityLevel(d.Caster, SPELL_ID)) and not d.MissileDone then
        call KillUnit(d.Missile)
        set d.MissileDone = true
    endif
    
    set stunner = null
    set target = null
    call GroupClear(G)
    
    if d.MissileDone then
        call d.destroy()
        return true
    endif
    
    return false
endfunction

private function Action takes nothing returns nothing
    local data d = data.create() //You need a struct to pass to the timer using KT
    
    call KT_Add(function Callback, d, TIMER_INTERVAL) //Here is the timer
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(t, Condition(function Cond))
    call TriggerAddAction(t, function Action)
endfunction
endscope


PS: X/Y not safe, use BoundSentinel by Vexorian
 

tooltiperror

Super Moderator
Reaction score
231
I was thinking of writing a Timer tutorial, now I think I will.

Here is how to use it, short story.

JASS:

//! fix align
 library Timers initializer OnInit
   globals
       unit hardcore
   endglobals
   private function callback takes nothing returns nothing
       call KillUnit(hardcore)
   endfunction
   private function OnInit takes nothing returns nothing
       local timer t=CreateTimer()                     //Create a timer,
       set hardcore=CreateUnit(...)                    //Create a unit,
       call TimerStart(t,5.00,false,function callback) //start timer t, set it to 5 seconds,                                                      
   endfunction                                         //false makes it so it won't repeat, and when
 endlibrary                                            //the timer is over, run function callback.
 

Ashlebede

New Member
Reaction score
43
I was thinking of writing a Timer tutorial, now I think I will.

Here is how to use it, short story.

JASS:
//! fix align
 library Timers initializer OnInit
   globals
       unit hardcore
   endglobals
   private function callback takes nothing returns nothing
       call KillUnit(hardcore)
   endfunction
   private function OnInit takes nothing returns nothing
       local timer t=CreateTimer()                     //Create a timer,
       set hardcore=CreateUnit(...)                    //Create a unit,
       call TimerStart(t,5.00,false,function callback) //start timer t, set it to 5 seconds,                                                      
   endfunction                                         //false makes it so it won't repeat, and when
 endlibrary                                            //the timer is over, run function callback.

JASS:
native DestroyTimer         takes timer whichTimer returns nothing


pl0x
 

tooltiperror

Super Moderator
Reaction score
231
I mean, I said short story short, but if you want, you could add a global timer and use that then destroy it, but you're better off using a timer system. Right, so I'll go write that tutorial now.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top