HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Beautiful floating text question

11-14-2008, 12:06 PM#1
dfgiop
Just wondering if anyone got the script or have seen the tutorial to do this particular floating text. It's part of a damage system I believe, damage numbers popping up over your hero's head. I know there are a lot of them around. But I really like this particular one.
It very much resembles the the World of Warcraft's floating text style. With the text popping up then shrink down, then go up and faded out. And with a critical strike damage being dealt, the floating text just jumps out, gives you that "boom" feeling.

I've seen in those places:
YouTube - [War3]Tales Cronicles RPG Trailor(probably an old discontinued project)

Dark Invasion II

Hopefully I have made my self clear of what I'm trying to say. Any help would be appreciated.
11-14-2008, 12:38 PM#2
DioD
check resource section may be?
11-14-2008, 12:43 PM#3
dfgiop
I have checked all of them, while there are a lot of them around, but all of them are very basic and standard.
11-14-2008, 06:52 PM#4
Zandose
http://www.wc3campaigns.net/showthread.php?t=101865

Damage detection engine:
Collapse JASS:
library LightLeaklessDamageDetect initializer Init
    
    // Creating threads off of this that last longer than the timeout below will likely cause issues, like everything blowing up (handle stack corruption)
    // It seems that threads created by timers, rather than executefunc / .evaluate / .execute are not affected. Any threads created from the timer thread are fine.
    // This being safe with even the usage laid out above isn't guarenteed. Use at own risk.
    // If you start getting random bugs, see if commenting out the timer line below (see comments) helps
    // If it does, report it in the thread for this script at [url]www.wc3campaigns.net[/url]
    
    globals
        private constant real SWAP_TIMEOUT = 600. // keep high; 600 should be about the right balance.
    endglobals
    
    globals
        private conditionfunc array func
        private integer funcNext = 0
        private trigger current = null
        private trigger toDestroy = null
        private group swapGroup
        private rect mapRect
    endglobals
    
    // One of the only accessible functions. Use it to add a condition. Must return boolean type, and then have return false at the end.
    // Note that it's technically a condition, so if you put a wait in there, it'll die. But waits are lame anyway.
    function AddOnDamageFunc takes conditionfunc cf returns nothing
        call TriggerAddCondition(current, cf)
        set func[funcNext] = cf
        set funcNext = funcNext + 1
    endfunction
    
    // These inline. For avoiding feedback loops. Feel free to make your own wrapper function for damage functions using this.
    function DisableDamageDetect takes nothing returns nothing
        call DisableTrigger(current)
    endfunction
    function EnableDamageDetect takes nothing returns nothing
        call EnableTrigger(current)
    endfunction
    
    // no more accessible functions, folks.
    
    //! textmacro CGLeaklessDamageDetectAddFilter takes UNIT
        
        // add here any conditions to add the unit to the trigger, example below, commented out:
        // if GetUnitTypeId($UNIT$) != 'h000' then // where 'h000' is a dummy unit
        call TriggerRegisterUnitEvent(current, $UNIT$, EVENT_UNIT_DAMAGED)
        // endif
        
    //! endtextmacro
    
    private function AddEx takes nothing returns boolean
        //! runtextmacro CGLeaklessDamageDetectAddFilter("GetFilterUnit()")
        return false
    endfunction

    private function Enters takes nothing returns boolean
        //! runtextmacro CGLeaklessDamageDetectAddFilter("GetTriggerUnit()")
        return false
    endfunction
    
    private function Swap takes nothing returns nothing
        local integer i = 0
        local boolean b = IsTriggerEnabled(current)
        
        call DisableTrigger(current)
        if toDestroy != null then
            call DestroyTrigger(toDestroy)
        endif
        set toDestroy = current
        set current = CreateTrigger()
        
        if not(b) then
            call DisableTrigger(current)
        endif
        
        call GroupEnumUnitsInRect(swapGroup, mapRect, Filter(function AddEx))
        
        loop
            exitwhen i >= funcNext
            call TriggerAddCondition(current, func[i])
            set i = i + 1
        endloop
    endfunction
    
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local region r = CreateRegion()
        local integer i = 0
        set mapRect = GetWorldBounds()
        call RegionAddRect(r, mapRect)
        call TriggerRegisterEnterRegion(t, r, null)
        call TriggerAddCondition(t, Condition(function Enters))
        
        set swapGroup = CreateGroup()
        
        set current = CreateTrigger()
        loop
            exitwhen i >= funcNext
            call TriggerAddCondition(current, func[i])
            set i = i + 1
        endloop
        
        call GroupEnumUnitsInRect(swapGroup, GetWorldBounds(), Filter(function AddEx))
        
        // Commenting out the next line will make the system leak indexes and events, but should make it safer.
        call TimerStart(CreateTimer(), SWAP_TIMEOUT, true, function Swap)
    endfunction
    
