HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Help Fixing and cleaning up code

08-03-2009, 05:32 AM#1
Drain Pipe
Ok so I'm pretty green to the whole JASS and vJass stuff so I started by taking a system that i made initially using GUI and converting it into what i think* is it's Jass equivalent, and integrating it to use Rising Dusk's Intuitive damage detection System. The problem is, I'm not sure where I'm doing pointless actions and where i may be leaking, if at all. So without further ado, this is what I've got:

Collapse JASS:
scope DamageDisplaySystem initializer Init
globals
    //Just color modifiers for each player colour so that the FT color matches player color
    
        private real array RED[11]
        private real array BLUE[11]
        private real array GREEN[11]
        
    //other arrays needed to allocate information and update slots as FTs are created/destroyed.
    
    private constant integer FT_MAX = 50 // Maximum number of floating texts that will be created per player. Can be scaled between values of 1-100 as needed.  For most maps it could be left at about 20-25.
    private constant real StackTimer = 0.25 // Maximum time interval between damage events in which the floating text on the unit will update before it is displayed and destroyed.
    private constant real PeriodicCheck = 0.025 // this can be modified as needed
    
    private group array DMG_PLAYER_GROUP[11] // Organizes units damaged by player
    private integer array DMG_PLAYER_GROUP_INT[11]
    
    private unit array DMG_PLAYER_GROUP_UNIT[FT_MAX]
    private real array DMG_PLAYER_GROUP_DMG[FT_MAX]
    private texttag array DMG_PLAYER_GROUP_FT[FT_MAX]
    private timer array DMG_PLAYER_GROUP_TIMER[FT_MAX]
    
    private timer FT_Timer = CreateTimer()
    
endglobals

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

function GetUnitZtrue takes unit u returns real
return (GetUnitFlyHeight(u)+ GetLocationZ(Location(GetUnitX(u),GetUnitY(u))))
endfunction

function GetUnitZ takes unit u returns real
return (GetUnitFlyHeight(u))
endfunction

function SetFT takes texttag Whichtag, string WhichString, integer DisplayPlayerID, real x, real y, real z, real RED, real BLUE, real GREEN, real ALPHA, real Xvel, real Yvel, real FadeTime, boolean Permanence, real size returns nothing
    call SetTextTagText(Whichtag, WhichString, size * 0.023 / 10)
    call SetTextTagPos(Whichtag, x, y, z+50.)
    call SetTextTagColorBJ(Whichtag, RED, GREEN, BLUE, ALPHA)
    call SetTextTagVelocity(Whichtag, Xvel, Yvel)
    if GetLocalPlayer() == Player(DisplayPlayerID) and IsMaskedToPlayer(x,y,Player(DisplayPlayerID))==false and IsFoggedToPlayer(x,y,Player(DisplayPlayerID))==false then
        call SetTextTagVisibility(Whichtag, true)
    else
        call SetTextTagVisibility(Whichtag, false)
    endif
    call SetTextTagPermanent(Whichtag, Permanence)
    call SetTextTagSuspended(Whichtag,Permanence)
    if (Permanence == false) then
        call SetTextTagFadepoint(Whichtag, FadeTime*2/3)
        call SetTextTagLifespan(Whichtag, FadeTime)
    endif

endfunction

function QuickFT takes string WhichString, integer DisplayPlayerID, real x, real y, real z, real RED, real BLUE, real GREEN, real ALPHA, real Xvel, real Yvel, real FadeTime, boolean Permanence, real size returns texttag
    set bj_lastCreatedTextTag = CreateTextTag()
    call SetTextTagText(bj_lastCreatedTextTag, WhichString, size * 0.023 / 10)
    call SetTextTagPos(bj_lastCreatedTextTag, x, y, z+50.)
    call SetTextTagColorBJ(bj_lastCreatedTextTag, RED, GREEN, BLUE, ALPHA)
    call SetTextTagVelocity(bj_lastCreatedTextTag, Xvel, Yvel)
    if GetLocalPlayer() == Player(DisplayPlayerID) and IsMaskedToPlayer(x,y,Player(DisplayPlayerID))==false and IsFoggedToPlayer(x,y,Player(DisplayPlayerID))==false then
        call SetTextTagVisibility(bj_lastCreatedTextTag,true)
    else
        call SetTextTagVisibility(bj_lastCreatedTextTag, false)
    endif
    call SetTextTagPermanent(bj_lastCreatedTextTag, Permanence)
    call SetTextTagSuspended(bj_lastCreatedTextTag,Permanence)
    if (Permanence == false) then
        call SetTextTagFadepoint(bj_lastCreatedTextTag, FadeTime*2/3)
        call SetTextTagLifespan(bj_lastCreatedTextTag, FadeTime)
    endif
    return bj_lastCreatedTextTag
