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

Holy v1.03

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
- Link Youtube -
https://www.youtube.com/watch?v=xFtNDFCgjLY

JASS:
scope test initializer int
    globals
        //================================================================
        //=             ----- Object of Spells Ability -----             =
        //================================================================
        //  1. Spells ID
            private constant    integer         SPELL_ID            =   'A000'
            
        //  2. Dummy ID and total dummy
            private constant    integer         DUMMY               =   'h000'
            private constant    integer         MAX_DUMMY           =   8
            
        //  3. Effects on caster
            private constant    string          EFFECT              =   "Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl"
            private constant    string          POINT_EFFECT        =   "origin"
            
            private constant    string          EFFECT2             =   "Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl"
            private constant    string          POINT_EFFECT2       =   "origin"
            
        //  4. Effect on target
            private constant    string          EFFECT3             =   "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
            private constant    string          POINT_EFFECT3       =   "origin"
         
        //  5. Damage of per dummy deal each target
            //  DAMAGE = INIT_DAMAGE + Level_Ability*PER_DAMAGE     
            private constant    real            INIT_DAMAGE         =   10 
            private constant    real            PER_DAMAGE          =   10
            
        //----------------------------------------------------------------
            private constant    string          INIT_SOUND          =   "Abilities\\Spells\\Human\\Defend\\DefendCaster.wav"
            private constant    string          DUMMY_SOUND         =   "Abilities\\Weapons\\AvengerMissile\\DestroyerMissile.wav"
        
            private constant    integer         BORN_TIME           =   4       
            private constant    integer         MOVE_TIME           =   16
                            
            private constant    real            AOE                 =   400            
            private constant    real            MAX_HEIGHT          =   600            
            private constant    real            MAX_ANGLE           =   3*bj_PI
            private constant    real            RADIUS              =   400
            private constant    real            HEIGHT_TARGET       =   50
                    
        //================================================================
            private constant    real            PI_P2               =   bj_PI/2
            private constant    real            PI_2                =   2*bj_PI
            
            private constant    real            AOE_P2              =   AOE/2
            private constant    real            AOE_P3              =   AOE/3
            private constant    real            AOE_5P6             =   5*AOE/6
            
            private constant    integer         MOVE_TIME2          =   2*MOVE_TIME
            private constant    integer         MOVE_TIME4          =   4*MOVE_TIME
            private constant    integer         MOVE_TIME5          =   5*MOVE_TIME
            private constant    integer         MOVE_TIME6          =   6*MOVE_TIME
            private             integer         SOUND_VOLUME        = 127
            
            private constant    real            TICK_TIME           =   0.03125

            private             boolean         bool                =   true

            private             real    array   SIN1[MOVE_TIME]
            private             real    array   SIN2[MOVE_TIME]
            private             real    array   SIN3[MOVE_TIME2]
                        
            private             real            temp                                   
    endglobals

    private struct data   
        unit                caster
        real                xc
        real                yc
        
        integer             level
                    
        unit                target
        real                xt
        real                yt
        real                zt
        boolean             fly
        
        unit        array   dummy[MAX_DUMMY]
        real        array   x[MAX_DUMMY]
        real        array   y[MAX_DUMMY]
        real        array   z[MAX_DUMMY]
        real        array   facing[MAX_DUMMY]
        integer     array   tick[MAX_DUMMY]
        real        array   rand[MAX_DUMMY]
        real                distance
        real                angle
        integer             tack
      
        integer             i
        integer             max
        real                temp
        real                DAMAGE
    endstruct
    
    private function AddEvent takes trigger trig, playerunitevent whichEvent returns nothing
        local integer index = 0
        loop
            call TriggerRegisterPlayerUnitEvent(trig, Player(index), whichEvent, null)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
    endfunction
    
    private function PlaySoundEx takes unit u, string path returns nothing
        local sound s = CreateSound(path, false, true, true, 12700, 12700, "DefaultEAXON")
        call SetSoundVolume(s, SOUND_VOLUME)
        set SOUND_VOLUME = 127
        call SetSoundChannel(s, 5)
        call SetSoundPitch(s, 1.00001)
        call SetSoundDistances(s, 600, 10000)
        call SetSoundDistanceCutoff(s, 3000)
        call SetSoundConeAngles(s, 0, 0, 127)
        call AttachSoundToUnit(s, u)
        call StartSound(s)
        if HaveSavedBoolean(ht, 0x906120, StringHash(path)) then
            call KillSoundWhenDone(s)
        else
            call SaveBoolean(ht, 0x906120, StringHash(path), true)
        endif
        set s = null
    endfunction
        
    private function update takes nothing returns nothing
        local data this = getRT()
        set this.xc = GetUnitX(this.caster)
        set this.yc = GetUnitY(this.caster)
            
        set this.i = 1
        loop
            exitwhen this.i > this.max
            exitwhen this.i > MAX_DUMMY
                
            if this.tick[this.i] == BORN_TIME then
                set this.max = this.max + 1
            endif
                
            if this.tick[this.i] == 0 then
                // --- Create ---
                set this.dummy[this.i] = CreateUnit(GetOwningPlayer(this.caster), DUMMY, this.xc, this.yc, 270)
                call PlaySoundEx(this.caster, INIT_SOUND)
            elseif this.tick[this.i] < MOVE_TIME then
                // --- Jump 1 ---
                set this.distance = AOE_P3 - SIN2[MOVE_TIME - this.tick[this.i]]*AOE_P3
                
                set this.temp = this.xc + this.distance*Cos(this.facing[this.i])
                call SetUnitX(this.dummy[this.i], this.temp)
                
                set this.temp = this.yc + this.distance*Sin(this.facing[this.i])
                call SetUnitY(this.dummy[this.i], this.temp)
                    
                set this.temp = SIN1[this.tick[this.i]]*AOE_P3
                call SetUnitFlyHeight(this.dummy[this.i], this.temp, 0)
            elseif this.tick[this.i] == MOVE_TIME then
                // --- End jump 1 and initializer jump 2 ---
                set this.x[this.i] = this.xc + AOE_P3*Cos(this.facing[this.i])
                set this.y[this.i] = this.yc + AOE_P3*Sin(this.facing[this.i])
                    
                call SetUnitX(this.dummy[this.i], this.x[this.i])
                call SetUnitY(this.dummy[this.i], this.y[this.i])
                call SetUnitFlyHeight(this.dummy[this.i], 0, 0)
                    
                set this.facing[this.i] = this.facing[this.i] + bj_PI
            elseif this.tick[this.i] < MOVE_TIME2 then
                // --- Jump 2 ---
                set this.tack = this.tick[this.i] - MOVE_TIME
                set this.distance = SIN2[this.tack]*AOE_5P6
                
                set this.temp = this.x[this.i] + this.distance*Cos(this.facing[this.i])
                call SetUnitX(this.dummy[this.i], this.temp)
                
                set this.temp = this.y[this.i] + this.distance*Sin(this.facing[this.i])
                call SetUnitY(this.dummy[this.i], this.temp)
                    
                set this.temp = SIN1[this.tack]*AOE_5P6
                call SetUnitFlyHeight(this.dummy[this.i], this.temp, 0)
            elseif this.tick[this.i] == MOVE_TIME2 then
                    // --- End jump 2 and initializer fly dummy ---
                set this.x[this.i] = this.x[this.i] + AOE_5P6*Cos(this.facing[this.i])
                set this.y[this.i] = this.y[this.i] + AOE_5P6*Sin(this.facing[this.i])
                    
                call SetUnitX(this.dummy[this.i], this.x[this.i])
                call SetUnitY(this.dummy[this.i], this.y[this.i])
                call SetUnitFlyHeight(this.dummy[this.i], 0, 0)
                    
                set this.facing[this.i] = this.facing[this.i] + bj_PI
            elseif this.tick[this.i] < MOVE_TIME4 then
                // --- Fly dummy ---
                set this.tack = this.tick[this.i] - MOVE_TIME2
                set this.distance = SIN3[this.tack]*MAX_HEIGHT
                set this.angle = SIN3[this.tack]*MAX_ANGLE
                    
                set this.temp = this.xc + AOE_P2*Cos(this.facing[this.i] - this.angle)
                call SetUnitX(this.dummy[this.i], this.temp)
                    
                set this.temp = this.yc + AOE_P2*Sin(this.facing[this.i] - this.angle)
                call SetUnitY(this.dummy[this.i], this.temp)
                    
                call SetUnitFlyHeight(this.dummy[this.i], this.distance, 0)
            elseif this.tick[this.i] == MOVE_TIME4 then
                // --- End fly dummy and initializer stand dummy ---
                set this.x[this.i] = this.xc + AOE_P2*Cos(this.facing[this.i] - MAX_ANGLE)
                set this.y[this.i] = this.yc + AOE_P2*Sin(this.facing[this.i] - MAX_ANGLE)
                set this.z[this.i] = MAX_HEIGHT
                    
                set this.rand[this.i] = GetRandomInt(1, 360)*bj_PI/180
                    
                call SetUnitX(this.dummy[this.i], this.x[this.i])
                call SetUnitY(this.dummy[this.i], this.y[this.i])
                call SetUnitFlyHeight(this.dummy[this.i], MAX_HEIGHT, 0)
            elseif this.tick[this.i] < MOVE_TIME5 then
                // --- Stand dummy ---
                set this.x[this.i] = this.xc + AOE_P2*Cos(this.facing[this.i] - MAX_ANGLE)
                set this.y[this.i] = this.yc + AOE_P2*Sin(this.facing[this.i] - MAX_ANGLE)
                    
                call SetUnitX(this.dummy[this.i], this.x[this.i])
                call SetUnitY(this.dummy[this.i], this.y[this.i])
            elseif this.tick[this.i] == MOVE_TIME5 then
                // --- End stand dummy and initializer fall dummy ---
                set this.x[this.i] = this.xc + AOE_P2*Cos(this.facing[this.i] - MAX_ANGLE)
                set this.y[this.i] = this.yc + AOE_P2*Sin(this.facing[this.i] - MAX_ANGLE)
                    
                call SetUnitX(this.dummy[this.i], this.x[this.i])
                call SetUnitY(this.dummy[this.i], this.y[this.i])
                    
                call PlaySoundEx(this.dummy[this.i], DUMMY_SOUND)    
            elseif this.tick[this.i] < MOVE_TIME6 then
                // --- Fall dummy ---
                set this.tack = this.tick[this.i] - MOVE_TIME5
                    
                set this.xt = GetUnitX(this.target)
                set this.yt = GetUnitY(this.target)
                    
                if this.fly then
                    set this.zt = GetUnitFlyHeight(this.target)
                else    
                    set this.zt = GetUnitFlyHeight(this.target) + HEIGHT_TARGET
                endif
                    
                set this.distance = SIN2[this.tack]*SquareRoot((this.xt - this.x[this.i])*(this.xt - this.x[this.i]) + (this.yt - this.y[this.i])*(this.yt - this.y[this.i]))
                set this.angle = Atan2(this.yt - this.y[this.i], this.xt - this.x[this.i])
                   
                set this.temp = this.x[this.i] + this.distance*Cos(this.angle)
                set this.temp = this.temp + SIN1[this.tack]*RADIUS*Cos(this.rand[this.i])*Cos(this.angle - PI_P2)
                call SetUnitX(this.dummy[this.i], this.temp)
                    
                set this.temp = this.y[this.i] + this.distance*Sin(this.angle)
                set this.temp = this.temp + SIN1[this.tack]*RADIUS*Cos(this.rand[this.i])*Sin(this.angle - PI_P2)
                call SetUnitY(this.dummy[this.i], this.temp)

                set this.temp = this.z[this.i] + SIN2[this.tack]*(this.zt - this.z[this.i])
                call SetUnitFlyHeight(this.dummy[this.i], this.temp, 0)
            elseif this.tick[this.i] == MOVE_TIME6 then
                //  --- Damage target ---
                call RemoveUnit(this.dummy[this.i])
                    
                if  IsUnitEnemy(this.target, GetOwningPlayer(this.caster)) and GetUnitState(this.target, UNIT_STATE_LIFE) > 0 and not IsUnitType(this.target, UNIT_TYPE_STRUCTURE) then
                    call DestroyEffect(AddSpecialEffectTarget(EFFECT3, this.target, POINT_EFFECT3))
                    call UnitDamageTargetBJ(this.caster, this.target, this.DAMAGE, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL )
                endif
                    
                set this.dummy[this.i] = null
                    
                if this.i == MAX_DUMMY then
                    set this.caster = null
                    set this.target = null
                    call breakRT()
                    call this.destroy()
                    return
                endif 
            endif
                      
            set this.tick[this.i] = this.tick[this.i] + 1
            set this.i = this.i + 1
        endloop               
    endfunction

    private function f takes nothing returns nothing
        local real      fa
        local integer   i       =   1
        local data      this    =   data.create()
        
        set this.caster         =   GetTriggerUnit()                
        set this.target         =   GetSpellTargetUnit()
        set this.fly            =   IsUnitType(this.target, UNIT_TYPE_FLYING) 
        set this.level          =   GetUnitAbilityLevel(this.caster, SPELL_ID)
        set this.DAMAGE         =   INIT_DAMAGE + this.level*PER_DAMAGE
        set this.max            =   1         
        set fa                  =   GetUnitFacing(this.caster)
        
        loop
            exitwhen i > MAX_DUMMY
            set this.tick[i]    =   0
            set this.facing[i]  =   fa + (PI_2*(i - 1))/MAX_DUMMY  
            set i = i + 1
        endloop
        
        if bool then
            set i = 1
            loop
                exitwhen i > MOVE_TIME
                set SIN1[i]    =   Sin((i*bj_PI)/MOVE_TIME)
                set SIN2[i]    =   Sin((i*PI_P2)/MOVE_TIME)
                set i = i + 1
            endloop
        
            set i = 1
            loop
                exitwhen i > MOVE_TIME2
                set SIN3[i]    =   Sin((i*PI_P2)/MOVE_TIME2)
                set i = i + 1
            endloop
            
            set bool = false
        endif
        
        call DestroyEffect(AddSpecialEffectTarget(EFFECT, this.caster, POINT_EFFECT))
        call DestroyEffect(AddSpecialEffectTarget(EFFECT2, this.caster, POINT_EFFECT2))
                        
        call addRT(this, TICK_TIME, true, function update)
    endfunction

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

