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

[vJASS] GetUnitZ instead of GetUnitFlyingHeight

Status
Not open for further replies.
Level 19
Joined
Oct 12, 2007
Messages
1,821
Is there a way to see the Z value the unit is on instead of its flying height?
With GetUnitFlyingHeight I get a clean value, but not if my unit is standing on a hill. Would be great if there excisted a GetUnitZ command, but does anyone have a trick for this?
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
Ah thanks alot!
Gonna try it out!

EDIT: Still doesn't work, however I believe it must be something else in the spell's code that's fcking up the Z values then. I'm gonna look for it one more time before I go zerk on this code.
 
Level 5
Joined
Jun 16, 2004
Messages
108
If you explained more precisely what exactly is happening and how the Z value is different from what you expect I might be able to pin point a possible problem, but here is a wide attempt.

One thing to note with flying units is that they typically have their Z set to flying height + terrain height. There might be a unit movement type that bypasses this behavior, but I am not sure. A potential side effect of this is that when you have a flying projectile or some such, it will appear to rise and fall when going over inclines or declines. If you do not want a change in Z while passing over hills and such, you will want to do a GetUnitFlyHeight - GetLocationZ solution periodically.

I believe one user tried using SetUnitFlyHeight with a slow increment value. Apparently the flying height of a unit is set automatically to the value you specify, whether you specify a slow or immediate interpolation between the flying heights. As an example, SetUnitFlyHeight(600., 100.) would take about 6 seconds to reach 600. height I believe, but GetUnitFlyHeight would report 600. at all times after calling the set.

Well, good luck to you.
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
I found out that it works, but there's still something in this code that fails from working.

Someone made this spell for me, but the only problem is the height issue on hills. Targets of the spell now correctly get the lightning attached to them because of GetUnitZ. However the dummy unit that gets summoned in the center of the area doesn't get the source of the lightning attached to it.

But yeah.. This code is very long. No problem if it's too long to go through.
There might even be some commands you won't recognize because of systems.

