• 🏆 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] (system) Missile

I have worked on this missle engine for 2 months now and start the first official beta today.

Please post feedback, critism, pros, cons, bugs, etc.
Thanks all for your patience!

And thanks for downloading.
Preview image by Furby. Thanks a lot!

Edit:
I've updated the testmap and added a second spell.
There is a lot of improvements in version 0.1.7 and I plan to make it even faster and even more modular. I also plan to create an easy to understand API.

Used librarys:


Changed all constants (TRUE, FALSE) to true/false
Changed interval to 0.03125
Fixed object leaks
Performance improvements on MissileMovement: Less object generation
Merged MissileLocHelpers to Missile<type>Target
Removed HomingMissile wrapper
Added second spell (Rain of Fire)
Removed Libraries from Modules



Changed name to Missile.
Completely remade in modules, supports now a lot of optional stuff.
Added SpellHelper, fixed a lot of problems, made the Miranas Arrow example WAY more powerful to show what this system is able to be capable of.


Keywords:
Missile, Projectile, xe, xemissile, xecollider, projectile, collider, awesome, anachron, collide, colliding, vJass
Contents

CustomMissile 0.1.7 (Map)

Reviews
BPower: 11:02, 25th Feb 2016 Reason for re-review: Nowadays the spell section is packed full of missile systems from different authors, therefore a more qualified moderator comment than "this is neat stuff" is required. There is keen...
Level 18
Joined
Jan 21, 2006
Messages
2,552
You should include demos of all the functionality that your system claims to have. I have already tried customizing the .zarc of a created CustomMissile and it breaks the missile, causing it to disappear shortly after being created. You really need to stress-test all of your missile's capabilities in order to determine there are no obvious bugs. Setting the z-arc to 0.03 should not break the missile, it shows you did very little actual testing.

Itachi009 said:
k tested it and xe and my pc handled about 300 missiles from your systems but only 240 from xe, and since your system also supports more possibilities i change my vote to 5/5

I don't know how the hell you got 300 projectiles. Without any unit enumerations on the map (though the feature still active) I ran up to 160 before my frame-rate started to drop badly. By 200 the game was not in a playable state.

In my system I got 365 created with the same drop in frame-rate I experienced with only 150 missiles from Anachron's system.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well then it may be a mistake on my part, but it seems strange how I could so easily break this despite you completely controlling every aspect of the projectile (including the unit) from birth to death.

I just double checked my implementation. In your test-map Arcane Missile trigger in the onCreate method I added this line exactly: set .zarc = 0.05. I checked to see what the method operator zarc= does and it just refers to .zArc so there should be no problems there.

Anachron said:
Then maybe disable a few features? And check the interval times.

You don't state any features that contradict or disrupt the activity of the others. I don't think I should have to find which ones don't work before I can start successfully using your system.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Okay; so did you find out the problem with zarc yet?

I like the way you handled XY arc though. It's making me think about possibilities of implementing a similar idea in mine.
 
Level 12
Joined
Sep 4, 2007
Messages
407
o_O it really lacks on showing what it can do, you should show all of it's features at least once in different spells. Like making a multiple arcane missile that have varied zarc's, xyarc's and speed for it's missiles, maybe a wall/tree/missile boucing rubber ball, or even an DotA's Mirana's Elune's Arrow. (btw, the first two are easy, i'm having some difficulty with the last one, your system doesn't really support projectiles that keep moving towards target "direction")

=)
 
Level 12
Joined
Sep 4, 2007
Messages
407
other thing: i think you should check the X n' Y of the missile qhen you move, so when it hits the maxX or maxY or minX or minY of the map it desapairs. dunno if features that, but most projectile, collide system does not support that. (oh, thanks i solved the problem xD)
 
Level 12
Joined
Sep 4, 2007
Messages
407
it's not working now, dunno what i did, i'm noob to vJass.