endfunction

function SetTextTagAlpha takes texttag Whichtag, real transparency returns nothing
endfunction
        
private function Conditions takes nothing returns boolean
    return GetTriggerDamageType() != DAMAGE_TYPE_TEST
endfunction

private function Actions takes nothing returns nothing
    local unit u = GetTriggerDamageSource()
    local unit t = GetTriggerDamageTarget()
    local real d = GetTriggerDamage()
    local integer i
    if IsUnitInGroup(t, DMG_PLAYER_GROUP[GetPlayerId(GetOwningPlayer(u))]) == false then
        set DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] = DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] + 1 
        call GroupAddUnit(DMG_PLAYER_GROUP[GetPlayerId(GetOwningPlayer(u))], t )
        set DMG_PLAYER_GROUP_UNIT[( ( FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) ) + DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] )] = t
        set DMG_PLAYER_GROUP_DMG[( ( FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) ) + DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] )] = d
        set DMG_PLAYER_GROUP_FT[( ( FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) ) + DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] )] = CreateTextTag()
        call SetFT(DMG_PLAYER_GROUP_FT[( ( FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) ) + DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] )],I2S(R2I(d)), GetPlayerId(GetOwningPlayer(u)), GetUnitX(t),GetUnitY(t),GetUnitZ(t),RED[GetPlayerId(GetOwningPlayer(u))],GREEN[GetPlayerId(GetOwningPlayer(u))],BLUE[GetPlayerId(GetOwningPlayer(u))],50.,0.,0.,5.0,true,7.+2.*DMG_PLAYER_GROUP_DMG[( ( FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) ) + DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] )]/ 600.00)
        call TimerStart(DMG_PLAYER_GROUP_TIMER[( ( FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) ) + DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))] )],StackTimer,false,null)
    else
        set i = ( FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) )
        loop
            exitwhen i > ((FT_MAX * ( GetPlayerId(GetOwningPlayer(u))) ) + DMG_PLAYER_GROUP_INT[GetPlayerId(GetOwningPlayer(u))])
            if t == DMG_PLAYER_GROUP_UNIT[i] then
                set DMG_PLAYER_GROUP_DMG[i] = ( DMG_PLAYER_GROUP_DMG[i] + d )
                call TimerStart( DMG_PLAYER_GROUP_TIMER[i],StackTimer,false,null)
            endif
            set i = i + 1
        endloop
    endif
    
    set u = null
    set t = null
    set i = 0
    set d = 0
endfunction

private function Conditions2 takes nothing returns boolean
    return not(DMG_PLAYER_GROUP_INT[0] == -1 and DMG_PLAYER_GROUP_INT[1] == -1 and DMG_PLAYER_GROUP_INT[2] == -1 and DMG_PLAYER_GROUP_INT[3] == -1 and DMG_PLAYER_GROUP_INT[4] == -1 and DMG_PLAYER_GROUP_INT[5] == -1 and DMG_PLAYER_GROUP_INT[6] == -1 and DMG_PLAYER_GROUP_INT[7] == -1 and DMG_PLAYER_GROUP_INT[8] == -1 and DMG_PLAYER_GROUP_INT[9] == -1 and DMG_PLAYER_GROUP_INT[10] == -1 and DMG_PLAYER_GROUP_INT[11] == -1)
endfunction