endlibrary

Floating text:
Collapse JASS:
scope Example initializer Init

    private function Text takes nothing returns boolean
        local texttag t = CreateTextTag()
        
        call SetTextTagColor(t, 255, 150, 150, 175)
        
        call SetTextTagText(t, R2S(GetEventDamage()), 0.025)
        call SetTextTagPos(t, GetUnitX(GetTriggerUnit()), GetUnitY(GetTriggerUnit()), 0.00)
        call SetTextTagVelocity(t, 0, 0.03)
        call SetTextTagVisibility(t, true)
        call SetTextTagFadepoint(t, 2)
        call SetTextTagLifespan(t, 3)
        call SetTextTagPermanent(t, false)
        
        return false
    endfunction

    private function Init takes nothing returns nothing
        call AddOnDamageFunc(Condition(function Text))
    endfunction

endscope

Edit: Just noticed, but that floating text probably leaks and you'll hit the ?99? floating text limit.
11-14-2008, 11:05 PM#5
dfgiop
I appreciate the help, Zandose. Unfortunately, that floating text does not have the style and look that I'm after.
11-15-2008, 06:25 AM#6
Pyrogasm
I can imagine you needing to do that yourself. If you want to give me a bit, I could probably write a library for you.
11-15-2008, 06:44 AM#7
dfgiop
Thank you Pyrogasm. You are right, and I've been trying to write my own and also looking for ideas all over the place, but it's not going anywhere... but if you know how to do it, you will officially be my idol.
11-15-2008, 06:49 AM#8
DioD
There is no "Beautiful" FT in second video, first video not available.
11-15-2008, 08:27 AM#9
dfgiop
Sorry DioD, Unfortunately, the first video is not available anymore, but if you pay close attention to the second video which is Dark Invasion II's promo. When he's showing it's combat system, the floating text jumped out, then shrank down, then faded out, of course I think you can increase the initial size of the text or tweak it a little bit to get greater effect. But I've been trying to code it myself with not much of success.
11-15-2008, 08:59 AM#10
Chocobo
just change velocity speed/angle periodicly...
11-15-2008, 10:14 AM#11
Pyrogasm
Okay, I've got to go to bed now... but I came up with this so far:
Collapse JASS:
library TextZoom requires TimerUtils initializer Init
    globals
        private constant real TIMER_INTERVAL = 0.04
        private constant real LAST_INITIALIZED_ARRAY_INDEX = 255

        private timer T = null
        private integer N = 0
        public ZoomData array ZoomDatas
    endglobals

    function interface ZoomCallbackFunction takes ZoomData ZoomedTextData returns nothing

    private struct ZoomData
        texttag Text = null
        string S = ""
        real SizeMod = 0.00
        real Size = 0.00
        ZoomCallbackFunction ZCF = null
        integer N = 0
    endstruct

    private function ZoomCallback takes nothing returns nothing
        local integer J = -1
        local ZoomData ZD

        loop
            set J = J+1
            exitwhen J >= N

            set ZD = ZoomDatas[J]

            set ZD.size = ZD.size + ZD.SizeMod
            call SetTextTagText(ZD.Text, ZD.S, ZD.size)
            set ZD.N = ZD.N - 1

            if ZD.N <= 0 then
                call ZD.ZCF.execute(ZD)

                set N = N-1
                if N > 0 then
                    set ZoomDatas[J] = ZoomDatas[N]
                    set ZoomDatas[N] = ZoomDatas[J]
                    set J = J-1
                else
                    call PauseTimer(T)
                endif
            endif
        endloop
    endfunction

    function FlushZoomData takes ZoomData ZD returns nothing
        call DestroyTextTag(ZD.Text)
        set ZD.Text = null
        set ZD.ZCF = null
    endfunction

    function ZoomText takes texttag whichText, string s, real startSize, real endSize, real duration, ZoomCallbackFunction CallbackCode returns nothing
        local ZoomData ZD = ZoomData[N]

        if ZD == 0 then
            set ZD = ZoomData.create()
            set ZoomDatas[N] = ZD
        endif

        call SetTextTagText(whichText, s, startSize)

        set ZD.Text = whichText
        set ZD.S = s
        set ZD.N = R2I(duration/TIMER_INTERVAL)
        set ZD.Size = startSize
        set ZD.SizeMod = (endSize-startSize)/ZD.N

        set N = N+1
        if N == 1 then
            call TimerStart(T, TIMER_INTERVAL, true, function ZoomCallback)
        endif
    endif

    private function Init takes nothing returns nothing
        local integer J = -1

        set T = NewTimer()

        loop
            set J = J+1
            exitwhen J > LAST_INITIALIZED_ARRAY_INDEX
            set ZoomDatas[J] = 0
        endloop
    endfunction
