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

Psychic Spell

This is my first spell i upload in hiveworkshop.com so i'm very worry :)
Here is my spell, as you see in picture: Make enemy area fly up and knock them down, deal damage.

Psychic spell requires GroupUtils, therefore send my special thank to Rising Dusk, a library very helpful!


Psychic spell
JASS:
library Psychic initializer init requires RepeatData, GroupUtils
/*
    spell Write by Daric Nguyen"
                    thanks to Rising_Dusk
                    
//=============================================================
    The spell very suitable with Blood Mage or Shaman :)
    
        Description:
            Your char make enemies around fly up 
                and when flyheight of enemy got to max
                    use Psychic and knock all enemies down
                        make enemies effected deal damage!
                        
                    Hope useful! 
            
        Requires:
            Group Utils
            Repeat Data (or similar Time System )
*/
globals
    private constant real DAMAGE=100 //Ability Damage
    private constant real TIME=.03      //Time loop
    private constant real RANGE=700 //Area of effect
    private constant string FX="Models\\PsychicTarget.mdl"  //Effect on target unit
    private constant string SFX="Models\\GrandUndeadAura.mdl" // Effect on caster unit
    private constant string SFX2="Models\\NewGroundEX.mdx" // Effect Explosion
    private constant attacktype ATT=ATTACK_TYPE_HERO
    private constant damagetype DMT=DAMAGE_TYPE_MAGIC
endglobals

function trig_con takes nothing returns boolean
    return ( GetSpellAbilityId() == 'A000' )
endfunction

private struct Psychic extends RepeatData
    unit caster
    unit target
    real fly
    real mfly
    boolean isfly
    effect deff
    real per
    // variables
    method onLoop takes nothing returns nothing
        local real x
        local real y
        local real dx
        local real dy
        set x=GetUnitX(this.target)
        set y=GetUnitY(this.target)
        set dx=x+GetRandomReal(0,5)*Cos((GetUnitFacing((this.target)))*bj_DEGTORAD)
        set dy=y+GetRandomReal(0,5)*Sin((GetUnitFacing((this.target)))*bj_DEGTORAD)
        call UnitAddAbility((this.target),'Amrf') 
        call SetUnitPosition((this.target),dx,dy)
        call SetUnitFlyHeight((this.target),this.fly,0)
        call UnitRemoveAbility((this.target),'Amrf')
        if this.isfly==true then // check is unit fly up
            if this.fly>=this.mfly then
                set this.isfly=false
            endif
            set this.fly=this.fly+4
        else
            if this.fly<=0 then
                call this.stop()
            endif
            set this.fly=this.fly-100
        endif   
    endmethod
    method onStart takes nothing returns nothing
        call PauseUnit(this.target,true)
        call SetUnitTimeScalePercent(this.target,0) // stop target unit animation
        set this.deff=AddSpecialEffectTarget(FX,this.target,"chest") // add effect on target
    endmethod
    method onEnd takes nothing returns nothing
        set this.per=(this.mfly / 500) // calculate damage increases percent or decreases percent follow max fly height
        if this.per<=.5 then
            set this.per=.5 // if decreases damage percent less than 50%, set it's 50%
        endif
        if this.per>=1.2 then
            set this.per=1.2 // if increases damage percent greater than 120%, set it's 120%
        endif
        call DestroyEffect(this.deff) // destroy effect attackment in target unit
        call UnitDamageTarget(this.caster,this.target,DAMAGE*this.per,false,false,ATT,DMT,null)
        call PauseUnit(this.target,false) // deal damage and unpause target unit
        call SetUnitTimeScalePercent(this.target,100) // unstop unit animation
        call DestroyEffect(AddSpecialEffect(SFX2,GetUnitX(this.target),GetUnitY(this.target))) // create explosion effect
        
        set this.target=null
        set this.caster=null
    endmethod
endstruct

private function PsychicAUnit takes unit source, unit t, real max returns nothing
    local Psychic ps=Psychic.create(0.03,0)
    set ps.caster=source
    set ps.target=t
    set ps.mfly=max
    set ps.isfly=true
    set ps.fly=0
endfunction