private function Actions2 takes nothing returns nothing
    local integer i = 0
    local integer j
    local integer maxslot
    local integer currentslot
    loop
        exitwhen i > 0
        set maxslot = DMG_PLAYER_GROUP_INT[i]
        set j = ( ( FT_MAX * ( i ) ) )
        loop
            exitwhen j > ( ( FT_MAX * ( i ) ) + maxslot )
            set currentslot = ( ( ( FT_MAX * ( i ) ) + maxslot ) - ( ( j ) - ( FT_MAX * ( i ) ) ) )
            call SetFT(DMG_PLAYER_GROUP_FT[currentslot],( I2S(R2I(DMG_PLAYER_GROUP_DMG[currentslot])) ), i,GetUnitX(DMG_PLAYER_GROUP_UNIT[currentslot]),GetUnitY(DMG_PLAYER_GROUP_UNIT[currentslot]),GetUnitZ(DMG_PLAYER_GROUP_UNIT[currentslot]),RED[i],GREEN[i],BLUE[i],50.,0.,0.,5.0,true,( 7.00 + ( 2.00 * ( DMG_PLAYER_GROUP_DMG[currentslot] / 600.00 ) ) ))
            if (TimerGetRemaining(DMG_PLAYER_GROUP_TIMER[currentslot]) <= 0.) then
                call SetFT(DMG_PLAYER_GROUP_FT[currentslot],( I2S(R2I(DMG_PLAYER_GROUP_DMG[currentslot])) ), i, GetUnitX(DMG_PLAYER_GROUP_UNIT[currentslot]),GetUnitY(DMG_PLAYER_GROUP_UNIT[currentslot]),GetUnitZ(DMG_PLAYER_GROUP_UNIT[currentslot]),RED[i],GREEN[i],BLUE[i],50.,0.,0.,5.0,false,( 7.00 + ( 2.00 * ( DMG_PLAYER_GROUP_DMG[currentslot] / 600.00 ) ) ))
                call DestroyTextTag(DMG_PLAYER_GROUP_FT[currentslot])
                call QuickFT(( I2S(R2I(DMG_PLAYER_GROUP_DMG[currentslot])) + "!" ), i, GetUnitX(DMG_PLAYER_GROUP_UNIT[currentslot]), GetUnitY(DMG_PLAYER_GROUP_UNIT[currentslot]),GetUnitZ(DMG_PLAYER_GROUP_UNIT[currentslot]),RED[i],GREEN[i],BLUE[i],0.,GetRandomReal(-0.007,0.007),0.02,( 0.75+1.5 * ( DMG_PLAYER_GROUP_DMG[currentslot] / 300.00 ) ),false,( 7.00 + ( 2.00 * ( DMG_PLAYER_GROUP_DMG[currentslot] / 600.00 ) ) ))
                    // Replacing last slot into empty slot
                call GroupRemoveUnit( DMG_PLAYER_GROUP[i], DMG_PLAYER_GROUP_UNIT[currentslot] )
                set DMG_PLAYER_GROUP_UNIT[currentslot] = DMG_PLAYER_GROUP_UNIT[( ( FT_MAX * ( i ) ) + DMG_PLAYER_GROUP_INT[i] )]
                set DMG_PLAYER_GROUP_DMG[currentslot] = DMG_PLAYER_GROUP_DMG[( ( FT_MAX * ( i ) ) + DMG_PLAYER_GROUP_INT[i] )]
                set DMG_PLAYER_GROUP_FT[currentslot] = CreateTextTag()
                call SetFT(DMG_PLAYER_GROUP_FT[currentslot],"", i, GetUnitX(DMG_PLAYER_GROUP_UNIT[currentslot]),GetUnitY(DMG_PLAYER_GROUP_UNIT[currentslot]),GetUnitZ(DMG_PLAYER_GROUP_UNIT[currentslot]),40.,40.,40.,0.,0.,0.,5.0,true,7.+2.*DMG_PLAYER_GROUP_DMG[currentslot]/ 600.00)
                    // Getting Rid of the last slot stats
                call TimerStart(DMG_PLAYER_GROUP_TIMER[currentslot], TimerGetRemaining(DMG_PLAYER_GROUP_TIMER[( ( FT_MAX * ( i ) ) + DMG_PLAYER_GROUP_INT[i] )]),false, null)
                set DMG_PLAYER_GROUP_UNIT[( ( FT_MAX * ( i ) ) + DMG_PLAYER_GROUP_INT[i] )] = null
                call DestroyTextTag(DMG_PLAYER_GROUP_FT[( ( FT_MAX * ( i ) ) + DMG_PLAYER_GROUP_INT[i] )] )
                set DMG_PLAYER_GROUP_INT[i] = ( DMG_PLAYER_GROUP_INT[i] - 1 )
            endif
            set j = j + 1
        endloop
        set i = i + 1
    endloop
