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

Sharp Needles v1.0

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: Undeadducky
The former Bristleback ultimate from my Oasis and Desert project.

Coding:

JASS:
function Trig_Igloult_Conditions takes nothing returns boolean
    return GetSpellAbilityId() == 'A000'
endfunction

function IgloUltFilt takes nothing returns boolean
    return IsUnitType(GetFilterUnit(),UNIT_TYPE_DEAD) == false and IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(LoadUnitHandle(udg_H,GetHandleId(GetExpiredTimer()),0))) == true and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false
endfunction

function IgloUltGroup takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit caster = LoadUnitHandle(udg_H,GetHandleId(t),0)
    local integer lvl = GetUnitAbilityLevel(caster,'A000')
    local unit iu = LoadUnitHandle(udg_H,GetHandleId(t),1001)
    local real ir = LoadReal(udg_H,GetHandleId(t),1002)
    call UnitDamageTarget(caster,GetEnumUnit(),10.,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
    call SaveReal(udg_H,GetHandleId(t),1002,ir - 5. * lvl)
    set t = null
    set caster = null
    set iu = null
endfunction

function IgloUltMove takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local unit caster = LoadUnitHandle(udg_H,GetHandleId(t),0)
    local integer lvl = GetUnitAbilityLevel(caster,'A000')
    local integer i = 1
    local real x = GetWidgetX(caster)
    local real y = GetWidgetY(caster)
    local real d
    local unit iu
    local real x2
    local real y2
    local group g = CreateGroup()
    local real a = LoadReal(udg_H,GetHandleId(t),1000) + 5.
    
    if IsUnitType(caster,UNIT_TYPE_DEAD) == true then
        loop
            exitwhen i > lvl * 4 + 5
            call RemoveUnit(LoadUnitHandle(udg_H,GetHandleId(t),100 + i))
            call PauseTimer(t)
            call DestroyTimer(t)
        endloop
    endif
    
    call SaveReal(udg_H,GetHandleId(t),1000,a)
    
    loop
        exitwhen i > lvl * 4 + 5
        set d = LoadReal(udg_H,GetHandleId(t),50 + i)
        set iu = LoadUnitHandle(udg_H,GetHandleId(t),100 + i)
        set x2 = x + d * Cos((360. / (lvl * 4. + 5.) * i + a) * .0174532)
        set y2 = y + d * Sin((360. / (lvl * 4. + 5.) * i + a) * .0174532)
        call SetUnitFacing(iu,57.295827 * Atan2(y2 - GetWidgetY(iu),x2 - GetWidgetX(iu)))
        call SetUnitX(iu,x2)
        call SetUnitY(iu,y2)
        call SaveUnitHandle(udg_H,GetHandleId(t),1001,iu)
        call SaveReal(udg_H,GetHandleId(t),1002,LoadReal(udg_H,GetHandleId(t),i))
        call GroupEnumUnitsInRange(g,x2,y2,120.,Filter(function IgloUltFilt))
        call ForGroup(g,function IgloUltGroup)
        call SaveReal(udg_H,GetHandleId(t),i,LoadReal(udg_H,GetHandleId(t),1002))
        if LoadReal(udg_H,GetHandleId(t),i) < 20. then
            call RemoveUnit(iu)
        endif
        call GroupClear(g)
        set i = i + 1
    endloop
    call DestroyGroup(g)
    set iu = null
    set caster = null
    set t = null
    set g = null
endfunction

function Trig_Igloult_SpellEndTimer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local timer t2 = LoadTimerHandle(udg_H,GetHandleId(t),0)
    local unit caster = LoadUnitHandle(udg_H,GetHandleId(t2),0)
    local integer lvl = GetUnitAbilityLevel(caster,'A000') 
    local integer i = 0
    local unit u
    
    loop
        exitwhen i > lvl * 4 + 5
        set u = LoadUnitHandle(udg_H,GetHandleId(t2),100 + i)
        call RemoveUnit(u)
        set i = i + 1
    endloop
    
    call PauseTimer(t2)
    call DestroyTimer(t2)
    
    call FlushChildHashtable(udg_H,GetHandleId(t))
    call FlushChildHashtable(udg_H,GetHandleId(t2))
    call DestroyTimer(t)  
    set caster = null  
    set t = null
    set t2 = null
endfunction

function Trig_Igloult_Actions takes nothing returns nothing
    local integer i = 1
    local integer a
    local timer t = CreateTimer()
    local timer t2 = CreateTimer()
    local real array d
    local real array h
    local unit caster = GetTriggerUnit()
    local integer lvl = GetUnitAbilityLevel(caster,'A000')
    local unit u

    loop   
        exitwhen i > 4 * lvl + 5   
        if i <= 3 then   
            set d[i] = -240. * i * i + 1040. * i - 640.   
            set h[i] = 70. * i - 30.   
        else
            set a = 3
            loop
                exitwhen a > 18    
                if i > a and i <= 3 + a then   
                    set d[i] = -240. * (i - a) * (i - a) + 1040. * (i - a) - 640.   
                    set h[i] = 70. * (i - a) - 30.    
                endif
                set a = a + 3   
            endloop
        endif
        set i = i + 1   
    endloop

    set i = 1
    
    loop
        exitwhen i > lvl * 4 + 5
        call SaveReal(udg_H,GetHandleId(t),i,30. * lvl + 50.)
        call SaveReal(udg_H,GetHandleId(t),50 + i,d[i])
        set u = CreateUnit(GetOwningPlayer(caster),'h000',GetWidgetX(caster) + 350. * Cos(360. / (lvl * 4. + 5.) * i * .0174532),GetWidgetY(caster) + 350. * Sin(360. / (lvl * 4. + 5.) * i * .0174532),360. / (lvl * 4. + 5.) * i)
        call SetUnitFlyHeight(u,h[i],200.)
        call SaveUnitHandle(udg_H,GetHandleId(t),100 + i,u)
        set i = i + 1
    endloop
    
    call SaveUnitHandle(udg_H,GetHandleId(t),0,caster)
    call SaveReal(udg_H,GetHandleId(t),1000,0.)
    
    call TimerStart(t,.04,true,function IgloUltMove)
    
    call SaveTimerHandle(udg_H,GetHandleId(t2),0,t)
    
    call TimerStart(t2,25.,false,function Trig_Igloult_SpellEndTimer)
    
    set t = null
    set t2 = null
    set caster = null
    set u = null
endfunction

//===========================================================================
function InitTrig_Igloult takes nothing returns nothing
    set gg_trg_Igloult = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Igloult,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Igloult,Condition(function Trig_Igloult_Conditions))
    call TriggerAddAction(gg_trg_Igloult,function Trig_Igloult_Actions)