private struct Psychic2 extends RepeatData
    unit caster
    unit dum
    effect deff
    real nfly
    real xx
    real yy
    real t1
    real t2
    real scale
    group g
    // variables
    method onLoop takes nothing returns nothing
        local unit e
        if this.t1<= 3.4 then
            if this.t1==0 then
                call SetUnitTimeScalePercent(this.caster,0)
            endif
            set this.t1=this.t1+0.06
            // check unit around caster
            call GroupEnumUnitsInRange(this.g,this.xx,this.yy,700,null)
            loop
                set e=FirstOfGroup(g)
                exitwhen e==null
                if IsUnitEnemy(e,GetOwningPlayer(this.caster)) and GetWidgetLife(e)>0.405 and IsUnitType(e,UNIT_TYPE_STRUCTURE)==false and IsUnitPaused(e)==false then
                    call PsychicAUnit(this.caster,e,(this.nfly+(GetRandomReal(-40,50)))) // pick up enum unit
                endif
                call GroupRemoveUnit(this.g,e)
            endloop
            call GroupRefresh(this.g)
            set this.nfly=this.nfly-8
        else
            if this.t2 ==255 then
                // unpause caster
                call PauseUnit(this.caster,false)
                call SetUnitTimeScalePercent(this.caster,100)
                set this.caster=null
            endif
            set this.t2=this.t2-10
            set this.scale=this.scale+0.02
        endif
        if this.t2<=0 then
            call this.stop()
        else
            call SetUnitVertexColor(this.dum,R2I(this.t2),R2I(this.t2),R2I(this.t2),R2I(this.t2))
            call SetUnitScale(this.dum, this.scale, this.scale, this.scale)
        endif
        set e=null
    endmethod
    method onStart takes nothing returns nothing
        call PauseUnit(this.caster,true)
        set this.dum=CreateUnit(Player(15),'h000',this.xx,this.yy,0)
        set this.deff=AddSpecialEffectTarget(SFX,this.dum,"origin")
    endmethod
    method onEnd takes nothing returns nothing
        // remove leak when method end
        call DestroyEffect(this.deff)
        call RemoveUnit(this.dum)
        call ReleaseGroup(this.g)
        set this.dum=null
    endmethod
endstruct


function trig_act takes nothing returns nothing
    local unit cast=GetTriggerUnit()
    local real x=GetUnitX(cast)
    local real y=GetUnitY(cast)
    local Psychic2 this=Psychic2.create(0.05,0) // (0.05= time loop per 0.05s,0= never end if don't use call this.stop() in any method)
    // now add some variables you need save in struct Psychic2
    set this.caster=cast
    set this.t1=0              // time tick one
    set this.t2=255         // time tick two, also is alpha real
    set this.yy=y           // save Yof caster
    set this.xx=x           // save X of caster
    set this.nfly=500   // save maximun fly height
    set this.scale=1.00 // save scale
    set this.g=NewGroup()
    set cast=null
endfunction

//===========================================================================
function init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( trig, Condition( function trig_con ) )
    call TriggerAddAction( trig, function trig_act )
    set trig=null
endfunction

endlibrary


Thank for use :D

Keywords:
repeat, data, loop, timer, time, psychic
Contents

Repeat Data - Psychic (Map)

Reviews
Update 26 April 2012 Bribe: This is a largely-unoptimized script. This resource also lacks importing instructions, deviating from our recommended standards. Please include these. Resource approved 2/5. 23rd Feb 2012 Bribe: The spell doesn't work...

Moderator

M

Moderator

Update 26 April 2012
Bribe: This is a largely-unoptimized script. This resource also lacks importing instructions, deviating from our recommended standards. Please include these. Resource approved 2/5.

23rd Feb 2012
Bribe: The spell doesn't work when I try it out. And it creates a huge amount of lag after the second cast. Within your map, you should also change the importing instructions and the demo script to highlight the Psychic spell and not the timer system.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
We already have things that do this:

http://www.hiveworkshop.com/forums/showthread.php?t=201381
http://www.thehelper.net/forums/showthread.php?t=132538
http://www.wc3c.net/showthread.php?t=105515

I don't really feel like approving yet another timer system that offers no utility which wasn't already there.

It is also important to note that function interfaces, while user-friendly, compile the code into a huge bloated mess. It is best to avoid this cr*p-tastic feature in 100% of cases.

The spell looks cool though.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
This spell is rejected without any moderator's comment posted after the rating.. -_- I don't know that this thing is important or not.. But this is firstly I see an accident like this.. I know that the creator is new here and I think this spell/system is good enough for a new user.. So please appreciate him.. But I don't mean moderator to approve this.. :D just leave comments for him after the rating bar..
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Some things are conceptually bad (like this, where I have pointed out at least three way better versions that do the same thing) or simply require so much work that the spell itself is so simple and full of bugs that it's unsalvageable (the moderator has to take the time to point out every mistake to the point where it's not even the user's work any more). Resources that are bad to that point should be submitted to the Triggers / Scripts forum, first, so that they can be developed.
 
Level 2
Joined
Feb 21, 2012
Messages
5
thank for suggestion! :D
but i think i still update this library, because each people have a different favorite, some people like using T32 system because it be trusted, and some people likes the simple when use, or the neat when they write spells (here, whenLoop,End and Start method).
And as my said in Spell Details, I hope it's useful, for everybody :) .
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
Well the normal naming convention is onLoop/onStart/onFinish, if you want it to be more intuitive. I think the spell is good but if you are submitting the timer system standalone it is not approvable. Sure you can have multiple libraries for one spell, so if this is to be approved you just change the spell name to "just the name of the spell" and not mention the timer system other than in the importing instructions, that way you circumvent one of the rules I have.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I can see you updated the code you posted here but your map still shows the "when" stuff instead of the "on" stuff.

You also would do way way better to get rid of the ".g" variable. It can be replaced with a constant group which never gets destroyed. Also keep in mind that "GroupEnum"... clears the group before enumerating new units, and that FirstOfGroup loops also clear the group.

In fact you don't even need GroupUtils here. At all.
 
Top