JASS:
scope FlameShackles initializer Init_FlameShackles

    globals
        private constant integer ABILITY_ID  = 'A0KO'
        private constant integer   DUMMY_ID  = 'u00Q'
        private constant string   LIGHTNING  = "LEAS"

        private constant real RADIUS         = 360.00000
        private constant real GRAB_MAX_STEP  = 009.00000
        private constant real DURATION       = 005.50000

        private constant real MAX_HEIGHT     = 200.00000
        private constant real RISE_TIME      = 001.50000
        private constant real GRAB_INTERVAL  = 000.03125//000.15000
        private constant real ORIGIN_OFFSET  = 032.00000
        private constant real TIMER_INTERVAL = 000.03125

        private integer index = 0
        private integer array swap

        private constant hashtable hash = InitHashtable()
        private constant timer tim = CreateTimer()
    endglobals

    private struct flame extends array
        player owner
        unit dummy
        unit caster
        real cast_x
        real cast_y
        real dummy_z
        real duration
        real grab_counter
        real a
        integer count

        implement Alloc

        static method filter takes player owner, unit u returns boolean
            return IsUnitEnemy(u,owner) and IsUnitType(u,UNIT_TYPE_GROUND) and GetWidgetLife(u) > .305
        endmethod

        static method rise takes nothing returns nothing
            local thistype this
            local integer i = 0
            local integer j
            local integer k
            local lightning l
            local unit u
            local real x1
            local real y1
            local real z1
            local real x2
            local real y2
            local real z2
            local real dx
            local real dy
            local real dist
            local real face
            local real step

            loop
                exitwhen i >= index
                set this = swap[i]
                set this.grab_counter = this.grab_counter - TIMER_INTERVAL
                set this.duration = this.duration - TIMER_INTERVAL
                if this.duration > 0.0 then
                    set x1 = this.cast_x
                    set y1 = this.cast_y
                    set z1 = this.dummy_z
                    if z1 < MAX_HEIGHT then
                        set z1 = z1 + MAX_HEIGHT * TIMER_INTERVAL/RISE_TIME
                        call SetUnitFlyHeight(this.dummy,z1,0.0)
                        set this.dummy_z = z1
                    endif
                    call GroupEnumUnitsInRange(bj_lastCreatedGroup,x1,y1,RADIUS,null)
                    set j = 1
                    loop // Remove Old Units from the newely picked group
                        exitwhen j >= this.count
                        set u = LoadUnitHandle(hash,this,j)
                        call GroupRemoveUnit(bj_lastCreatedGroup,u)
                        set j = j + 1
                    endloop

                    set j = this.count
                    loop // Add Lightning to the new units and add them to the counter
                        set u = FirstOfGroup(bj_lastCreatedGroup)
                        exitwhen u == null
                        if filter(this.owner,u) then
                            set j = j + 1
                            set x2 = GetUnitX(u)
                            set y2 = GetUnitY(u)
                            set z2 = GetUnitZ(u) + ORIGIN_OFFSET
                            set l = AddLightningEx(LIGHTNING,false,x1,y1,z1,x2,y2,z2)
                            call SaveUnitHandle     ( hash , this ,  j , u )
                            call SaveLightningHandle( hash , this , -j , l )
                        endif
                        call GroupRemoveUnit(bj_lastCreatedGroup,u)
                    endloop
                    set this.count = j
                    set j = 1
                    loop // Check all the units we picked either in range or outside
                        set u = LoadUnitHandle(hash,this,j)
                        exitwhen u == null
                        set x2 = GetUnitX(u)
                        set y2 = GetUnitY(u)
                        set dx = x2 - x1
                        set dy = y2 - y1
                        set dist = SquareRoot(dx*dx + dy*dy)
                        set face = Atan2(dy,dx)
                        set l = LoadLightningHandle(hash,this,-j)
                        if dist <= RADIUS then // the unit is still in the range of the orb
                            if not LoadBoolean(hash,this,j) then // Just in case the exiting unit re-entered
                                call SetLightningColor(l,1,1,1,1)
                                call SaveBoolean(hash,this,j,true)
                            endif
                            // grab the units
                            if this.grab_counter <= 0.0 then // if the grab interval has ticked then we pull them back
                                set step = this.a * dist // this equation calculates the strength of the drag
                                call SetUnitX(u,x1 + (dist - step) * Cos(face))
                                call SetUnitY(u,y1 + (dist - step) * Sin(face))
                            endif
                            set z2 = GetUnitZ(u) + ORIGIN_OFFSET
                            call MoveLightningEx(l,false,x1,y1,z1,x2,y2,z2)
                        else // the unit has moved out of the orb range
                            call SaveBoolean(hash,this,j,false) // Flag the unit as out-of-Range
                            call SetLightningColor(l,1,1,1,0)
                        endif
                        set j = j + 1
                    endloop

                    if this.grab_counter <= 0.0 then // Reset the grab counter only when all units are checked and the counter has ticked
                        set this.grab_counter = GRAB_INTERVAL
                    endif

                else
                    set index = index - 1
                    set swap[i] = swap[index]
                    set i = i - 1
                    call KillUnit(this.dummy)
                    set this.dummy = null
                    set j = 1
                    loop
                        set l = LoadLightningHandle(hash,this,-j)
                        exitwhen l == null
                        call DestroyLightning(l)
                        set j = j + 1
                    endloop
                    call FlushChildHashtable(hash,this)
                    call .deallocate()
                    if index == 0 then
                        call PauseTimer(tim)
                    endif
                    
                endif

                set u = null
                //set l = null
                set i = i + 1
            endloop
        endmethod

        static method start takes unit caster, real x1, real y1 returns nothing
            local thistype this = thistype.allocate()
            local unit u
            local lightning l
            local integer i = 0
            local real x2
            local real y2
            local real z2

            set swap[index] = this
            set this.owner  = GetOwningPlayer(caster)
            set this.duration = DURATION
            set this.grab_counter = GRAB_INTERVAL
            set this.a = GRAB_MAX_STEP/RADIUS
            set this.count = 0
            set this.caster = caster
            set this.cast_x = x1
            set this.cast_y = y1
            set this.dummy_z = 0.0
            set this.dummy = CreateUnit(this.owner,DUMMY_ID,x1,y1,0)
            call ShakeCamera(GetOwningPlayer(caster), 3.00)
            call GroupEnumUnitsInRange(bj_lastCreatedGroup,x1,y1,RADIUS,null)
            loop
                set u = FirstOfGroup(bj_lastCreatedGroup)
                exitwhen u == null
                if filter(this.owner,u) then
                    set i = i + 1
                    set x2 = GetUnitX(u)
                    set y2 = GetUnitY(u)
                    set z2 = GetUnitZ(u) + ORIGIN_OFFSET
                    set l = AddLightningEx(LIGHTNING,false,x1,y1,0,x2,y2,z2)
                    call SaveUnitHandle     ( hash , this ,  i , u )
                    call SaveLightningHandle( hash , this , -i , l )
                    call SaveBoolean        ( hash , this ,  i , true)
                endif
                call GroupRemoveUnit(bj_lastCreatedGroup,u)
            endloop
            set this.count = i
            //call BJDebugMsg(I2S(this.count))
            if index == 0 then
                call TimerStart(tim,TIMER_INTERVAL,true,function flame.rise)
            endif
            set index = index + 1
        endmethod
    endstruct

    private function FlameShackles_Conditions takes nothing returns boolean
        if GetSpellAbilityId() == ABILITY_ID then
            call flame.start(GetTriggerUnit(),GetSpellTargetX(),GetSpellTargetY())
        endif
        return false
    endfunction

    private function Init_FlameShackles takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t,function FlameShackles_Conditions)
        set t = null
    endfunction

endscope
 
Level 5
Joined
Jun 16, 2004
Messages
108
From the looks of it you want to use GetLocationZ for your dummy unit too.

Maybe something like this:
JASS:
if z1 < MAX_HEIGHT then
 set z1 = z1 + MAX_HEIGHT * TIMER_INTERVAL/RISE_TIME
 call SetUnitFlyHeight(this.dummy,z1,0.0)
 set this.dummy_z = z1
 call MoveLocation(Loc, this.cast_x, this.cast_y)
 set z1 = z1 + GetLocationZ(Loc)
endif

(I purposely put the location Z modification after you set dummy_z in the periodic just in case you want to be able to move the dummy unit around or some such; if you know that the dummy unit's x/y will never change you can just initially set the location Z value in the dummy unit's creation)
 
Two useful hints when working with flying heights:
A) Make sure that the units pitch and roll values in the object editor are set to 0.
B) Set the untis movement type to "foot", and then instead add and remove 'Amrf' (raven form) to the unit as you create it. This will enable you to set the fly height of ground units, and this usually produces better results than doing so on a unit with "fly" movement type. I am not sure exactly why but i believe that units with "fly" movement type often lean to the sides as they turn, even when moved with triggers, and this might not always be what you want.
 
Status
Not open for further replies.
Top