endfunction

Keywords:
iglo, needle, bristleback, ultimate
Contents

Еще одна карта (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 12:06, 2nd Sep 2011 Bribe: You don't need the "h" trigger, just drag the init hashtable line to the InitTrig_ function in your main trigger. If this is meant to be used with vanilla JASS...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: Too long as NeedsFix. Rejected.

12:06, 2nd Sep 2011
Bribe: You don't need the "h" trigger, just drag the init hashtable
line to the InitTrig_ function in your main trigger.

If this is meant to be used with vanilla JASS you need to list all of
the required udg_ variables, make a "variables" trigger that can
be copy pasted to auto generate the variables, or you can be super
awesome cool and combine the two and use GUIJASS like I do.

Put the code in hidden tags and add a better description including
import instructions.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
I only skimmed through the code... seems fine (i guess).

However:

1- it lacks documentation on how & what to import
2- When you first cast the spell, the direction of the needle's are pointed outwards instead of rotation direction
3- As for special effects, there are a few advices you could follow:
a. Try letting the needles' start location be the unit itself & then expand to their supposed locations (check this out: Comradesphip v1.03 -- not advertising my spell but this shows you what I'm talking about)
b. Do one of two things: in your case, all needles go at the same polar speed (i.e. the ones on the outside goes faster than the ones closer to the caster) making them rotate together and stay in synch with each other. Either, you let them rotate at the same actual speed (thus giving the impression that those closer and those farther away from the caster rotate at different speeds, OR actually let each rotate at a randomly picked speed and at a randomly picked radius and randomly picked direction which would look MUCH AWESOMER!
c. Try using another model for the needles 'cause this one looks odd: the trace left behind is actually a part of the needle model rather than a real trace, so it rotates with the needle instead of leaving a nice circular shaped trace.

Good job however :)


EDIT:
Use GetUnitX(or Y) instead of GetWidgetX(or Y)... the first is faster ;)

EDIT 2:
Make your code adjustable by setting global variables at the top which can be easily changed (as mentioned below by Magtheridon96)
 
Last edited:
JASS:
local real x = GetWidgetX(caster)
local real y = GetWidgetY(caster)

->

JASS:
local real x = GetUnitX(caster)
local real y = GetUnitY(caster)


local group g = CreateGroup()

This is a huge problem.
Just use a global group and clear it at the end.

JASS:
call GroupEnumUnitsInRange(g,x2,y2,120.,Filter(function IgloUltFilt))
call ForGroup(g,function IgloUltGroup)

Also, here, why don't you just do whatever you want with the units in the filter function using an if/then/endif statement? You could return false at the end then.
ForGroup is virtually useless here.

Tip: Don't destroy the global group, just clear it.


Also:

JASS:
    loop   
        exitwhen i > 4 * lvl + 5   
        if i <= 3 then   
            set d[i] = -240. * i * i + 1040. * i - 640.   
            set h[i] = 70. * i - 30.   
        else
            set a = 3
            loop
                exitwhen a > 18    
                if i > a and i <= 3 + a then   
                    set d[i] = -240. * (i - a) * (i - a) + 1040. * (i - a) - 640.   
                    set h[i] = 70. * (i - a) - 30.    
                endif
                set a = a + 3   
            endloop
        endif
        set i = i + 1   
    endloop

You could do this at map initialization for all levels.
Declaring local arrays is as bad as creating a local gruop and destroying it >.<


JASS:
function InitTrig_Igloult takes nothing returns nothing
    set gg_trg_Igloult = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Igloult,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(gg_trg_Igloult,Condition(function Trig_Igloult_Conditions))
    call TriggerAddAction(gg_trg_Igloult,function Trig_Igloult_Actions)
endfunction

Don't use TriggerAddAction, just add the actions as a condition and use an if statement to make sure the correct spell is being cast.
Conditions are much faster.


And, it's better if you use a local trigger here because that Global variable is dependent of the name of the trigger.

And in your actions function, you should declare a local integer for GetHandleId(t) since you're repeating that function call several times..

edit
And I agree with Deuterium about how your spell needs to be configurable.
Since it isn't vJASS, I'd recommend using functions that return the values instead of globals to keep this plain Jass :p
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
well mckill2009 what u say makes sense about the timer... but a local timer isn't a problem.. & honestly i prefer having a local timer since it's a spell to be imported into a map; in that case, even if u got a global timer, it's gna be only for this spell and thus would be almost as equally efficient as having the local timer.
(that is unless the mapper tweaks the triggers)

right?


i misread what u said mckill2009... so just scratch that :p
 
Last edited:
Top