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

one Jass spell quest

Status
Not open for further replies.
Level 28
Joined
Jan 26, 2007
Messages
4,789
I didn't try it, but this might work:


JASS:
    private function Damage takes integer level returns real // PROXY
        return GetHeroStr(GetTriggerUnit())
    endfunction
(it's right beneath the other Damage-function)

If the 'GetTriggerUnit()' isn't recognized, then you should do this:

JASS:
    private function Damage takes integer level, unit Hero returns real // PROXY
        return GetHeroStr(Hero)
    endfunction
And then press CTRL + F to find "Damage(s.level)" (there will be 2 matches, you need to change both of them).
Change it to this: Damage(s.level, s.c)

That's my guess at least :p


Oh yeah, you can use 'level' in the formula as well, like this:
GetHeroStr(Hero) + level * 50
This is just an example...


Edit: If you wonder why I didn't use the GetheroStrength(...) in the SetUpDAMAGE, it's because I think that function is initialized at map init, meaning the hero might not even exist by then.
 
Level 11
Joined
Oct 13, 2008
Messages
560
this

:sadpanda:
 

Attachments

  • asdasdsad.JPG
    asdasdsad.JPG
    132.4 KB · Views: 111
Level 28
Joined
Jan 26, 2007
Messages
4,789
behind is back?

i o

i is behind "o"?
Behind is after

i o

o is after i
o is behind i


And Anachron is right: it's because I didn't see that it needs a real, so I used an integer.
You can use I2R(my previous code) as well.
I2R means Integer to Real.

If you don't know the difference:
10 is an integer,
10.00 is a real.

basically, numbers with a comma are reals, while integers don't have a comma.
 
Level 11
Joined
Oct 13, 2008
Messages
560
Same error

=\

See this
Too many arguments passed on the function
set s__Boomerang___Data_dam1=Boomerang___Damage(s__Boomerang___Data_level , s__Boomerang___Data_c)


See this

Too many arguments passed on the function
set s__Boomerang___Data_dam1=Boomerang___Damage(s__Boomerang___Data_level , s__Boomerang___Data_c)
 
I can't even find the line "set s__Boomerang___Data_dam1=Boomerang___Damage(s__Boomerang___Data_level , s__Boomerang___Data_c)" in the entire code.


s__ stands for struct, so in the Boomerang Data struct the call of Boomerang___Damage (The function you have written for him) is taking one argument to much.
 
Level 28
Joined
Jan 26, 2007
Messages
4,789
s__ stands for struct, so in the Boomerang Data struct the call of Boomerang___Damage (The function you have written for him) is taking one argument to much.
Ah, okay, I'm not really familiar with vJass ^^


Unfortunately, I cannot save with the NewGen WE...
I'll have to do it without testing, so it can bug.

This is how I would write the code:

JASS:
library_once Boomerang uses GroupUtils, xefx, DestructableLib, IsTerrainWalkable
    
    private keyword Data // DO NOT TOUCH; configuration is below
    
    // Credits:
    //  - Ciebron for the inspiration
    //  - -JonNny for reporting some bugs
    //  - Rising_Dusk for his GroupUtils library
    //  - Anitarf for his IsTerrainWalkable library
    //  - Vexorian for JassHelper and xe
    //  - PipeDream for Grimoire
    //  - PitzerMike for JassNewGenPack and DestructableLib
    //  - MindWorX for JassNewGenPack
    //  - SFilip for TESH
    
    globals
        private constant    real                    TICK                    = 1./32 // granulation of movement
        private constant    integer                 AID                     = 'A000' // the ability triggering this spell
        private             real            array   DAMAGE                  // damage dealt by the boomerang to units it hits
        private             real            array   DAMAGE_ABSORPTION       // the damage dealt is reduced by this much everytime the boomerang hits a unit or a tree
        private constant    boolean                 DAMAGE_ABSORPTION_RELATIVE = true // is DAMAGE_ABSORPTION to be treated as an absolute value or a value relative to the current damage
        private constant    real                    DAMAGE_BOUNDARY         = 10. // once the damage is lower or equal to this, the boomerang stops flying
        private constant    string                  BOOMERANG_MODEL         = "Abilities\\Weapons\\SentinelMissile\\SentinelMissile.mdl" // this is the model representing the boomerang
        private constant    real                    BOOMERANG_COLLSIZE      = 96. // the AoE in which units are damaged by the boomerang
        private constant    real                    BOOMERANG_SIZE          = 1.25 // the scaling of the boomerang
        private constant    real                    BOOMERANG_HEIGHT        = 64. // the Z height of the boomerang
        private constant    real                    BOOMERANG_SPEED         = 600. // the speed at which the boomerang moves // due to limitations this is only an approximation
        private constant    boolean                 ALLOW_MULTIPLE_HITS     = true // if this is true, the boomerang can hit units more than once on his path
        private constant    boolean                 USE_RIGHT_BOOMERANG     = true // just avoid setting both to false, okay?
        private constant    boolean                 USE_LEFT_BOOMERANG      = true
        private constant    boolean                 COLLIDE_WITH_GROUND     = true // do boomerangs collide with unwalkable terrain?
        private             real            array   MIN_RANGE               // minimum throwing distance for the boomerang
        private constant    boolean                 KILL_TREES              = false // if true, trees are killed once the boomerang hits one, if this is false, the boomerang stops flying
        private constant    string                  HIT_FX                  = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl" // when the boomerang hits a unit, this effect is spawned on the unit hit
        private constant    string                  HIT_FX_ATTPT            = "chest" // the beforementioned effect will be attached to this point
        private constant    attacktype              ATTACK_TYPE             = ATTACK_TYPE_MAGIC // the attack type of the damage the boomerang deals
        private constant    damagetype              DAMAGE_TYPE             = DAMAGE_TYPE_MAGIC // the damage type of the damage the boomerang deals
        private constant    weapontype              WEAPON_TYPE             = WEAPON_TYPE_METAL_MEDIUM_SLICE // sound when boomerang hits a unit
    endglobals
    
    private function Damage takes integer level, unit u returns real // PROXY
        return I2R(GetHeroStr(u, true))
    endfunction
    
    private function SetUpDAMAGE_ABSORPTION takes nothing returns nothing
        set DAMAGE_ABSORPTION[1]=0.16 // lowers damage dealt by 16% of current damage.
        set DAMAGE_ABSORPTION[2]=0.12
        set DAMAGE_ABSORPTION[3]=0.08
    endfunction
    
    private function Damage_Absorption takes integer level returns real // PROXY
        return DAMAGE_ABSORPTION[level]
    endfunction
    
    private function SetUpMIN_RANGE takes nothing returns nothing
        set MIN_RANGE[1]=200.
        set MIN_RANGE[2]=200.
        set MIN_RANGE[3]=200.
    endfunction
    
    private function Min_Range takes integer level returns real // PROXY
        return MIN_RANGE[level]
    endfunction
    
    private function ValidTarget takes unit u, Data s returns boolean
        return IsUnitType(u, UNIT_TYPE_DEAD)==false /*         Delimited Comments FTW
        */ and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false /*
        */ and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false /*
        */ and (not IsUnitInGroup(u, s.g)) /*
        */ and IsUnitEnemy(u, GetOwningPlayer(s.c))
    endfunction
    
    // This is shit. Don't touch shit.
    
    globals
        private location l
        private rect R=Rect(0,0,1,1)
        private Data tmps
        private integer tmpd
    endglobals

    private struct Data
        unit c // caster
        xefx dum1 // boomerang dummy 1
        xefx dum2 // boomerang dummy 2
        boolean d1a // is dummy 1 active
        boolean d2a // is dummy 2 active
        integer level
        real d // planned distance
        real a // current angle
        real x // x-coord of launch point
        real y // y-coord
        real tx // targeted x-coord
        real ty // targeted y-coord
        real f // base-angle
        real dam1 // damage dealt to the next unit the boomerang hits
        real dam2 // damage dealt to the next unit the boomerang hits
        group g // group holding already damaged enemies
        
        static boolexpr DamageFilter
        static boolexpr TreeFilter
        
        private integer i
        
        private static thistype array Structs
        private static timer T=CreateTimer()
        private static integer Count=0
        
        method onDestroy takes nothing returns nothing
            set .c=null
            if .d1a then
                call .dum1.destroy()
            endif
            if .d2a then
                call .dum2.destroy()
            endif
            call ReleaseGroup(.g)
            // clean your struct here
            set thistype.Count=thistype.Count-1
            set thistype.Structs[.i]=thistype.Structs[thistype.Count]
            set thistype.Structs[.i].i=.i
            if thistype.Count==0 then
                call PauseTimer(thistype.T)
            endif
        endmethod
        
        private static method UnitDistCheck takes nothing returns nothing
        local unit u=GetEnumUnit()
        local real x=GetUnitX(u)
        local real y=GetUnitY(u)
        local real d1x=tmps.dum1.x
        local real d1y=tmps.dum1.y
        local real d2x=tmps.dum2.x
        local real d2y=tmps.dum2.y
            if ((not tmps.d1a) or (((x-d1x)*(x-d1x))+((y-d1y)*(y-d1y)))>BOOMERANG_COLLSIZE*BOOMERANG_COLLSIZE) and ((not tmps.d2a) or (((x-d2x)*(x-d2x))+((y-d2y)*(y-d2y)))>BOOMERANG_COLLSIZE*BOOMERANG_COLLSIZE) then // if the unit is not inside any boomerang anymore
                // unit is not near any of the active boomerangs
                call GroupRemoveUnit(tmps.g, u)
            endif
            set u=null
        endmethod
        
        private static method DamageFilterFunc takes nothing returns boolean
        local unit u=GetFilterUnit()
            // check if unit is a valid target for damage
            if ValidTarget(u, tmps) then
                if tmpd==1 then // tmpd hold the current boomerang; 1 for left-wing, 2 for right-wing
                    // damage the unit; if the unit for some reason cant be damaged, dont continue
                    if UnitDamageTarget(tmps.c, u, tmps.dam1, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE) then
                        call DestroyEffect(AddSpecialEffectTarget(HIT_FX, u, HIT_FX_ATTPT))
                        call GroupAddUnit(tmps.g, u)
                        if DAMAGE_ABSORPTION_RELATIVE then
                            set tmps.dam1=tmps.dam1*(1-Damage_Absorption(tmps.level))
                        else
                            set tmps.dam1=tmps.dam1-Damage_Absorption(tmps.level)
                        endif
                        if tmps.dam1<=DAMAGE_BOUNDARY then // damage has become too low
                            call tmps.dum1.destroy() // destroy the boomerang dummy
                            set tmps.d1a=false // mark that boomerang as destroyed
                            if not tmps.d2a then // if the other boomerang is dead as well, destroy the spells instance
                                call tmps.destroy()
                            endif
                        endif
                    endif
                elseif tmpd==2 then // pretty much the same here
                    if UnitDamageTarget(tmps.c, u, tmps.dam2, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE) then
                        call DestroyEffect(AddSpecialEffectTarget(HIT_FX, u, HIT_FX_ATTPT))
                        call GroupAddUnit(tmps.g, u)
                        if DAMAGE_ABSORPTION_RELATIVE then
                            set tmps.dam2=tmps.dam2*(1-Damage_Absorption(tmps.level))
                        else
                            set tmps.dam2=tmps.dam2-Damage_Absorption(tmps.level)
                        endif
                        if tmps.dam2<=DAMAGE_BOUNDARY then
                            call tmps.dum2.destroy()
                            set tmps.d2a=false
                            if not tmps.d1a then
                                call tmps.destroy()
                            endif
                        endif
                    endif
                endif
            endif
            set u=null
            return false
        endmethod
        
        private static method TreeFilterFunc takes nothing returns boolean
        local destructable d=GetFilterDestructable()
        local real x
        local real y
        local real bx
        local real by
            if (not IsDestructableDead(d)) and IsDestructableTree(d) then // filter out dead and non-tree destructables
                set x=GetWidgetX(d)
                set y=GetWidgetY(d)
                if tmpd==1 then // same as above
                    set bx=tmps.dum1.x
                    set by=tmps.dum1.y
                    if (((x-bx)*(x-bx))+((y-by)*(y-by)))<=BOOMERANG_COLLSIZE*BOOMERANG_COLLSIZE then // tree must be inside the collision radius
                        if KILL_TREES then // if the boomerang is allowed to kill trees, do so
                            call KillDestructable(d)
                            // but adjust the damage as if a unit had been hit
                            if DAMAGE_ABSORPTION_RELATIVE then
                                set tmps.dam1=tmps.dam1*(1-Damage_Absorption(tmps.level))
                            else
                                set tmps.dam1=tmps.dam1-Damage_Absorption(tmps.level)
                            endif
                            if tmps.dam1<=DAMAGE_BOUNDARY then // same as above
                                call tmps.dum1.destroy()
                                set tmps.d1a=false
                                if not tmps.d2a then
                                    call tmps.destroy()
                                endif
                            endif
                        else // if Trees may not be destroyed, destroy the boomerang instantly
                            call tmps.dum1.destroy()
                            set tmps.d1a=false
                            if not tmps.d2a then // and end the spell instance if appropriate
                                call tmps.destroy()
                            endif
                        endif
                    endif
                elseif tmpd==2 then // next section is the same as above
                    set bx=tmps.dum2.x
                    set by=tmps.dum2.y
                    if (((x-bx)*(x-bx))+((y-by)*(y-by)))<=BOOMERANG_COLLSIZE*BOOMERANG_COLLSIZE then
                        if KILL_TREES then
                            call KillDestructable(d)
                            if DAMAGE_ABSORPTION_RELATIVE then
                                set tmps.dam2=tmps.dam2*(1-Damage_Absorption(tmps.level))
                            else
                                set tmps.dam2=tmps.dam2-Damage_Absorption(tmps.level)
                            endif
                            if tmps.dam2<=DAMAGE_BOUNDARY then
                                call tmps.dum2.destroy()
                                set tmps.d2a=false
                                if not tmps.d1a then
                                    call tmps.destroy()
                                endif
                            endif
                        else
                            call tmps.dum2.destroy()
                            set tmps.d2a=false
                            if not tmps.d1a then
                                call tmps.destroy()
                            endif
                        endif
                    endif
                endif
            endif
            set d=null
            return false
        endmethod
        
        private static method Callback takes nothing returns nothing
        local integer i=thistype.Count-1
        local thistype s
        local real r
        local real x
        local real y
            loop
                exitwhen i<0
                set s=thistype.Structs[i]
                //
                // make the boomerang home, even if the caster moves
                set s.x=GetUnitX(s.c)
                set s.y=GetUnitY(s.c)
                set s.d=SquareRoot( ((s.tx-s.x)*(s.tx-s.x))+((s.ty-s.y)*(s.ty-s.y)) )
                set s.f=Atan2(s.ty-s.y, s.tx-s.x)-(bj_PI/4)
                // functions for moving the boomerang:
                // r(a)=distance*Sin(2*a) // a is the angle and goes from 90 to 0 // distance from center point
                // x(a)=Cos(a)*r(a) // x and y coordinates in relation to the location it was cast.
                // y(a)=Sin(a)*r(a) // note that i inlined some things to allow casting the boomerang in all directions from any point on the map
                set r=(s.d*Sin(2*s.a))
                set tmps=s
                if ALLOW_MULTIPLE_HITS then
                    call ForGroup(s.g, function Data.UnitDistCheck)
                endif
                if s.d1a then // is dummy 1 active
                    set tmpd=1 // indicate were working with dummy 1
                    set x=s.x+(Cos(s.a+s.f)*r)
                    set y=s.y+(Sin(s.a+s.f)*r)
                    
                    set s.dum1.x=x
                    set s.dum1.y=y
                    
                    call GroupEnumUnitsInRange(ENUM_GROUP, x, y, BOOMERANG_COLLSIZE, Data.DamageFilter)
                    call SetRect(R, x-BOOMERANG_COLLSIZE, y-BOOMERANG_COLLSIZE, x+BOOMERANG_COLLSIZE, y+BOOMERANG_COLLSIZE)
                    call EnumDestructablesInRect(R, Data.TreeFilter, null)
                    if COLLIDE_WITH_GROUND and (not IsTerrainWalkable(x,y)) then // if boomerangs collide with unwalkable terrain and the terrain is unwalkable
                        call s.dum1.destroy() // destroy the dummy
                        set s.d1a=false
                        if not s.d2a then // if the other dummy is inactive
                            call s.destroy() // destroy this spell instance
                        endif
                    endif
                endif
                if s.d2a then
                    set tmpd=2
                    set x=s.x+(Cos((bj_PI/2-s.a)+s.f)*r)
                    set y=s.y+(Sin((bj_PI/2-s.a)+s.f)*r)
                    
                    set s.dum2.x=x
                    set s.dum2.y=y
                    
                    call GroupEnumUnitsInRange(ENUM_GROUP, x, y, BOOMERANG_COLLSIZE, Data.DamageFilter)
                    call SetRect(R, x-BOOMERANG_COLLSIZE, y-BOOMERANG_COLLSIZE, x+BOOMERANG_COLLSIZE, y+BOOMERANG_COLLSIZE)
                    call EnumDestructablesInRect(R, Data.TreeFilter, null)
                    if COLLIDE_WITH_GROUND and not IsTerrainWalkable(x,y) then
                        call s.dum2.destroy()
                        set s.d2a=false
                        if not s.d1a then
                            call s.destroy()
                        endif
                    endif
                endif
                set s.a=s.a-(TICK*((bj_PI*BOOMERANG_SPEED)/(4*s.d)))
                if s.a<=0 or IsUnitType(s.c, UNIT_TYPE_DEAD)==true then // stop this spell when caster is dead or the boomerang is at the casters position again.
                    call s.destroy()
                endif
                // do your things here, dont forget to call s.destroy() somewhen
                //
                set i=i-1
            endloop
        endmethod
        
        static method SpellCond takes nothing returns boolean
            return GetSpellAbilityId()==AID
        endmethod
        
        static method create takes nothing returns thistype
        local thistype s=thistype.allocate()
            set l=GetSpellTargetLoc()
            set s.tx=GetLocationX(l)
            set s.ty=GetLocationY(l)
            call RemoveLocation(l)
            set l=null
            set s.c=GetTriggerUnit()
            set s.x=GetUnitX(s.c)
            set s.y=GetUnitY(s.c)
            set s.level=GetUnitAbilityLevel(s.c, AID)
            set s.d=SquareRoot( ((s.tx-s.x)*(s.tx-s.x))+((s.ty-s.y)*(s.ty-s.y)) )
            if s.d==0 then
                set s.f=(GetUnitFacing(s.c)*bj_DEGTORAD)
            else
                set s.f=Atan2(s.ty-s.y, s.tx-s.x)
            endif
            if s.d<Min_Range(s.level) then // enforce the minimum distance
                set s.d=Min_Range(s.level)
                set s.tx=s.x+s.d*Cos(s.f)
                set s.ty=s.y+s.d*Sin(s.f)
            endif
            set s.f=s.f-(bj_PI/4)
            set s.a=(bj_PI/2)
            set s.g=NewGroup()
            set s.d1a=false
            set s.d2a=false
            if USE_RIGHT_BOOMERANG then
                set s.d1a=true
                set s.dam1=Damage(s.level,s.c)
                
                set s.dum1=xefx.create(s.x, s.y, 0)
                set s.dum1.fxpath=BOOMERANG_MODEL
                set s.dum1.scale=BOOMERANG_SIZE
                set s.dum1.z=BOOMERANG_HEIGHT
            endif
            if USE_LEFT_BOOMERANG then
                set s.d2a=true
                set s.dam2=Damage(s.level,s.c)
                
                set s.dum2=xefx.create(s.x, s.y, 0)
                set s.dum2.fxpath=BOOMERANG_MODEL
                set s.dum2.scale=BOOMERANG_SIZE
                set s.dum2.z=BOOMERANG_HEIGHT
            endif
            
            // initialize the struct here
            set thistype.Structs[thistype.Count]=s
            set s.i=thistype.Count
            if thistype.Count==0 then
                call TimerStart(thistype.T, TICK, true, function thistype.Callback)
            endif
            set thistype.Count=thistype.Count+1
            
            if (not s.d1a) and (not s.d2a) then
                call s.destroy()
                return 0
            endif
            return s
        endmethod
        
        private static method onInit takes nothing returns nothing
        local trigger t=CreateTrigger()
            call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
            call TriggerAddCondition(t, Condition(function Data.SpellCond))
            call TriggerAddAction(t, function Data.create)
            
            set Data.DamageFilter=Condition(function Data.DamageFilterFunc)
            set Data.TreeFilter=Condition(function Data.TreeFilterFunc)
            
            call SetUpDAMAGE_ABSORPTION()
            call SetUpMIN_RANGE()
        endmethod
    endstruct

endlibrary

I hope it works :/
 
Status
Not open for further replies.
Top