set i = 0
set j = 0
set maxslot = 0
set currentslot = 0
endfunction

private function Init takes nothing returns nothing
    local trigger trg = CreateTrigger()
    local integer i = 0
    local integer j = 0
        set RED[0] = 100.00
        set BLUE[0] = 0.00
        set GREEN[0] = 0.00
        set RED[1] = 0.00
        set BLUE[1] = 100.00
        set GREEN[1] = 0.00
        set RED[2] = 10.98
        set BLUE[2] = 72.55
        set GREEN[2] = 90.20
        set RED[3] = 32.95
        set BLUE[3] = 50.59
        set GREEN[3] = 0.00
        set RED[4] = 100.00
        set BLUE[4] = 0.00
        set GREEN[4] = 100.00
        set RED[5] = 100.00
        set BLUE[5] = 5.49
        set GREEN[5] = 54.12
        set RED[6] = 12.55
        set BLUE[6] = 0.00
        set GREEN[6] = 75.29
        set RED[7] = 89.80
        set BLUE[7] = 69.02
        set GREEN[7] = 35.69
        set RED[8] = 58.82
        set BLUE[8] = 58.82
        set GREEN[8] = 58.82
        set RED[9] = 49.41
        set BLUE[9] = 94.51
        set GREEN[9] = 74.90
        set RED[10] = 6.27
        set BLUE[10] = 27.45
        set GREEN[10] = 38.43
        set RED[11] = 30.59
        set BLUE[11] = 0.00
        set GREEN[11] = 16.47
        loop
            exitwhen i > 11
            set DMG_PLAYER_GROUP_INT[i] = -1
            set DMG_PLAYER_GROUP[i] = CreateGroup()
            set i = i + 1
        endloop
    set i = 0
    set j = 0
        loop
            exitwhen i > 11
                    loop
                        exitwhen j > FT_MAX
                        set DMG_PLAYER_GROUP_TIMER[(i*FT_MAX)+j]=CreateTimer()
                        set j = j + 1
                    endloop
            set i = i + 1
        endloop
    
    call TriggerAddAction(trg, function Actions)
    call TriggerAddCondition(trg, Condition(function Conditions))
    call TriggerRegisterDamageEvent(trg, 0)
    set trg = CreateTrigger()
    call TriggerAddAction(trg, function Actions2)
    call TriggerAddCondition(trg, Condition(function Conditions2))
    call TriggerRegisterTimerExpireEvent(trg, FT_Timer)
    call TimerStart(FT_Timer, PeriodicCheck,true, null)

    
    set i = 0
    set j = 0
    set trg = null
endfunction
endscope

Anyways, Before you dive in and ask what everything is for I'll lay out the system for you. It's pretty basic in design and the idea came to me when I noticed some maps displaying the damage dealt from abilities to the player. I thought this was a neat Idea, although i had a beef about cluttered floating texts flying all over the place. I also wanted a method so that i could get the total damage dealt if multiple damage events hit all at once (ie for shotgun style abilities, like pluck yew from tob). So i came up with this.

The system is setup to handle up to 100 floating texts displayed per character, but this can be tweaked to whatever you require. The floating text will appear dimmed over the unit, displaying the current total damage dealt to said unit with the same colour as your player colour. There is a timer which you can set which is the time between damage events in which the floating text will continuously update the damage being dealt. After that time fades, the floating text will light up and float away like any normal text, displaying the total stacked damage on the unit.

The purpose for this system is to allow chain-damage events to be stacked and displayed to the player, something like displaying combo damage dealt to a unit.


Now as for my method, I basically have 2 sets of arrays which store the player and the slot occupied by the damaged unit.

Now the trigger is split up into the triggered damage events and monitoring the floating text until it dies. There's a periodic update which can be adjusted as needed which, so long as at least one slot is open for any player, cycles from the last position down to the first slot for each player, updates the texts, and replaces any expired slots similar to how most other systems work (ie knockback systems). As far as i know it work's just fine and doesn't really seem have any leaks that I can think of (though I'm sure there are, since I'm not quite used to all the things that can go wrong with this stuff), but I'm pretty sure my method for storing the units and information can be simplified with structs and other clean ups, tho i haven't really gotten into using structs yet.

