Spell Birds

Viikuna

No Marlo no game.
Reaction score
265
Here is a spell i made for wc3creations spell contest.

It is vJass and MUI. Requires Cohadars TT, Vexorians CheckPathability and SafeX/Y -functions. ( You find all these from testmap. )

code:
JASS:
// Bird Strike by Viikuna
// This spell is made for wc3Creations Spell Contest
// Theme: Missile, Light.   ( and Birds ) 


scope Birds initializer init
// this uses SomeNeatFunctions, TT ( Credits go to Cohadar )

globals
//==================================================================================
//==================================================================================
    // Ability is based on Channel
    private constant integer ABILITY_ID = 'A000'
    // AoE for Knockback
    private constant real AOE = 300.0
    // AoE fot missile collinsion
    private constant real MISSILE_AOE = 50.0 
    // Damage is calculated like this: DAMAGE_LEVEL*AbilityLevel+DAMAGE_BASE
    private constant real DAMAGE_BASE = 0.0
    private constant real DAMAGE_LEVEL = 50.0
    // All the Birds
    private constant integer MISSILE_ID0 = 'h000'
    private constant integer MISSILE_ID1 = 'h001'
    private constant integer MISSILE_ID2 = 'h002'
    private constant integer MISSILE_ID3 = 'h003'
    private constant integer MISSILE_ID4 = 'h004'
    // Damage types
    private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
    private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC
    private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
    // When unit collides with some object, the damage is calculated like this:
    // Units Sliding Velocity * DAMAGE_FACTOR
    private constant real DAMAGE_FACTOR = 2.5
    // The bigger the number, the bigger the knockback
    private constant real KNOCKBACK_FACTOR = 0.01
    // missiles Maximum travelling range
    private constant real MAX_RANGE = 1500.0
    // Missiles move speed
    private constant real STARTING_VELOCITY = 10.0
    private constant real ACCELERATION = 0.5 / 2
    // How fast sliding units stop
    private constant real FRICTION = 2.5 / 2
    // Maximum targets knocked per Missile
    private constant integer MAX_TARGETS = 10
 //==================================================================================   
 //==================================================================================   
    private integer array MISSILE_ID
    private filterfunc F
    private filterfunc True
    private group TempG = CreateGroup()
    private unit TempU
endglobals