endlibrary
I haven't syntax checked it or tested it at all, but I can't how it might end up not working. If you feel confident figuring out the errors in the code, I'd suggest that you fix it up for yourself if you need it right now. Else, wait for me to finish it tomorrow. (I'm GMT -8.)
11-15-2008, 11:50 AM#12
dfgiop
Thank you so much Pyrogasm. I'll wait for you to finish . I've been checking the code myself, and it's very advanced for my level I must say. I realized I need to import TimerUtils library to use this. Just wondering did you use the blue TimerUtils or the red TimerUtils?
11-15-2008, 09:05 PM#13
Pyrogasm
It doesn't matter. I personally prefer red.
11-15-2008, 11:12 PM#14
Pyrogasm
Finished up, but I still haven't tested it yet.
Collapse JASS:
library ZoomTextLibrary requires TimerUtils, Table initializer Init
//********************************************************************************
//* ZoomTextLibrary
//* ------------
//*
//* The purpose of this library is to provide an easy way to make zooming TextTags
//* Example: local texttag TT = CreateTextTag()
//*          call SetTextTagPosUnit(TT, GetTriggerUnit(), 50.00)
//*          call ZoomTextInOut(TT, R2S(GetEventDamage()), 0.25, 3.00, 0.00, 0.50, 1.50, 0.30, null)
//*
//* Function Explanation:
//*   ZoomText
//*      This function zooms a texttag from size X to size Y over Z seconds; it does not zoom in and out,
//*      but rather only one of the two
//*      However, it can perform both: endsize > startsize = in, endsize < startsize = out
//*
//*      whichText: the texttag you want to zoom (created by the user, not this library) 
//*      s: the string you want the texttag to display (because to set the height you must also set its text)
//*      startSize: the starting size of the text (NOT a font size, see TextTagSize2Height in Blizzard.j)
//*      endSize: the ending size of the zoom
//*      callbackCode: this is the function that is evalutated upon the zoom being completed; it must conform to this:
//*
//*                    function interface ZoomCallbackFunction takes ZoomData ZoomedTextData returns boolean
//*
//*                    - Because .evaluate is used, this function may not have waits or use GetTriggeringTrigger()
//*                    - If the function returns true, the texttag is destroyed; if false, it is not
//*                    - If not destroyed, doing so at a later time is the responsibility of the user
//*                    - If this argument is 'null', then the Default function will be called
//*                    - After the end of this function, the relevant ZoomData is automatically destroyed
//*      returns ZoomData: this is the ZoomData associated with this zooming instance, so that some arguments may
//*                        be modified by the user
//*
//*  ZoomTextInOut
//*      This function zooms a texttag from size X to size Y, then down to size Z, taking A seconds to zoom to Y,
//*      B seconds paused at Y, and C seconds to zoom to Z
//*
//*      whichText: see above
//*      s: see above
//*      startSize: see above
//*      endSize: see above
//*      zoomSize: size Y in the above description
//*      zoomInDuration: time A in the above description
//*      stayDuration: time B in the above description
//*      zoomOutDuration: time C in the above description
//*      callbackCode: see above; however, this is only called at the end of time C, and nowhere else
//*      returns ZoomData: see above
//*
//*  Default
//*      This function is the default function if callbackCode is 'null'; you can set it to whatever you want,
//*      but remember that this system does not destroy the texttags by default
//********************************************************************************