anywho, I'd appreciate any help with cleaning this up. I will be using this system in the future and Hopefully I can get a user freindly one up once I'm better with JASS.
08-03-2009, 07:30 AM#2
Sophismata
This sounds really cool - particularly because I've been wanting to write up something similar. Hopefully I can help you out - I'll look over the code this evening.
08-03-2009, 07:34 AM#3
Tot
lil question: how do you get the damage to show? (can't find it in your code)
08-03-2009, 08:27 AM#4
Sophismata
Looking over the code, there's a whole bunch of stuff that we can change. For example, you require the use of IDDS, which itself requires the use of GroupUtils. Thus, you should be using GroupUtils to handle groups. (Sorry, that was my modification. Default IDDS only requires table.)

Also, there's no way to guarantee that player-colours remain the same as at init, so I'd avoid colouring damage that way, and instead allow a way to link damage colour to damage type (as defined by IDDS, a requirement).

Further, I'd then include functions to call the system manually for user-defined events, such as unit healing.



Give me some time, I'll go over this in more detail and post my suggestions and recommendations. As I said, this is something I've been wanting to do for a while, so I'm excited :).
08-03-2009, 10:55 AM#5
Pyrogasm
Well. There's one thing that's going to kill you: the game engine can only display 99 texttags for each player at any given time. Albeit this means that if 99 texttags are shown for Player 1 with GetLocalPlayer() blocks, then a separate 99 can be shown for Player 2... but when you go over 99 the first ones start to disappear.

As for your system:
  • There is no need to size 1-dimensional arrays not inside structs, like you did here:
    Collapse JASS:
    globals
            private real array RED[11]
            private real array BLUE[11]
            private real array GREEN[11]
        private group array DMG_PLAYER_GROUP[11]
        private integer array DMG_PLAYER_GROUP_INT[11]
        
        private unit array DMG_PLAYER_GROUP_UNIT[FT_MAX]
        private real array DMG_PLAYER_GROUP_DMG[FT_MAX]
        private texttag array DMG_PLAYER_GROUP_FT[FT_MAX]
        private timer array DMG_PLAYER_GROUP_TIMER[FT_MAX]
    endglobals
  • In your GetUnitZtrue function you're leaking a location (Location(GetUnitX(u),GetUnitY(u))), which you want to fix. The best way to do this (in this specific situation) is to have a global location and then just use MoveLocation() instead:
    Collapse JASS:
    globals
        private location ZLoc = Location(0.00, 0.00) //Set this at init
    endglobals
    
    private function GetUnitZtrue takes unit u returns real
        call MoveLocation(L, GetUnitX(u),GetUnitY(u))
        return GetUnitFlyHeight(u) + GetLocationZ(ZLoc
    endfunction
  • Most, if not all of your functions should be private. GetUnitZ especially since it's such a common function name.

    Along that same line of thinking, renaming some of your functions would be a good idea. "Actions2" is a bit ambiguous, if you get my drift.
  • You could really benefit from using ARGB to color your texttags. That would prevent you from having to use those stupid RGB arrays to define the player colors. Alternatively, you could make the text colored using the |cRRGGBBAA <text> |r color codes.
  • Why are you allocating so many timers?! A system like this should be able to be run on 1 timer only, but I'll get to that later...
  • This is out of order here, but I just thought of this: when you use the 0 index of an array, you can still use a "count" variable to display which indexes are used.

    Simply increase Count after you use it and always loop until >= count:
    Collapse JASS:
    set MyArray[Count] = 5 //Count == 0; MyArray[0] = 5
    set Count = Count+1 //Count == 1
    //...
    set i = 0
    loop
        call BJDebugMsg(I2S(MyArray[i]))
        set i = i+1
        exitwhen i >= Count
    endloop
  • This is a very dumb way of doing things:
    Collapse JASS:
        call TriggerAddAction(trg, function Actions2)
        call TriggerAddCondition(trg, Condition(function Conditions2))
        call TriggerRegisterTimerExpireEvent(trg, FT_Timer)
        call TimerStart(FT_Timer, PeriodicCheck,true, null)
    

    Instead, you could simply have the timer run Actions2 (call TimerStart(FT_Timer, PeriodicCheck, true, function Actions2))and check if Conditions() == true inside Actions2, or just inline the check altogether.

    Actually, now that I think about it you could remove the need for a Conditions2 altogether. Instead of checking all of those array members vs. -1, when Actions is run check some global boolean. If false, there is no timer started, and you can call TimerStart() from Actions. If the boolean is true then the timer is already running.

    Then in Actions2, if there are currently 0 floating text being monitored, then you set the boolean = false and then call PauseTimer()
  • Okay, so from looking at your code, what I can tell you is that you would benefit enormously from the usage of structs. You're basically doing all of the work yourself right now... If you read Vexorian's tutorial vJASS for Spell Makers, you should get a pretty good feel for how structs work, but just to get you started I would suggest this:
    Collapse JASS:
    struct FTInstance
        texttag T
        unit U
        real D
        //A few other things that I'll get to later
    endstruct
    
    struct FTData extends array //extends array should be in the JASSHelper manual; basically it allows us to do "FTData[<an integer>]"
        player P
        FTInstance array FTIs[99] //Since 99 is the maximum number of texttags for any given player
        integer Count = 0
        group G
    endstruct
    Then you can simply loop through the FTDatas and their corresponding FTInstances to get the relevant data. So, how about this for a rewrite of Actions2 and Init:

    Collapse JASS:
    function Periodic takes nothing returns nothing
        local integer K = 0//Capital I's do weird things in [ jass] tags...
        local integer J
        local FTInstance F
    
        loop
            set J = 0
    
            loop
                set F = FTData[K].FTIs[J]
    
                //Do all of your stuff for setting .T here
                //Replacing the last instance is quite easy once you're using structs, but I'll leave that to you to figure out
                
                set J = J+1
                exitwhen J >= FTData[K].Count
            endloop
        endloop
    endfunction
    
    private function Init takes nothing returns nothing
        local integer J = 0
        local trigger trg = CreateTrigger()
    
        loop
            set FTData[J] = FTData.create()
            set FTData[J].G = CreateGroup()
    
            //You could even instancate all of the FTInstances now if you wanted...
            //I don't know what purpose it would serve, but you could do it.
    
            set J = J+1
            exitwhen J >= 12
        endloop
    
        call TriggerAddAction(trg, function Damaged)
        call TriggerAddCondition(trg, Condition(function DamagedConditions))
        call TriggerRegisterDamageEvent(trg, 0)
    
        call TimerStart(FT_Timer, PeriodicCheck, true, function Periodic)
    endfunction
    BAM! That looks a lot cleaner.

  • Now, I could rewrite your whole system for you, but I need to wake up to leave for vacation in 3 hours so I'm not going to do that. Instead, I'm going to let you dick around with structs and figure out how best to organize your system.

    A lot of learning is simply doing, and now that you have some direction I think you can fix a lot of what needs to be fixed.

    There is one thing that I seriously recommend you fix: the timer issue. You have a timer for every floating text instance, which is just no good. FT_Timer runs every 0.025 seconds, which is damn fast (for good reason, though), and you could certainly just run a few extra actions on it every time.

    Instead of creating a new timer for every instance and then checking to see when it expires and all of that bullshit, just add a new member to your FTInstance struct: integer Life.

    When you create a texttag, set .Life = R2I(<Duration of texttag>/<Timer interval>). This serves as a sort of counter to see when the texttag should be destroyed. In every iteration of Periodic, set F.Life = F.Life-1; if F.Life <= 0, then destroy F and clean everything up. Else, do nothing.

    Then in Actions (which I would rename to "onDamage" or "Damaged" or something), set F.Life = (<Duration of texttag>/<Timer interval>) to refresh the time until it's 'locked in'.

    If you don't quite understand this, take a look at a few quality spells in the database and you'll see how they will use counter variables to determine when some repetitive action is to be stopped.

I really would like to make another "I have no life so I do this to people's code" post, but I seriously must go. I hope this helps you out a lot :)
08-03-2009, 12:31 PM#6
Sophismata
Quote:
Originally Posted by Pyrogasm
Well. There's one thing that's going to kill you: the game engine can only display 99 texttags for each player at any given time. Albeit this means that if 99 texttags are shown for Player 1 with GetLocalPlayer() blocks, then a separate 99 can be shown for Player 2... but when you go over 99 the first ones start to disappear.

That shouldn't be a problem - as long as textags have their permanence set to false and are given a lifespan, they are removed. I don't think there are many situations where you'd be showing 90 or more textags at once.


Quote:
Originally Posted by Pyrogasm
I really would like to make another "I have no life so I do this to people's code" post, but I seriously must go. I hope this helps you out a lot :)