//===========================================================================
    private function int takes nothing returns nothing
        local trigger t = CreateTrigger()
        call AddEvent(t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(t, Condition( function c ) )
        call TriggerAddAction(t, function f )
    endfunction

endscope

JASS:
//=========================================================================================
//  ____              _   _                                                     
// |  _ \ _   _ _ ___| |_(_)_ __ __  ___ 
// | |_) ) | | | '_  | __| | '  '  |/ _ \
// |  _ /| |_| | | | | |_| | || || |  __/
// |_| \_\___._|_| |_|\__|_|_||_||_|\___|
//=========================================================================================
library Runtime initializer int
    globals
        constant hashtable       ht = InitHashtable()
    endglobals
    
    function addRT takes integer i, real timeout, boolean periodic, code func returns nothing
        local timer t = CreateTimer()
        local integer id = GetHandleId(t)
        if t == null then
        call BJDebugMsg(SCOPE_PREFIX + "Warning: Overflow runtime blue")
        return
        endif
        call SaveInteger(ht, id, 0, i)
        call SaveInteger(ht, id, 2, 0)//count <<
        call SaveReal(ht, id, 1, timeout)
        call TimerStart(t,timeout,periodic,func)
        set t = null
    endfunction
    
    function getRT takes nothing returns integer
        local integer id = GetHandleId(GetExpiredTimer())
        local integer i = LoadInteger(ht,id, 0)
        call SaveInteger(ht,id,2,LoadInteger(ht,id,2)+1)
        return i
    endfunction
    
    function countRT takes nothing returns real
        local integer id = GetHandleId(GetExpiredTimer())
        local real result = I2R(LoadInteger(ht,id,2)) * LoadReal(ht,id, 1)
        return result
    endfunction
    
    function breakRT takes nothing returns nothing
        local timer t=GetExpiredTimer()
        call PauseTimer(t)
        call FlushChildHashtable(ht, GetHandleId(t))
        call DestroyTimer(t)
        set t = null
    endfunction
//=========================================================================================
    private function int takes nothing returns nothing
    endfunction
endlibrary

Keywords:
Holy, Light, Final Fantasy, Spells, White Mage's
Contents

Holy v1.03 (Map)

Reviews
12th Dec 2015 IcemanBo: Too long as NeedsFix. Rejected. 22:47, 2nd Aug 2014 BPower: Need Fix http://www.hiveworkshop.com/forums/spells-569/holy-v1-03-a-253676/index2.html#post2561062 16:55, 22nd Jul 2014 BPower: Not approve-able aslong...

Moderator

M

Moderator

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

22:47, 2nd Aug 2014
BPower: Need Fix

http://www.hiveworkshop.com/forums/spells-569/holy-v1-03-a-253676/index2.html#post2561062

16:55, 22nd Jul 2014
BPower:
Not approve-able aslong as it depends on ExortKit.
 
Very clear coding ;). But you have to rename library and method c and f if it isn't a part of frame and please explain your configurable.