//==============================================================================
    globals
        private constant real TIMER_INTERVAL = 0.04
    endglobals

    private function Default takes ZoomData ZoomedTextData returns boolean
        return true
    endfunction

    //==========================================================================
    globals
        private timer T = null
        private integer N = 0
        public ZoomData array ZoomDatas
        private Table TimerData
    endglobals

    function interface ZoomCallbackFunction takes ZoomData ZoomedTextData returns boolean

    private struct ZoomData
        texttag Text = null
        string S = ""
        real SizeMod = 0.00
        real Size = 0.00
        boolean InOut = false
        real OutSize = 0.00
        real OutDur = 0.00
        real PauseDur = 0.00
        ZoomCallbackFunction ZCF = null
        ZoomCallbackFunction RealZCF = null
        integer N = 0
    endstruct

    private function H2I takes handle H returns integer
        return H
        return 0
    endfunction

    private function ZoomCallback takes nothing returns nothing
        local integer J = -1
        local ZoomData ZD

        loop
            set J = J+1
            exitwhen J >= N

            set ZD = ZoomDatas[J]

            set ZD.size = ZD.size + ZD.SizeMod
            call SetTextTagText(ZD.Text, ZD.S, ZD.size)
            set ZD.N = ZD.N - 1

            if ZD.N <= 0 then
                if ZD.ZCF.evaluate(ZD) then
                    call DestroyTextTag(ZD.Text)
                endif

                if not(ZD.InOut) then
                   call ZD.destroy()
                endif

                set N = N-1
                if N > 0 then
                    set ZoomDatas[J] = ZoomDatas[N]
                    set J = J-1
                else
                    call PauseTimer(T)
                    call ReleaseTimer(T)
                endif
            endif
        endloop
    endfunction

    function ZoomText takes texttag whichText, string s, real startSize, real endSize, real duration, ZoomCallbackFunction callbackCode returns ZoomData
        local ZoomData ZD = ZoomData.create()

        call SetTextTagText(whichText, s, startSize)
        if callbackCode == null then
            set callbackCode = function Default
        endif

        set ZD.Text = whichText
        set ZD.S = s
        set ZD.N = R2I(duration/TIMER_INTERVAL)
        set ZD.Size = startSize
        set ZD.SizeMod = (endSize-startSize)/ZD.N
        set ZD.ZCF = callbackCode

        set ZoomDatas[N] = ZD
        set N = N+1

        if N == 1 then
            set T = NewTimer()
            call TimerStart(T, TIMER_INTERVAL, true, function ZoomCallback)
        endif

        return ZD
    endif

    private function PauseFinish takes nothing returns nothing
        local timer PauseT = GetExpiredTimer()
        local ZoomData ZD = ZoomData(TimerData[H2I(PauseT)])

        set ZD.InOut = false
        set ZD.ZCF = ZD.RealZCF
        set ZD.N = R2I(ZD.OutDur/TIMER_INTERVAL)
        set ZD.SizeMod = (ZD.OutSize-ZD.Size)/ZD.N

        set ZoomDatas[N] = ZD
        set N = N+1

        if N == 1 then
            set T = NewTimer()
            call TimerStart(T, TIMER_INTERVAL, true, function ZoomCallback)
        endif
    endfunction

    private function InFinish takes ZoomData ZoomedTextData returns boolean
        local timer PauseT = NewTimer()

        set TimerData[H2I(PauseT)] = ZoomedTextData
        call TimerStart(PauseT, ZoomedTextData.PauseDur, false, function PauseFinish

        return false
    endfunction

    private function ZoomTextInOut takes texttag whichText, string s, real startSize, real zoomSize, real endSize, real zoomInDuration, real stayDuration, real zoomOutDuration, ZoomCallbackFunction callbackCode returns ZoomData
        local ZoomData ZD = ZoomData.create()

        set ZoomDatas[N] = ZD
        call SetTextTagText(whichText, s, startSize)

        if callbackCode == null then
            set callbackCode = function Default
        endif

        set ZD.Text = whichText
        set ZD.S = s
        set ZD.N = R2I(zoomInDuration/TIMER_INTERVAL)
        set ZD.Size = startSize
        set ZD.SizeMod = (zoomSize-startSize)/ZD.N
        set ZD.RealZCF = callbackCode

        set ZD.InOut = true
        set ZD.OutSize = endSize
        set ZD.OutDur = zoomOutDuration
        set ZD.PauseDur = stayDuration
        set ZD.ZCF = function InFinish

        set N = N+1
        if N == 1 then
            set T = NewTimer()
            call TimerStart(T, TIMER_INTERVAL, true, function ZoomCallback)
        endif

        return ZD
    endfunction

    private function Init takes nothing returns nothing
        set TimerData = Table.create()
    endfunction
endlibrary
11-16-2008, 12:04 AM#15
Pyrogasm
Okay, so here's the most current update:
Collapse JASS:
library ZoomTextLibrary initializer Init requires TimerUtils, Table
//********************************************************************************
//* ZoomTextLibrary
//* ------------
//*
//* The purpose of this library is to provide an easy way to make zooming TextTags
//* Example: local texttag TT = CreateTextTag()
//*          call SetTextTagPosUnit(TT, GetTriggerUnit(), 50.00)
//*          call ZoomTextInOut(TT, R2S(GetEventDamage()), 0.25, 3.00, 0.00, 0.50, 1.50, 0.30, null)
//*
//* Function Explanation:
//*   ZoomText
//*      This function zooms a texttag from size X to size Y over Z seconds; it does not zoom in and out,
//*      but rather only one of the two
//*      However, it can perform both: endsize > startsize = in, endsize < startsize = out
//*
//*      whichText: the texttag you want to zoom (created by the user, not this library) 
//*      s: the string you want the texttag to display (because to set the height you must also set its text)
//*      startSize: the starting size of the text (NOT a font size, see TextTagSize2Height in Blizzard.j)
//*      endSize: the ending size of the zoom
//*      callbackCode: this is the function that is evalutated upon the zoom being completed; it must conform to this:
//*
//*                    function interface ZoomCallbackFunction takes ZoomData ZoomedTextData returns boolean
//*
//*                    - Because .evaluate is used, this function may not have waits or use GetTriggeringTrigger()
//*                    - If the function returns true, the texttag is destroyed; if false, it is not
//*                    - If not destroyed, doing so at a later time is the responsibility of the user
//*                    - If this argument is 'null', then the Default function will be called
//*                    - After the end of this function, the relevant ZoomData is automatically destroyed
//*      returns ZoomData: this is the ZoomData associated with this zooming instance, so that some arguments may
//*                        be modified by the user
//*
//*  ZoomTextInOut
//*      This function zooms a texttag from size X to size Y, then down to size Z, taking A seconds to zoom to Y,
//*      B seconds paused at Y, and C seconds to zoom to Z
//*
//*      whichText: see above
//*      s: see above
//*      startSize: see above
//*      endSize: see above
//*      zoomSize: size Y in the above description
//*      zoomInDuration: time A in the above description
//*      stayDuration: time B in the above description
//*      zoomOutDuration: time C in the above description
//*      callbackCode: see above; however, this is only called at the end of time C, and nowhere else
//*      returns ZoomData: see above
//*
//*  Default
//*      This function is the default function if callbackCode is 'null'; you can set it to whatever you want,
//*      but remember that this system does not destroy the texttags by default
//********************************************************************************

//==============================================================================
    globals
        private constant real TIMER_INTERVAL = 0.04
    endglobals

    private function Default takes ZoomData ZoomedTextData returns boolean
        return true
    endfunction

    //==========================================================================
    globals
        private timer T = null
        private integer N = 0
        public ZoomData array ZoomDatas
        private Table TimerData
    endglobals

    function interface ZoomCallbackFunction takes ZoomData ZoomedTextData returns boolean

    private struct ZoomData
        texttag Text = null
        string S = ""
        real SizeMod = 0.00
        real Size = 0.00
        boolean InOut = false
        real OutSize = 0.00
        real OutDur = 0.00
        real PauseDur = 0.00
        ZoomCallbackFunction ZCF = null
        ZoomCallbackFunction RealZCF = null
        integer N = 0
    endstruct

    private function H2I takes handle H returns integer
        return H
        return 0
    endfunction

    private function ZoomCallback takes nothing returns nothing
        local integer J = -1
        local ZoomData ZD

        loop
            set J = J+1
            exitwhen J >= N

            set ZD = ZoomDatas[J]

            set ZD.Size = ZD.Size + ZD.SizeMod
            call SetTextTagText(ZD.Text, ZD.S, ZD.Size)
            set ZD.N = ZD.N - 1

            if ZD.N <= 0 then
                if ZD.ZCF.evaluate(ZD) then
                    call DestroyTextTag(ZD.Text)
                endif

                if not(ZD.InOut) then
                   call ZD.destroy()
                endif

                set N = N-1
                if N > 0 then
                    set ZoomDatas[J] = ZoomDatas[N]
                    set J = J-1
                else
                    call PauseTimer(T)
                    call ReleaseTimer(T)
                endif
            endif
        endloop
    endfunction

    function ZoomText takes texttag whichText, string s, real startSize, real endSize, real duration, ZoomCallbackFunction callbackCode returns ZoomData
        local ZoomData ZD = ZoomData.create()

        call SetTextTagText(whichText, s, startSize)
        if callbackCode == null then
            set callbackCode = function Default
        endif

        set ZD.Text = whichText
        set ZD.S = s
        set ZD.N = R2I(duration/TIMER_INTERVAL)
        set ZD.Size = startSize
        set ZD.SizeMod = (endSize-startSize)/ZD.N
        set ZD.ZCF = callbackCode

        set ZoomDatas[N] = ZD
        set N = N+1

        if N == 1 then
            set T = NewTimer()
            call TimerStart(T, TIMER_INTERVAL, true, function ZoomCallback)
        endif

        return ZD
    endif

    private function PauseFinish takes nothing returns nothing
        local timer PauseT = GetExpiredTimer()
        local ZoomData ZD = ZoomData(TimerData[H2I(PauseT)])

        set ZD.InOut = false
        set ZD.ZCF = ZD.RealZCF
        set ZD.N = R2I(ZD.OutDur/TIMER_INTERVAL)
        set ZD.SizeMod = (ZD.OutSize-ZD.Size)/ZD.N

        set ZoomDatas[N] = ZD
        set N = N+1

        if N == 1 then
            set T = NewTimer()
            call TimerStart(T, TIMER_INTERVAL, true, function ZoomCallback)
        endif

        call ReleaseTimer(PauseT)
    endfunction

    private function InFinish takes ZoomData ZoomedTextData returns boolean
        local timer PauseT = NewTimer()

        set TimerData[H2I(PauseT)] = ZoomedTextData
        call TimerStart(PauseT, ZoomedTextData.PauseDur, false, function PauseFinish

        return false
    endfunction

    private function ZoomTextInOut takes texttag whichText, string s, real startSize, real zoomSize, real endSize, real zoomInDuration, real stayDuration, real zoomOutDuration, ZoomCallbackFunction callbackCode returns ZoomData
        local ZoomData ZD = ZoomData.create()

        set ZoomDatas[N] = ZD
        call SetTextTagText(whichText, s, startSize)

        if callbackCode == null then
            set callbackCode = function Default
        endif

        set ZD.Text = whichText
        set ZD.S = s
        set ZD.N = R2I(zoomInDuration/TIMER_INTERVAL)
        set ZD.Size = startSize
        set ZD.SizeMod = (zoomSize-startSize)/ZD.N
        set ZD.RealZCF = callbackCode

        set ZD.InOut = true
        set ZD.OutSize = endSize
        set ZD.OutDur = zoomOutDuration
        set ZD.PauseDur = stayDuration
        set ZD.ZCF = function InFinish

        set N = N+1
        if N == 1 then
            set T = NewTimer()
            call TimerStart(T, TIMER_INTERVAL, true, function ZoomCallback)
        endif

        return ZD
    endfunction

    private function Init takes nothing returns nothing
        set TimerData = Table.create()
    endfunction
endlibrary
I get "Syntax Error" on the line private function PauseFinish takes nothing returns nothing, and I've got to go now so I don't have time to figure it out. However, you can try to fix the syntax errors yourself if you want.

Or, if someone else can tell me what the error on that line is, because I cannot figure it out for the life of me.