Enjoy your vacation, by the by.
08-03-2009, 05:34 PM#7
Drain Pipe
Wow I am very grateful for all the feed back. Not quite everything is clear to me but most of it makes sense. As for replacing slots, I've been told how it's done so i shouldn't have too much trouble with it now. Anyways, Thanks a bunch for all the tips and fixes. Hope you have a great trip.

NOW, for whomever is still here I have questions which will modify how i go about fixing this.

1) Some of the functions i made in here I will be using outside of this system. I actually have some 10-15 functions that will be used over the entire map. Is there a way i can simply group them all in one tidy spot, and just refer to them any other private functions?

..More questions to come as I get stuck...
08-03-2009, 07:23 PM#8
Anitarf
The answer tot hat question would depend on a lot of factors. For starters, if you have decent documentation listing all the public functions available, it doesn't matter where in the library those functions are. I still prefer to group them together for more organisation when writing code, but when it comes to large libraries with multiple subsections that may actually make things less organised, also if I have a textmacro that generates both public and private functions, I won't go out of my way to split it into two so that public functions would end up getting generated together.
08-04-2009, 12:21 AM#9
Drain Pipe
Well for now I only have about 5 or 6 functions but I plan to make more, and would rather they stay altogether. These will be more like small but useful functions that are used with multiple applications, from spells, to systems to whatever else you can do in an AoS. So having them in their own spot would work out for the best. Do I just create a library for all of them or what? These are all independent of each other.
08-04-2009, 12:55 AM#10
Anitarf
Wait a minute, you mean a compilation of miscelaneous functions? Usually, those are either so short you can inline them or long enough to warrant their own library. Can you name some examples?
08-04-2009, 02:50 AM#11
Drain Pipe
GetUnitZ and GetUnitZTrue. I'm using that for my knockback system as well as this. QuickFT and Set FT also will be used for a bunch of other spells and things not related to this. I just put them in here because it was easier to go back and check what my inputs were when they were right there. But those functions I don't really need in there, they're more miscellanious but used in multiple systems. And I have more that i need to make still. Do I just throw all those into 1 library or what?
08-04-2009, 03:33 AM#12
Sophismata
Put related functions in related libraries. If you have a whole bunch of useful functions that don't really stand alone, you can throw them into your own library and use that as a requirement for other libraries that utilise them.