private struct Data2
    unit u
    unit knocker
    real sin
    real cos
    real x
    effect e
    real y
    real velocity
    boolean impact = false
    
    method move takes nothing returns nothing
        set this.velocity = this.velocity - FRICTION
        set this.x = SafeX(this.x + this.velocity * this.cos)
        set this.y = SafeY(this.y + this.velocity * this.sin)
        set this.velocity = this.velocity - FRICTION
        if CheckPathability(this.x,this.y) == true then
            call SetUnitX(this.u,this.x)
            call SetUnitY(this.u,this.y)
        else
            set this.impact = true
        endif
    endmethod
    
    method onDestroy takes nothing returns nothing
        call PauseUnit(this.u,false)
        call DestroyEffect(this.e)
        if this.impact == true then
            call UnitDamageTarget(this.knocker,this.u,this.velocity*DAMAGE_FACTOR,false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
            call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl",this.x,this.y))
        endif
    endmethod
endstruct

private function Loop2 takes nothing returns boolean
    local Data2 D = TT_GetData()
    if D.impact == true or D.velocity <= 0 then
        call D.destroy()
        return true
    endif
    call D.move()
    return false
endfunction

private struct Data
    unit array bird[10]
    unit shooter
    real velocity
    real range = 0.0
    real x
    real y
    real array birdX[10]
    real array birdY[10]
    real sin
    real cos
    real array birdCos[10]
    real array birdSin[10]
    boolean spreaded = false
    boolean end = false
    
    
    method KnockThem takes nothing returns nothing
        local unit u
        local real x
        local real y
        local real dx
        local real dy
        local real a
        local Data2 D
        local integer i = 0
        set TempU = this.shooter
        call GroupEnumUnitsInRange(TempG,this.x,this.y,AOE,F)
        loop
            set u = FirstOfGroup(TempG)
            set i = i + 1
            exitwhen u == null or i == MAX_TARGETS
            set x = GetUnitX(u)
            set y = GetUnitY(u)
            set dx = x - this.x
            set dy = y - this.y
            set D = Data2.create()
            set D.velocity = (AOE - (SquareRoot(dx * dx + dy * dy)/2) ) * ( this.velocity / 2 ) * KNOCKBACK_FACTOR
            set a = Atan2(dy,dx)
            set D.sin = Sin(a)
            set D.cos = Cos(a)
            set D.x = x
            set D.y = y
            set D.u = u
            set D.e = AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\FaerieDragonInvis\\FaerieDragon_Invis.mdl",D.u,"chest")
            set D.knocker = this.shooter
            call PauseUnit(D.u,true)
            call D.move()
            call TT_Start(function Loop2,D)
            call UnitDamageTarget(this.shooter,u,DAMAGE_LEVEL*GetUnitAbilityLevel(this.shooter,ABILITY_ID)+DAMAGE_BASE,false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
            call DestroyEffect(AddSpecialEffect("Abilities\\Weapons\\ProcMissile\\ProcMissile.mdl",x,y))
            call GroupRemoveUnit(TempG,u)
        endloop
        call GroupClear(TempG)
    endmethod
    
    method move takes nothing returns nothing
        local unit u
        local real a
        local real dx
        local real dy
        local real d
        local real r
        local integer i = 0
        local real cos = this.velocity * this.cos
        local real sin = this.velocity * this.sin
        set this.x = SafeX( this.x + cos)
        set this.y = SafeY( this.y + sin)
        set TempU = this.shooter
        call GroupEnumUnitsInRange(TempG,this.x,this.y,MISSILE_AOE,F)
        set u = FirstOfGroup(TempG)
        if this.range >= MAX_RANGE or u != null or CheckPathability(this.x,this.y) == false then
            call GroupClear(TempG)
            set this.spreaded = true
            set r = bj_PI / 5
            set a = 0
            set this.range = 0.0
            call this.KnockThem()
            loop
                exitwhen i > 9
                set a = a + r
                call SetUnitFacing(this.bird<i>,a*bj_RADTODEG)
                set this.birdCos<i> = Cos(a)
                set this.birdSin<i> = Sin(a)
                set i = i + 1
            endloop
            return
        endif
        loop
            exitwhen i &gt; 9
            set dx = this.x - this.birdX<i>
            set dy = this.y - this.birdY<i>
            set d = SquareRoot(dx * dx + dy * dy)
            if d &gt; 150.0 then
                set a = Atan2(dy,dx)
                set this.birdSin<i> = Sin(a)
                set this.birdCos<i> = Cos(a)
            else
                if d &lt; 10 then
                    set this.birdSin<i> = GetRandomReal(0.0,1.0)
                    set this.birdCos<i> = GetRandomReal(0.0,1.0)
                endif
            endif
            set this.birdX<i> = SafeX(this.birdX<i> + cos)
            set this.birdY<i> = SafeY(this.birdY<i> + sin)
            set this.birdX<i> = SafeX(this.birdX<i> + 5.0 * this.birdCos<i>)
            set this.birdY<i> = SafeY(this.birdY<i> + 5.0 * this.birdSin<i>)
            call SetUnitX(this.bird<i>,this.birdX<i>)
            call SetUnitY(this.bird<i>,this.birdY<i>)
            set i = i + 1
        endloop
        set this.velocity = this.velocity + ACCELERATION
        set this.range = this.range + this.velocity
        set this.velocity = this.velocity + ACCELERATION
        set u = null
    endmethod
    
    method spread takes nothing returns nothing
        local integer i = 0
        if this.range &gt; AOE then
            set this.end = true
            return
        endif
        loop
            exitwhen i &gt; 9
            set this.birdX<i> = SafeX(this.birdX<i> + this.velocity * this.birdCos<i>)
            set this.birdY<i> = SafeY(this.birdY<i> + this.velocity * this.birdSin<i>)
            call SetUnitX(this.bird<i>,this.birdX<i>)
            call SetUnitY(this.bird<i>,this.birdY<i>)
            set i = i + 1
        endloop
        set this.velocity = this.velocity + ACCELERATION
        set this.range = this.range + this.velocity
        set this.velocity = this.velocity + ACCELERATION
    endmethod
    
    method onDestroy takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i &gt; 9
            call KillUnit(this.bird<i>)
            set i = i + 1
        endloop
    endmethod

endstruct

private function ItIsTrue takes nothing returns boolean
   return true
endfunction

private function filter takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(TempU)) == true and GetWidgetLife(GetFilterUnit()) &gt; 0.0451 and GetUnitFlyHeight(GetFilterUnit()) == 0 and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false
endfunction

private function Loop takes nothing returns boolean
    local Data D = TT_GetData()
    if D.end == true then
        call D.destroy()
        return true
    endif
    if D.spreaded == true then
        call D.spread()
    else
        call D.move()
    endif
    return false
endfunction

private function B takes nothing returns nothing
     local Data D = Data.create()
     local integer i = 0
     local unit u = GetTriggerUnit()
     local location loc = GetSpellTargetLoc()
     local real x = GetUnitX(u)
     local real y = GetUnitY(u)
     local real x2 = GetLocationX(loc)
     local real y2 = GetLocationY(loc)
     local real dx = x2 - x
     local real dy = y2 - y
     local real angle = Atan2(dy, dx)
     set D.sin = Sin(angle)
     set D.cos = Cos(angle)
     set D.x = x
     set D.y = y
     set D.shooter = u
     set D.velocity = STARTING_VELOCITY
     loop
         exitwhen i &gt; 9
         set D.bird<i> = CreateUnit(Player(13),MISSILE_ID[GetRandomInt(0,4)],D.x,D.y,angle*bj_RADTODEG)
         call PauseUnit(D.bird<i>,true)
         set D.birdX<i> = x
         set D.birdY<i> = y
         set D.birdCos<i> = GetRandomReal(0.0,1.0)
         set D.birdSin<i> = GetRandomReal(0.0,1.0)
         set i = i + 1
     endloop
     call TT_Start(function Loop, D)
     call RemoveLocation(loc)
     set loc = null
     set u = null
endfunction


private function A takes nothing returns boolean
    return GetSpellAbilityId() == ABILITY_ID
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    set MISSILE_ID[0] = MISSILE_ID0
    set MISSILE_ID[1] = MISSILE_ID1
    set MISSILE_ID[2] = MISSILE_ID2
    set MISSILE_ID[3] = MISSILE_ID3
    set MISSILE_ID[4] = MISSILE_ID4
    set True = Filter(function ItIsTrue)
    loop
        call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,True)
        set i = i + 1
        exitwhen i == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t,Condition(function A))
    call TriggerAddAction(t,function B)
    set F = Filter(function filter)