If this is not a part of your habit, remove this. in front of variables

set this.SIN1[i] = Sin((i*bj_PI)/MOVE_TIME) set this.SIN2[i] = Sin((i*bj_PI)/(2*MOVE_TIME)) set this.temp = this.temp + this.SIN1[this.tack]*RADIUS*Cos(this.rand[this.i])*Cos(this.angle - bj_PI/2) set this.temp = this.temp + this.SIN1[this.tack]*RADIUS*Cos(this.rand[this.i])*Sin(this.angle - bj_PI/2)

Looks like i*bj_PI,RADIUS*Cos(this.rand[this.i])*Sin(this.angle - bj_PI/2) used twice during period, save it to variable and bj_PI/2 = 1.57078

set this.dummy[this.i] = CreateUnit(GetOwningPlayer(this.caster), DUMMY, xc, yc, 270)

Save GetOwningPlayer as a member of struct.

GetUnitState(this.target, UNIT_STATE_LIFE) > 0 => GetWidgetLife, this is faster than GetUnitState. You can simply use UnitAlive or IsUnitType(whichUnit,UNIT_TYPE_DEAD) and GetUnitTypeId(whichUnit) != 0 to assure a better death check.

Save ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL on configurable. Get rid of BJs

This is using for? set this.fly = IsUnitType(this.target, UNIT_TYPE_FLYING) , if a unit have a fly height or SetUnitPathing=true without UNIT_TYPE_FLYING or a target is going to fly while this spell is casting?.