In the case of a public system, we have to include all functions that are required by the system. Those that the end-user shouldn't need to use are made private, those functions that are used to access the system are left as-is or given a system prefix.
08-04-2009, 12:45 PM#13
Anitarf
I prefer to inline stuff like GetUnitZ; it's only three lines of code (a global location declaration/initialization, a MoveLocation call and a GetLocationZ call) and you shouldn't really need it in more than a few places.

I'm not really sure how GetUnitZTrue is supposed to be different from GetUnitZ, nor what QuickFT and SetFT are supposed to be, so I can't really comment on those. In general, however, I have never needed a library of miscelaneous functions myself, so I'm sure that whatever those are they are either inlineable or deserve their own library (maybe one is even already in our resource section).
08-04-2009, 08:31 PM#14
Drain Pipe
The difference between the 2 getUnitZs is that one takes into account terrain height, while the other simply takes height from terrain. I'd have to test but I'm not 100% sure everything will work properly with getUnitZtrue.

Also QuickFT creates an unassigned floating text which will self terminate. SetFT is used to modify a newly created floating text or just update another one. I did have a CreateFT function as well for making temporarily trackable floating texts but it wasn't working so i removed it. The system itself first creates a trackable floating text that updates and then when it's time to expire, destroys that floating text, flushes out that slot, and creates a self terminating one to display the final damage dealt. Anyways, thanks for the advice. Seeing as I'm working to eventually make this system streamlined I'll have to keep those smaller functions in here anyways.
08-04-2009, 11:46 PM#15
Drain Pipe
So...now it doesn't work with the new patch... ugh....