JASS:
scope ShortBow initializer init
    private keyword spell
    private struct spellMissile extends CustomMissile
        private integer hittedUnits = 0
        private real    dmgPerUnit = 0.
        private spell   spellInst = 0
        
        private unit source = null
        
        public static method new takes spell ins, unit caster returns thistype
            local real x = GetUnitX(caster)
            local real y = GetUnitY(caster)
            local thistype this = thistype.create(x, y, GetLocZ(x, y) + 85., 0.)
            
            set .source = caster
            set .spellInst = ins
            
            call .setTargetPos(GetSpellTargetX(), GetSpellTargetY())
            
            return this
        endmethod
        
        method onCreate takes nothing returns nothing
            set .sfx        = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
            set .scale      = 1   //: 100% of the normal size
            set .colorA     = 255   //: fully visible
            set .movespeed  = 512.  //: Moves with a rate of 512
            set .hitrange   = 65.   //: Hits units and missles in range of 65.
            set .decay      = 5.    //: Decays after 5 seconds.
            set .height     = 50.   //: Has a height of 50.
            set .hitunits   = true  //: Hits units
            set .hitdests   = true  //: Hits destructables
            set .hitwalls   = true  //: Hits walls
        endmethod
        
        
        method onUnitTouch takes unit theUnit returns nothing
            if GetUnitState(theUnit, UNIT_STATE_LIFE) == 0. or GetOwningPlayer(.source) == GetOwningPlayer(theUnit) then
                return
            endif
            if IsPlayerEnemy(GetOwningPlayer(.source), GetOwningPlayer(theUnit)) then
                call UnitDamageTarget(.source, theUnit, GetHeroAgi(.source,true), false, false, ATTACK_TYPE_PIERCE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_METAL_LIGHT_SLICE)
            endif
            call .spellInst.destroy()
        endmethod
    endstruct
    
    private struct spell
        private spellMissile missile = 0
        
        public static method create takes unit caster, unit target returns thistype
            local thistype this = thistype.allocate()
            
            set .missile = spellMissile.new(this, caster)
            call BJDebugMsg("Direction Coordinates: X=" + R2S(GetSpellTargetX()) + " Y=" + R2S(GetSpellTargetY()))
            
            return this
        endmethod
    endstruct
    
    private function cast takes nothing returns boolean
        if GetSpellAbilityId() != 'A006' then
            return false
        endif
        call spell.create(GetTriggerUnit(), GetSpellTargetUnit())
        return false
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        
        call TriggerAddCondition(t, Condition(function cast))
        
        loop
            exitwhen i >= bj_MAX_PLAYERS
            
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)
            set i = i +1
        endloop
    endfunction
    
endscope
 
Level 12
Joined
Sep 4, 2007
Messages
407
doing this should work then?

JASS:
scope ShortBow initializer init
    private keyword spell
    private struct spellMissile extends CustomMissile
        private integer hittedUnits = 0
        private real    dmgPerUnit = 0.
        private spell   spellInst = 0
        
        private unit source = null
        
        public static method new takes spell ins, unit caster, real spellx, real spelly returns thistype
            local real x = GetUnitX(caster)
            local real y = GetUnitY(caster)
            local thistype this = thistype.create(x, y, GetLocZ(x, y) + 85., 0.)
            
            set .source = caster
            set .spellInst = ins
            
            call .setTargetPos(spellx, spelly)
            
            return this
        endmethod
        
        method onCreate takes nothing returns nothing
            set .sfx        = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
            set .scale      = 1   //: 100% of the normal size
            set .colorA     = 255   //: fully visible
            set .movespeed  = 512.  //: Moves with a rate of 512
            set .hitrange   = 65.   //: Hits units and missles in range of 65.
            set .decay      = 5.    //: Decays after 5 seconds.
            set .height     = 50.   //: Has a height of 50.
            set .hitunits   = true  //: Hits units
            set .hitdests   = true  //: Hits destructables
            set .hitwalls   = true  //: Hits walls
        endmethod
        
        
        method onUnitTouch takes unit theUnit returns nothing
            if GetUnitState(theUnit, UNIT_STATE_LIFE) == 0. or GetOwningPlayer(.source) == GetOwningPlayer(theUnit) then
                return
            endif
            if IsPlayerEnemy(GetOwningPlayer(.source), GetOwningPlayer(theUnit)) then
                call UnitDamageTarget(.source, theUnit, GetHeroAgi(.source,true), false, false, ATTACK_TYPE_PIERCE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_METAL_LIGHT_SLICE)
            endif
            call .spellInst.destroy()
        endmethod
    endstruct
    
    private struct spell
        private spellMissile missile = 0
        
        public static method create takes unit caster, unit target returns thistype
            local thistype this = thistype.allocate()
            
            set .missile = spellMissile.new(this, caster, GetSpellTargetX(), GetSpellTargetY())
            
            return this
        endmethod
    endstruct
    
    private function cast takes nothing returns boolean
        if GetSpellAbilityId() != 'A006' then
            return false
        endif
        call spell.create(GetTriggerUnit(), GetSpellTargetUnit())
        return false
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        
        call TriggerAddCondition(t, Condition(function cast))
        
        loop
            exitwhen i >= bj_MAX_PLAYERS
            
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)
            set i = i +1
        endloop
    endfunction
    