set this.facing[i] = fa + (2*bj_PI*(i - 1))/MAX_DUMMY

2*bj_PI = 6.28318

local integer i = 1 and (2*bj_PI*(i - 1))

=>

local integer i = 0 and (2*bj_PI*i)

set this.SIN2[i] = Sin((i*bj_PI)/(2*MOVE_TIME))

Save 2*MOVE_TIME and i*bj_PI to variable and this too set this.SIN3[i] = Sin((i*bj_PI)/(2*MOVE_TIME2))

I think you have to put function f to function c since function c is faster than function f (Conditions => Action) and then simply check it.

I think the member of hive, they are using JNPG and Regular WE than XDesign Pack v1.06.

Use timer is fast enough.

Inside library ExortKit has some useless function such as:

JASS:
function HideUnitInMap takes unit u returns nothing
        call UnitSetUsesAltIcon(u, true)
    endfunction

    function ShowUnitInMap takes unit u returns nothing
        call UnitSetUsesAltIcon(u, false)
    endfunction
function PrintPlayer takes player p, string s, real d returns nothing
        if d == 0 then
            call DisplayTextToPlayer(p, 0, 0, s)
        else
            call DisplayTimedTextToPlayer(p, 0, 0, d, s)
        endif
    endfunction
function Print takes string s, real d returns nothing
        if d == 0 then
            call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, s)
        else
            call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, d, s)
        endif
    endfunction
 function GetChance takes real r returns boolean
        if (r >= 100) or GetRandomReal(0.00, 100.00) <= r then
            return true
        endif
        return false
    endfunction
       
    function IsGameDay takes nothing returns boolean
        if(GetTimeOfDay() > 6.00 and GetTimeOfDay() < 18.00)then
            return true
        else
            return false
        endif
    endfunction
       
    function GetPID takes player whichPlayer returns integer
        return GetPlayerId(whichPlayer)
    endfunction
       
    function GetUID takes unit u returns integer
        return GetPlayerId(GetOwningPlayer(u))
    endfunction