endfunction

endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>



Here is the testmap:
View attachment All the Birds.w3x
Download it and give me some comments.

Spell description would be something like this:

It sends few angry Birds flying towards the target location. When Birds collide with something or meet the maximum range, they spread out and deal damage to enemies and knock them them away.

EDIT. some shots: Bird1.jpg Birds2.jpg
 

NaPzt3R

You can change this now in User CP.
Reaction score
38
What about telling us what it does.. And add some screenshots? :D
 

quraji

zap
Reaction score
144
Looks neat. Wonder why it's a target spell? Doesn't seem to affect the spell at all casting at different locations.

I see you're doing quite a bit of moving calculations, which doesn't make sense to me as the birds only exist for a flash and the movement distance is so small (for both birds and knockback units). Seems a waste to me when no one will notice the difference between this and a basic static speed slide.

I really like the look of the birds though, going to have to see what models they are :)
 

Viikuna

No Marlo no game.
Reaction score
265
Actyally those Birds knockback a bit more if they get some time to accelerate.

BTW Check those pics too :)

EDIT, They are those famous bird projectiles. I have allways wondered how many differend color birds there is in wc3, I hope I found them all. ( I think I did )
 

NaPzt3R

You can change this now in User CP.
Reaction score
38
Looks pretty neat from the look of the screenshots.
Going to download the map now.