endscope

because it does not o_O
 
Level 12
Joined
Sep 4, 2007
Messages
407
according to the debugmsg, the reals get there just fine, and still not working. o_O

JASS:
scope ShortBow initializer init
    private keyword spell
    private struct spellMissile extends CustomMissile
        private integer hittedUnits = 0
        private real    dmgPerUnit = 0.
        private spell   spellInst = 0
        
        private unit source = null
        
        public static method new takes spell ins, unit caster, real spellx, real spelly returns thistype
            local real x = GetUnitX(caster)
            local real y = GetUnitY(caster)
            local thistype this = thistype.create(x, y, GetLocZ(x, y) + 85., 0.)
            
            set .source = caster
            set .spellInst = ins
            
            call .setTargetPos(spellx, spelly)
            call BJDebugMsg(".new Direction Coordinates: X=" + R2S(spellx) + " Y=" + R2S(spelly))
            
            return this
        endmethod
        
        method onCreate takes nothing returns nothing
            set .sfx        = "Abilities\\Weapons\\Arrow\\ArrowMissile.mdl"
            set .scale      = 1   //: 100% of the normal size
            set .colorA     = 255   //: fully visible
            set .movespeed  = 512.  //: Moves with a rate of 512
            set .hitrange   = 65.   //: Hits units and missles in range of 65.
            set .decay      = 5.    //: Decays after 5 seconds.
            set .height     = 50.   //: Has a height of 50.
            set .hitunits   = true  //: Hits units
            set .hitdests   = true  //: Hits destructables
            set .hitwalls   = true  //: Hits walls
        endmethod
        
        
        method onUnitTouch takes unit theUnit returns nothing
            if GetUnitState(theUnit, UNIT_STATE_LIFE) == 0. or GetOwningPlayer(.source) == GetOwningPlayer(theUnit) then
                return
            endif
            if IsPlayerEnemy(GetOwningPlayer(.source), GetOwningPlayer(theUnit)) then
                call UnitDamageTarget(.source, theUnit, GetHeroAgi(.source,true), false, false, ATTACK_TYPE_PIERCE, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_METAL_LIGHT_SLICE)
            endif
            call .spellInst.destroy()
        endmethod
    endstruct
    
    private struct spell
        private spellMissile missile = 0
        
        public static method create takes unit caster, real x, real y returns thistype
            local thistype this = thistype.allocate()
            
            set .missile = spellMissile.new(this, caster, x, y)
            call BJDebugMsg(".create Direction Coordinates: X=" + R2S(x) + " Y=" + R2S(y))
            
            return this
        endmethod
    endstruct
    
    private function cast takes nothing returns boolean
        if GetSpellAbilityId() != 'A006' then
            return false
        endif
        call spell.create(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
        call BJDebugMsg("function cast Direction Coordinates: X=" + R2S(GetSpellTargetX()) + " Y=" + R2S(GetSpellTargetY()))
        return false
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        
        call TriggerAddCondition(t, Condition(function cast))
        
        loop
            exitwhen i >= bj_MAX_PLAYERS
            
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)
            set i = i +1
        endloop
    endfunction
    