function GetHandleU takes unit u returns integer
        return GetHandleId(GetOwningPlayer(u))
    endfunction
       
    function GetHandleP takes player p returns integer
        return GetHandleId(p)
    endfunction
function GetWDB takes widget a, widget b returns real
        return GetDB(GetWidgetX(a), GetWidgetY(a), GetWidgetX(b), GetWidgetY(b))
    endfunction

    function GetWAB takes widget a, widget b returns real
        return GetAB(GetWidgetX(a), GetWidgetY(a), GetWidgetX(b), GetWidgetY(b))
    endfunction
function IsPlayerOnline takes player p returns boolean
        return GetPlayerSlotState(p) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(p)==MAP_CONTROL_USER
    endfunction
   
    function IsPlayerLeft takes player p returns boolean
        return GetPlayerSlotState(p) == PLAYER_SLOT_STATE_LEFT and GetPlayerController(p)==MAP_CONTROL_USER
    endfunction
   
    function IsPlayerEmpty takes player p returns boolean
        return (GetPlayerSlotState(p) == PLAYER_SLOT_STATE_EMPTY)
    endfunction

function PlayerId takes player whichPlayer returns integer
        return GetPlayerId(whichPlayer) + 1
    endfunction

//This function is using for?. Each spell has a different way of creating.