EDIT:
This is awesome.
Is it okay if I use it in my map? I might edit it a bit.
 

Viikuna

No Marlo no game.
Reaction score
265
No problem, you are free to use it. ( That is actually the reason why I posted it in first place. )
 

Faust

You can change this now in User CP.
Reaction score
123
An excellent idea, I will use some "mutated" form it some time in my map ^^
 

Jedimindtrixxx

┻━┻ ︵ ¯\(ツ)/¯ ︵ ┻━┻
Reaction score
168
wow i tried it out and its amazing. they go faster over time and they push out more the more they travel!
one thing though, at times they fly through the enemy and dont hit them.

also, how would i make them speed up faster?
i see this:
JASS:
    // Missiles move speed
    private constant real STARTING_VELOCITY = 10.0
    private constant real ACCELERATION = 0.5 / 2

but to make it faster do i increase the .5 or decrease, or do i increase/decrease the /2 ?
 

Viikuna

No Marlo no game.
Reaction score
265
Actyally, I dont really remember why it is 0.5 / 2, and not 0.25, since they are the same thing. ( weird )

Anyways, it incereases missiles speed by 0.25 per every timer tick. So after first tick , missile speed is 10 + 0.25 ( = 10.25). After second tick it will be 10.25 + 0.25 ( = 10.5 ) and etc.

To make accelerate faster just replace that 0.5 / 2 ( = 0.25 ) with 0.26 or 0.27 or some other number, which is greater than 0.25.

at times they fly through the enemy and dont hit them.
This is because birds doest trigger collinsion, but the center of that bird swarm does. You can incerease MISSILE_AOE, it tells from how big are it will pick enemy units and trigger collinsion.
 

_whelp

New Member
Reaction score
54
The description sounds kinda funny cause angry birds give me the thought of mad birds pooping.
JASS:
//lolololololol
 

Viikuna

No Marlo no game.
Reaction score
265
Do I need to do something else than wait to get spells aproved?
Waiting is no problem, but if there is something else, I would like to know.
 

gameman

It's been a long, long time.
Reaction score
96
Wow! This is awesome. I'll be wondering when you will be doing requests.
 

Viikuna

No Marlo no game.
Reaction score
265
Well, If you have something to request PM me and I see what I can do. I can make spells, but dont request any big systems or things that take too much coding :D .
 

Viikuna

No Marlo no game.
Reaction score
265
Omg, since this is now aproved, I think I need to recode it, so it is at the date of best quality vJass coding.
 

Romek

Super Moderator
Reaction score
963
> Omg, since this is now aproved, I think I need to recode it, so it is at the date of best quality vJass coding.
Go ahead. Though it's approval-worthy as it is.

That somewhat reminds me of my Panda Roll spell.
It's approved, though I'm planning on recoding it so it meets my standards.
 
Reaction score
91
Awesome idea, pretty original and quite interesting! I guess I can find some use of this in my map if you recode it.
Just a suggestion - wouldn't it be better if the birds landed/exploded/whatever it's called at the position where you casted the spell? Right now it has a fixed distance and it could be hard to target someone in a fast paced game where every unit is moving and trying to dodge some damage.
 

Viikuna

No Marlo no game.
Reaction score
265
Good idea, fixxed distance really kinda sucks. I will get back to this later, gotta make some pizza now..
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top