endscope
 
Level 12
Joined
Sep 4, 2007
Messages
407
Edit:I get the sound of the arrow model when the spell is casted, that means the arrow is actually created. but i don't get the dying sound. o_O

could it be a height or z problem? like i'm actually casting the arrow but not seeing it because is bellow the ground or too above the unit (i got a third pearson camera system)?

I don't se the arrow model at any time though.
 
Level 12
Joined
Sep 4, 2007
Messages
407
you mean attaching the camera to the "arrow" unit and setting the z offset of it equal to the one in the arrow? o_O

Edit: I did this:
JASS:
        public static method new takes spell ins, unit caster, real spellx, real spelly returns thistype
            local real x = GetUnitX(caster)
            local real y = GetUnitY(caster)
            local thistype this = thistype.create(x, y, GetLocZ(x, y) + 85., 0.)
            call SetCameraField(CAMERA_FIELD_ZOFFSET, GetLocZ(x, y) + 85., 0.1)
            
            set .source = caster
            set .spellInst = ins
            
            call .setTargetPos(spellx, spelly)
            call BJDebugMsg(".new Direction Coordinates: X=" + R2S(spellx) + " Y=" + R2S(spelly))
            
            return this
        endmethod

and.....

Edit: The camera gets a bit more farer (z) from the unit (normal camera here, camera system deactivated), probably because of that + 85.
 
Level 12
Joined
Sep 4, 2007
Messages
407
dude, in your system this method takes three reals and no boolean...

i used the GetLocZ(x,y) for the third real. no donut still, no arrow appears, and the noise is still there.

Edit: i'm going to take a break here, be back later or tomorrow. try to fix this thing aswell.
 
Level 12
Joined
Sep 4, 2007
Messages
407
sure

Edit:

I already did that for .scale...

it's not the alpha colour from vexorian aswell... removed the line, result: nothing.