function CreateDummy takes player owner, integer unitid, real x, real y, real face, real dur returns unit
        local unit u = CreateUnit(owner, unitid, x, y, face)
        call SetUnitPathing(u, false)
        call SetUnitX(u, x)
        call SetUnitY(u, y)
        call UnitApplyTimedLife(u, 'BTLF', dur)
        return u
    endfunction
function SetFastAnimation takes unit whichUnit, real percentScale returns nothing
        call SetUnitTimeScale(whichUnit, percentScale * 0.01)
    endfunction
       
    function RemoveUnitEx takes unit c returns nothing
        call UnitApplyTimedLife(c, 'BTLF', 0.01)
    endfunction

And more...


They can do it without those function ;).

Using interface isn't a good idea.

More function => more compile => more spaces.

This spell is cool by the way, so 5/5 ;).
 
Last edited:

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
Not really "very good". Much can be improved, in current state it's unacceptable.

At first, and foremost: make it independant of "ExortKit". It's bad design to make script requiring some random pack of functions which share names with multiple popular libraries api which handle such operations better and more convenient than your wierd lib.

Struct fields and global variables count can definitely be reduced. Your approach can also use some improvements.
Merge conditions and actions -> apply whole expression via conditions, it is a common way to script spells and it has been for years now.

GetUnitState(this.target, UNIT_STATE_LIFE) > 0 into GetWidgetLife(target) > 0.405. Drop UnitDamageTargetBJ for native instead.