included the method onLoop: no difference (it doesn't even print the debugmsgs), you missile does not become active.

since the onLoop is not called I assume that the method move has a problem, let me check. Well, the method move seems to have no problem at all o_O
 
Last edited:
Level 12
Joined
Sep 4, 2007
Messages
407
it is created, i hear the noise of the missile being created like an archer was firing an arrow (the effect has the sound) but i don't see anything. my guess is that the missile is created underground and stays there.

also your system seems to always target the units feet if used with hasTaget.

also, if you set zArc on, no matter the arc you put, it will go undeground. (i made the magic missiles with only a random xyArc because of that.)

(but those two things are not important right now... i suppose i can fix for my map, for the target, it's just a matter of changing the arrival z. for the other one, i have no idea. the zarcs seems to delete the xyarc.)
 
(but those two things are not important right now... i suppose i can fix for my map, for the target, it's just a matter of changing the arrival z. for the other one, i have no idea. the zarcs seems to delete the xyarc.)
Hugh, what? That shouldn't be. zArc and xyArc are two completely different things and are never linked to each other.
 
Level 12
Joined
Sep 4, 2007
Messages
407
that's true i guess the xyarc continues working underground since i can't see anymore because of the zarc ALWAYs going underground no matter if the arc is positive or negative.

(fixed the .end.z always hitting the target feet:
JASS:
        private method updateTarget takes nothing returns nothing
            if .hasTarget then
                if .target != null then
                    set .end.x = GetUnitX(.target)
                    set .end.y = GetUnitY(.target)
                    set .end.z = GetLocZ(.end.x, .end.y) + GetUnitFlyHeight(.target) + 100.
                endif
            else
                call .end.applyLoc(.eff.loc)
            endif
        endmethod

just add an +110 z height for it. now it hits the chest. of course this changes from model to model and from scale to scale. but overall i think + 100 looks always better.
 
just add an +110 z height for it. now it hits the chest. of course this changes from model to model and from scale to scale. but overall i think + 100 looks always better.
Thanks, but that really depends on the models so I can't really make this for every unit. But I guess there is nothing against +50 height :p
 
Level 12
Joined
Sep 4, 2007
Messages
407
so how about the notarget missile? how do we solve? the missles that have .aim seems to work fine. (we can just create an dummy in the target point. that would make the missle stop where the unit is unless we can change the unit location to a bit far away everytime it gets nearby. xD hahaha: making the OnReach to change the dummy unit's position.) lol


bad news: hitdest n' hitunits don't work either. o_O (tested using a projectile with defined target. in doesn't notice the trees and units in the way)

hitwall seems to WANT to work since it plays the effects of onHitWall, but .spellInst.destroy() didn't work under onHitWall.

also: the alpha seems to be working, but the other three colours don't (i might be wrong).

did you fully tested?
 
Last edited:
Level 12
Joined
Sep 4, 2007
Messages
407
i created. check out the coding:

JASS:
scope MagicMissile initializer init
    private keyword spell
    private struct spellMissile extends CustomMissile
        private integer hittedUnits = 0
        private real    dmgPerUnit = 0.
        private spell   spellInst = 0
        
        private unit source = null
        private unit aim = null
        
        public static method new takes spell ins, unit caster, unit theTarget returns thistype
            local real x = GetUnitX(caster)
            local real y = GetUnitY(caster)
            local thistype this = thistype.create(x, y, GetLocZ(x, y) + 85., 0.)
            
            set .source = caster
            set .aim = theTarget
            set .spellInst = ins
            
            call .setTargetUnit(theTarget, true)
            
            return this
        endmethod
        
        method onCreate takes nothing returns nothing
            set .sfx        = "Abilities\\Spells\\Undead\\OrbOfDeath\\AnnihilationMissile.mdl"
            set .scale      = .55   //: 55% of the normal size
            set .colorA     = 128   //: Half transparent
            set .movespeed  = 2000.  //: Moves with a rate of 512
            set .turnspeed  = 0.15  //: Turns with a rate of 0.15
            set .hitrange   = 65.   //: Hits units and missles in range of 48.
            set .xyarc      = GetRandomReal(-0.15,0.15) //: Has a random real xyArc from -0.15 to 0.15
            set .decay      = 6.    //: Decays after 6 seconds.
            set .height     = 50.   //: Has a height of 50.
            set .hitwalls   = true
            set .hitdests   = true
            set .hitunits   = true
        endmethod

        method onWallHit takes nothing returns nothing
            call .spellInst.destroy()
        endmethod
        
        method onUnitTouch takes unit theUnit returns nothing
            call UnitDamageTarget(.source, theUnit, 100., false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
            call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\OrbOfDeath\\OrbOfDeathMissile.mdl", theUnit, "chest"))
            call .spellInst.destroy()
        endmethod
        
        method onDestTouch takes destructable theDestructable returns nothing
            call .spellInst.destroy()
        endmethod
        
        method onTargetReach takes nothing returns nothing
            call UnitDamageTarget(.source, .aim, 100., false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
            call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\OrbOfDeath\\OrbOfDeathMissile.mdl", .aim, "chest"))
            call .spellInst.destroy()
        endmethod
        
    endstruct
    
    private struct spell
        private spellMissile missile = 0
        
        public static method create takes unit caster, unit target returns thistype
            local thistype this = thistype.allocate()
            
            set .missile = spellMissile.new(this, caster, target)
            
            return this
        endmethod
    endstruct
    
    private function cast takes nothing returns boolean
        if GetSpellAbilityId() != 'A000' then
            return false
        endif
        call spell.create(GetTriggerUnit(), GetSpellTargetUnit())
        return false
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        
        call TriggerAddCondition(t, Condition(function cast))
        
        loop
            exitwhen i >= bj_MAX_PLAYERS
            
            call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_CAST, null)
            set i = i +1
        endloop
    endfunction
    
endscope

i made it based on your spell arcane missile
 
Top