Code is unreadable, escpecially because of "this" spam. You could place functions into struct as static methods - when "this" has been defined, it will be automatically included before each of struct fields greatly improving readability.

Use one global timer instead of your triggers/evaluations/periodic event. Uhh..
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Please code your spell without the ExortKit. Bannar basically pointed out the main reasons why your submission is not approve-able, aslong as it depends on the ExortKit.
Function packs are not very welcome in general. A good rule is that external libraries should only cover excacly their purpose e.g. a Timer library should only cover timer related code.
Of course this applies for public resources, what you prefer/do within your own map/coding is totally up to you.
 

Bannar

Code Reviewer
Level 26
Joined
Mar 19, 2008
Messages
3,140
If you do so, the whole point of spell uploading is lost.
We do want you to upload new spells, join the community, have fun, spam jokes, find new friends.

However, we are also into teaching ppl new/better/more efficient/more convenient ways of scripting within war3 environment. Wouldn't you be better satisfied with your work if at the end you heard "good job, bgcy_ro002"? Surely you would. None of us is here to deny yours, or anybody else' work - contrary, we are here to help you develop your skills.

At the end its both, better for you and community.
Don't be afraid to ask any questions that may seem to trouble you.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Okay let's get started:

1. The AddEvent function is not really nessesary, because it doesn't add any extra efficiency or could be used as wrapper because your spell is a scope. If you wish to do so you could use RegisterPlayerUnitEvent or better SpellEffectEvent from our JASS section.
If not you could just add what AddEvent does into private function int.
Furthermore remove the line TriggerAddAction and do the integer comparison for the correct SpellAbilityId() directly in function f.
Talking about the naming a little bit more generic function names are appreciated. private function f --> private function run/spell/action/....

The current version of JNGP 2.x does highlight int and bool in its standart settings, it would be very nice if you avoid those in your code.
JASS:
    private function int takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer index = 0
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT , null)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition( function c ) )
    endfunction

2. I can only recommend to stick to the JPAG ruleset. It makes your code much more readable and clean looking.
e.g. set this.DAMAGE =... --> set this.damage =...
if bool then --> please relabel bool into a more self-explanatory variable name. You may also add one line in the globals and explain what this boolean actually does.
JASS:
    private function f takes nothing returns boolean
        local real      fa
        local integer   i       =   1
        local data      this  
        
        if GetSpellAbilityId() == SPELL_ID then
            set this = data.create()
            .....
        endif
        return false
    endfunction

I will think about a better solution for your update function when I have more time. Currently it looks messy.

Don't feel discouraged, people here are just trying to help you. The spell itself looks cool, judging from the screenshot and video.
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
Nothing changed since my last review.

I would like to add a couple of things:

call UnitDamageTargetBJ(this.caster, this.target, this.DAMAGE, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL ) --> replace the BJ with native UnitDamageTarget

if IsUnitEnemy(this.target, GetOwningPlayer(this.caster)) and GetUnitState(this.target, UNIT_STATE_LIFE) > 0 and not IsUnitType(this.target, UNIT_TYPE_STRUCTURE) then --> This filter should be part of the user configuration.

Instead of Runtime you could use the much more convenient library TimerUtils.
 
Level 14
Joined
Nov 18, 2007
Messages
816
MOVE_TIME should be called MOVE_TICKS. Alternatively, you make MOVE_TIME behave as the name indicates and let the users configure a time directly there. The latter option is better for users, by the way.

Why do you filter again when damaging the unit? Shouldnt that already have been handled by the allowed targets of the ability?

Why do you use this.i as an index variable instead of a local variable?
 
Level 6
Joined
May 23, 2011
Messages
295
is the name suposed to be only Holy? i think it would be better to to slap something like Holy Strike or Holy/Divinine Judgement
 
Top