Multiboard not updating?

Reaction score
91
I've been having this problem for around an hour now and I still can't figure it out, which is driving me totally insane - I've looked for every single mistake in my code and put debug messages everywhere. And still no effect - the code just doesn't work at some place (in a function call particularly). Everything in it is fine: values get increased, checks get ran but when it comes to updating the multi board nothing happens. It can't be from the system I'm using since it worked a few moments before everything just stopped.

Look at the function UpdateMultiboard - it is supposed to call some other function that increases the value in some column or row.

To give a short explanation on this thing - when a player's Hero attacks, 3 wisps colored in light blue and owned by player passive appear above the attacked unit's head. At random intervals one of the wisps turns into a different color and once the player is quick enough to click it, it gets light blue again and grants a "level" point for the player. The process repeats again and again, the level point gets higher and higher and all this stuff has to get pasted into a multi board, individual for each player. It is sorted like this:
Combo name | Bounty | Bonus damage
"something" | 15 | 25%

However, the multi board never gets updated, and I have no idea why.

JASS:

library ComboLib initializer Init uses TimerUtils, PUI, AMS, TimedLoop, xebasic, GetPlayerColored

// ID is for referencing some things about the wisps
//! runtextmacro PUI_PROPERTY("private", "integer", "ID", "141421")
// Time is used to count some combo stuff
//! runtextmacro PUI_PROPERTY("private", "integer", "TIME", "7")


globals
    private constant string TITLE = "Combo Meter"
    private constant integer ROWS = 4
    private constant integer COLLUMNS = 3
endglobals

globals
// declare multiboards for each player..
    Multiboard mb1
    Multiboard mb2
    Multiboard mb3
    Multiboard mb4
    Multiboard mb5
    Multiboard mb6
    Multiboard mb7
    Multiboard mb8
    
// and an array to store them (they are actually structs)
    integer array mb
    
// used with GetPlayerId() for array index - to determine the level of combo
    integer array LEVEL
// Text displayed for each level (displayed on the multiboard)
    string array TEXT
// Bonus bounty used for some other cases (also displayed on mb)
    integer array BOUNTY
// And bonus damage multiplier for other stuff (also displayed on mb)
    real array MULTIPLIER
    
// I store some player colors since I change the wisps
    playercolor array PLAYER_COLOR
endglobals

globals
    //private Table t - same syntax
    private integer array t
    private integer a = 0
    private real gx = 0.
    private real gy = 0.
    
// Group containing all heroes so TIME[] can be subtracted from them
    private group gr = CreateGroup()
endglobals

// MY NIGHTMARE, IT JUST DOESN'T WORK 
private function UpdateMultiboard takes unit cast, integer lvl returns nothing
    local player p = GetOwningPlayer(cast)
    local integer pid = GetPlayerId(p)
    local Multiboard mult = mb[pid]
    /*
    call mult.SetItem(3, 1, TEXT[LEVEL[pid]])
    call mult.SetItem(3, 2, I2S(BOUNTY[LEVEL[pid]]))
    call mult.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[pid]]))
    */
    call mult.SetItem(3, 1, TEXT[lvl])
    call mult.SetItem(3, 2, I2S(BOUNTY[lvl]))
    call mult.SetItem(3, 3, R2S(MULTIPLIER[lvl]))
    call mult.Fold()
    call mult.Unfold()
endfunction

private struct Data
    unit cast
    unit targ
    player owner
    unit array wisp[3]
// To determine whether the wisp is colored or not
// (by colored I mean color other than light blue since that looks like white)
    boolean array yes[3]
    timer tim
    trigger trig
    boolean held = false
    integer clicks
    
    private method onTimedLoop takes nothing returns boolean
        if GetWidgetLife(this.targ) > 0.405 and GetWidgetLife(this.cast) > 0.405 and GetWidgetLife(this.wisp[0]) > 0.405 and GetWidgetLife(this.wisp[1]) > 0.405 and GetWidgetLife(this.wisp[2]) > 0.405 then
            set a = 0
            set gx = GetUnitX(this.targ)
            set gy = GetUnitY(this.targ)
            loop
                exitwhen a > 2
                call SetUnitX(this.wisp[a], gx - (50. * a))
                call SetUnitY(this.wisp[a], gy + (50. * a))
                set a = a + 1
            endloop
        else
            set a = 0
            loop
                exitwhen a > 2
                call KillUnit(this.wisp[a])
                set a = a + 1
            endloop
            return TimedLoop_STOP
        endif
        return TimedLoop_CONTINUE
    endmethod
    
    implement TimedLoop
    
    private static method onCallback takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        set a = 0
        loop
            exitwhen a > 2
            set this.yes[a] = false
            call SetUnitOwner(this.wisp[a], Player(PLAYER_NEUTRAL_PASSIVE), false)
            call SetUnitColor(this.wisp[a], PLAYER_COLOR_LIGHT_BLUE)
            set a = a + 1
        endloop
        
        set a = GetRandomInt(0, 2)
        set this.yes[a] = true
        call SetUnitColor(this.wisp[a], PLAYER_COLOR[GetRandomInt(0, 7)])
        // ^ get a random wisp and color it
        
// This works...
        set gx = 2. - (0.1 * LEVEL[GetPlayerId(GetOwningPlayer(this.cast))])
        if gx < 0.8 then
            set gx = 0.8
        endif
        call SetTimerData(this.tim, this)
        call TimerStart(this.tim, gx, false, function thistype.onCallback)
    endmethod
    
    static method create takes unit cast returns thistype
        local thistype this = thistype.allocate()
        set this.cast = cast
        set this.tim = NewTimer()
        set this.trig = CreateTrigger()
        set t[GetUnitIndex(this.cast)] = integer(this)
        set this.owner = GetOwningPlayer(this.cast)
        set this.clicks = 0
        call this.startTimedLoop()
        call SetTimerData(this.tim, this)
        // this works...
        set gx = 2. - (0.1 * LEVEL[GetPlayerId(GetOwningPlayer(this.cast))])
        if gx < 0.8 then
            set gx = 0.8
        endif
        call TimerStart(this.tim, gx, false, function thistype.onCallback)
        return this
    endmethod
    
    private static method onSelect takes nothing returns boolean
        local unit sel = GetTriggerUnit()
        local integer id = ID[sel]
        local thistype this = thistype(t[GetUnitIndex(sel)])
        local player p = GetOwningPlayer(this.cast)
        local integer pid = GetPlayerId(p)
        local integer lvl
        local Multiboard mult
// everything works here...
            if this.yes[id] == true then
                if LEVEL[pid] < 14 then
                    set LEVEL[pid] = LEVEL[pid] + 1
                endif
                set mult = mb[pid]
                set lvl = LEVEL[pid]
                // EXCEPT THIS ONE ... -.-
                call UpdateMultiboard.execute(this.cast, LEVEL[pid])
                // works....
                set this.yes[id] = false
                //call SetUnitOwner(this.wisp[id], Player(PLAYER_NEUTRAL_PASSIVE), false)
                call SetUnitColor(this.wisp[id], PLAYER_COLOR_LIGHT_BLUE)
            endif
            // works... T_T
            if GetLocalPlayer() == p then
                call ClearSelection()
                call SelectUnit(this.cast, true)
            endif
            set t[GetUnitIndex(sel)] = this
        return false
    endmethod
    
    method wispSwap takes unit targ returns nothing
        local real tx = GetUnitX(targ)
        local real ty = GetUnitY(targ)
        set this.targ = targ
        set a = 0
        loop
            exitwhen a > 2
            call RemoveUnit(this.wisp[a])
            set this.wisp[a] = CreateUnit(GetOwningPlayer(this.cast), 'e004', tx, ty, 0.)
            call UnitAddAbility(this.wisp[a], 'Amrf')
            call UnitRemoveAbility(this.wisp[a], 'Amrf')
            call SetUnitFlyHeight(this.wisp[a], 150., 0.)
            call SetUnitColor(this.wisp[a], PLAYER_COLOR_LIGHT_BLUE)
            // desync?
            //call ShowUnit(this.wisp[a], GetOwningPlayer(this.wisp[a]) == GetLocalPlayer())
            call TriggerRegisterUnitEvent(this.trig, this.wisp[a], EVENT_UNIT_SELECTED)
            call TriggerAddCondition(this.trig, Condition(function thistype.onSelect))
            set ID[this.wisp[a]] = a
            set t[GetUnitIndex(this.wisp[a])] = integer(this)
            set a = a + 1
        endloop
        // works...
        call this.startTimedLoop()
    endmethod
    
    method onDestroy takes nothing returns nothing
        call TriggerClearConditions(this.trig)
        call DisableTrigger(this.trig)
        call DestroyTrigger(this.trig)
        call ReleaseTimer(this.tim)
        set a = 0
        loop
            exitwhen a > 2
            call RemoveUnit(this.wisp[a])
            set a = a + 1
        endloop
    endmethod
endstruct


// Works... 
(I separated it into another function since I thought the timer callback couldn't handle so much function calls... but actually it could so that wasn't the problem)
    
private function MultiboardCreation takes nothing returns nothing
    call TriggerSleepAction(0)
    set mb1 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb1.SetItemWidth(1, 1, 8) // "Combo name"
    call mb1.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb1.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb1.SetItemWidth(2, 1, 1)
    call mb1.SetItemWidth(2, 2, 1)
    call mb1.SetItemWidth(2, 3, 1)
    
    call mb1.SetItemWidth(3, 1, 8)
    call mb1.SetItemWidth(3, 2, 8)
    call mb1.SetItemWidth(3, 3, 8)
    
    call mb1.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb1.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb1.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb1.SetItem(3, 1, TEXT[LEVEL[0]])
    call mb1.SetItem(3, 2, I2S(BOUNTY[LEVEL[0]]))
    call mb1.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[0]]))
    
    if GetLocalPlayer() == Player(0) then
        call mb1.Show()
    endif
    
    
    set mb2 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb2.SetItemWidth(1, 1, 8) // "Combo name"
    call mb2.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb2.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb2.SetItemWidth(2, 1, 1)
    call mb2.SetItemWidth(2, 2, 1)
    call mb2.SetItemWidth(2, 3, 1)
    
    call mb2.SetItemWidth(3, 1, 8)
    call mb2.SetItemWidth(3, 2, 8)
    call mb2.SetItemWidth(3, 3, 8)
    
    call mb2.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb2.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb2.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb2.SetItem(3, 1, TEXT[LEVEL[1]])
    call mb2.SetItem(3, 2, I2S(BOUNTY[LEVEL[1]]))
    call mb2.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[1]]))
    
    if GetLocalPlayer() == Player(1) then
        call mb2.Show()
    endif
    
    set mb3 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb3.SetItemWidth(1, 1, 8) // "Combo name"
    call mb3.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb3.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb3.SetItemWidth(2, 1, 1)
    call mb3.SetItemWidth(2, 2, 1)
    call mb3.SetItemWidth(2, 3, 1)
    
    call mb3.SetItemWidth(3, 1, 8)
    call mb3.SetItemWidth(3, 2, 8)
    call mb3.SetItemWidth(3, 3, 8)
    
    call mb3.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb3.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb3.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb3.SetItem(3, 1, TEXT[LEVEL[2]])
    call mb3.SetItem(3, 2, I2S(BOUNTY[LEVEL[2]]))
    call mb3.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[2]]))
    
    if GetLocalPlayer() == Player(2) then
        call mb3.Show()
    endif
    
    set mb4 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb4.SetItemWidth(1, 1, 8) // "Combo name"
    call mb4.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb4.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb4.SetItemWidth(2, 1, 1)
    call mb4.SetItemWidth(2, 2, 1)
    call mb4.SetItemWidth(2, 3, 1)
    
    call mb4.SetItemWidth(3, 1, 8)
    call mb4.SetItemWidth(3, 2, 8)
    call mb4.SetItemWidth(3, 3, 8)
    
    call mb4.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb4.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb4.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb4.SetItem(3, 1, TEXT[LEVEL[3]])
    call mb4.SetItem(3, 2, I2S(BOUNTY[LEVEL[3]]))
    call mb4.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[3]]))
    
    if GetLocalPlayer() == Player(3) then
        call mb4.Show()
    endif
    
    set mb5 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb5.SetItemWidth(1, 1, 8) // "Combo name"
    call mb5.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb5.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb5.SetItemWidth(2, 1, 1)
    call mb5.SetItemWidth(2, 2, 1)
    call mb5.SetItemWidth(2, 3, 1)
    
    call mb5.SetItemWidth(3, 1, 8)
    call mb5.SetItemWidth(3, 2, 8)
    call mb5.SetItemWidth(3, 3, 8)
    
    call mb5.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb5.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb5.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb5.SetItem(3, 1, TEXT[LEVEL[4]])
    call mb5.SetItem(3, 2, I2S(BOUNTY[LEVEL[4]]))
    call mb5.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[4]]))
    
    if GetLocalPlayer() == Player(4) then
        call mb5.Show()
    endif
    
    set mb6 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb6.SetItemWidth(1, 1, 8) // "Combo name"
    call mb6.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb6.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb6.SetItemWidth(2, 1, 1)
    call mb6.SetItemWidth(2, 2, 1)
    call mb6.SetItemWidth(2, 3, 1)
    
    call mb6.SetItemWidth(3, 1, 8)
    call mb6.SetItemWidth(3, 2, 8)
    call mb6.SetItemWidth(3, 3, 8)
    
    call mb6.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb6.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb6.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb6.SetItem(3, 1, TEXT[LEVEL[5]])
    call mb6.SetItem(3, 2, I2S(BOUNTY[LEVEL[5]]))
    call mb6.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[5]]))
    
    if GetLocalPlayer() == Player(5) then
        call mb6.Show()
    endif
    
    set mb7 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb7.SetItemWidth(1, 1, 8) // "Combo name"
    call mb7.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb7.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb7.SetItemWidth(2, 1, 1)
    call mb7.SetItemWidth(2, 2, 1)
    call mb7.SetItemWidth(2, 3, 1)
    
    call mb7.SetItemWidth(3, 1, 8)
    call mb7.SetItemWidth(3, 2, 8)
    call mb7.SetItemWidth(3, 3, 8)
    
    call mb7.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb7.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb7.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb7.SetItem(3, 1, TEXT[LEVEL[6]])
    call mb7.SetItem(3, 2, I2S(BOUNTY[LEVEL[6]]))
    call mb7.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[6]]))
    
    if GetLocalPlayer() == Player(0) then
        call mb7.Show()
    endif
    
    set mb8 = Multiboard.Create(TITLE, ROWS, COLLUMNS, true, true, false, 25)
    call mb8.SetItemWidth(1, 1, 8) // "Combo name"
    call mb8.SetItemWidth(1, 2, 8) // "Bonus bounty"
    call mb8.SetItemWidth(1, 3, 8) // "Bonus damage"
    
    call mb8.SetItemWidth(2, 1, 1)
    call mb8.SetItemWidth(2, 2, 1)
    call mb8.SetItemWidth(2, 3, 1)
    
    call mb8.SetItemWidth(3, 1, 8)
    call mb8.SetItemWidth(3, 2, 8)
    call mb8.SetItemWidth(3, 3, 8)
    
    call mb8.SetItem(1, 1, "|cffffcc00Combo name|r")
    call mb8.SetItem(1, 2, "|cffffcc00Bonus bounty|r")
    call mb8.SetItem(1, 3, "|cffffcc00Bonus damage|r")
    
    call mb8.SetItem(3, 1, TEXT[LEVEL[7]])
    call mb8.SetItem(3, 2, I2S(BOUNTY[LEVEL[7]]))
    call mb8.SetItem(3, 3, R2S(MULTIPLIER[LEVEL[7]]))
    
    if GetLocalPlayer() == Player(7) then
        call mb8.Show()
    endif
    
    set mb[0] = mb1
    set mb[1] = mb2
    set mb[2] = mb3
    set mb[3] = mb4
    set mb[4] = mb5
    set mb[5] = mb6
    set mb[6] = mb7
    set mb[7] = mb8
endfunction

// explained above
private function MultiboardSafe takes nothing returns nothing
    call MultiboardCreation.execute()
    call ReleaseTimer(GetExpiredTimer())
endfunction

// Wooooooorks...
private function StoreData takes nothing returns nothing
    set a = 0
    loop
        exitwhen a > 7
        set LEVEL[a] = 0
        set a = a + 1
    endloop
    
    set TEXT[0] = "None"
    set TEXT[1] = "Dope!"
    set TEXT[2] = "Deadly!"
    set TEXT[3] = "Damn!"
    set TEXT[4] = "Cool!"
    set TEXT[5] = "Crazy!"
    set TEXT[6] = "Blast!"
    set TEXT[7] = "Boom!"
    set TEXT[8] = "Atomic!"
    set TEXT[9] = "All right"
    set TEXT[10] = "GOSU!"
    set TEXT[11] = "OMG!"
    set TEXT[12] = "Smokin' "
    set TEXT[13] = "Smokin' Style"
    set TEXT[14] = "Smokin' Sick Style"
    
    set BOUNTY[0] = 0
    set BOUNTY[1] = 10
    set BOUNTY[2] = 15 
    set BOUNTY[3] = 25
    set BOUNTY[4] = 30
    set BOUNTY[5] = 35
    set BOUNTY[6] = 45
    set BOUNTY[7] = 50
    set BOUNTY[8] = 60
    set BOUNTY[9] = 70
    set BOUNTY[10] = 75
    set BOUNTY[11] = 85
    set BOUNTY[12] = 95
    set BOUNTY[13] = 95
    set BOUNTY[14] = 100
    
    
    set MULTIPLIER[0] = 0.00
    set MULTIPLIER[1] = 0.05
    set MULTIPLIER[2] = 0.1
    set MULTIPLIER[3] = 0.1
    set MULTIPLIER[4] = 0.15
    set MULTIPLIER[5] = 0.15
    set MULTIPLIER[6] = 0.2
    set MULTIPLIER[7] = 0.25
    set MULTIPLIER[8] = 0.3
    set MULTIPLIER[9] = 0.35
    set MULTIPLIER[10] = 0.4
    set MULTIPLIER[11] = 0.45
    set MULTIPLIER[12] = 0.5
    set MULTIPLIER[13] = 0.55
    set MULTIPLIER[14] = 0.6
    
    set PLAYER_COLOR[0] = PLAYER_COLOR_RED
    set PLAYER_COLOR[1] = PLAYER_COLOR_BLUE
    set PLAYER_COLOR[2] = PLAYER_COLOR_CYAN
    set PLAYER_COLOR[3] = PLAYER_COLOR_PURPLE
    set PLAYER_COLOR[4] = PLAYER_COLOR_YELLOW
    set PLAYER_COLOR[5] = PLAYER_COLOR_ORANGE
    set PLAYER_COLOR[6] = PLAYER_COLOR_GREEN
    set PLAYER_COLOR[7] = PLAYER_COLOR_PINK
    call ReleaseTimer(GetExpiredTimer())
endfunction

// also works
private function OnAttack takes nothing returns boolean
    local unit cast = GetAttacker()
    local unit targ = GetTriggerUnit()
    local Data this
    if IsUnitType(cast, UNIT_TYPE_HERO) == true then//and IsUnitEnemy(targ, GetOwningPlayer(cast)) then
        set this = t[GetUnitIndex(cast)]
        if targ != this.targ then
            call this.destroy()
            set this = Data.create(cast)
            call this.wispSwap(targ)
        endif
        
        if not IsUnitInGroup(this.cast, gr) then
            call GroupAddUnit(gr, this.cast)
        endif
    endif
    set cast = null
    set targ = null
    return false
endfunction

private function OnDamage takes nothing returns boolean
    local unit cast = GetEventDamageSource()
    local unit targ = GetTriggerUnit()
    local real dmg = GetEventDamage()
    local Data this = t[GetUnitIndex(cast)]
    if this == 0 then
    else
        call DisableDamageDetect()
        call UnitDamageTarget(cast, targ, dmg + (dmg * MULTIPLIER[LEVEL[GetPlayerId(GetOwningPlayer(cast))]]), true, true, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
        call EnableDamageDetect()
        set TIME[this.cast] = 7
    endif
    set cast = null
    set targ = null
    return false
endfunction

private function Minus takes nothing returns nothing
    local unit cast = GetEnumUnit()
    local integer id 
    set TIME[cast] = TIME[cast] - 1
    if TIME[cast] <= 0 then
        set id = GetPlayerId(GetOwningPlayer(cast))
        if LEVEL[id] > 0 then
            set LEVEL[id] = LEVEL[id] - 1
        endif
        set TIME[cast] = 7
        // AAAAAAA ... :|
        call UpdateMultiboard.execute(cast, LEVEL[id])
    endif
    set cast = null
endfunction

private function SubstractTime takes nothing returns nothing
    call ForGroup(gr, function Minus)
endfunction

private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(trig, Condition(function OnAttack))

    call TimerStart(NewTimer(), 0.00, false, function StoreData)
    call TimerStart(NewTimer(), 0.5, false, function MultiboardSafe)
    call TimerStart(CreateTimer(), 1., true, function SubstractTime)
    
    call AddOnDamageFunc(Condition(function OnDamage))
endfunction

endlibrary



AMS system code:
JASS:

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//                  ADVANCED MULTIBOARD SYSTEM - v3.02 Beta                 //
//                              BY MAGENTIX                                 //
//                                                                          //
//                     Requires vJASS & Cohadar's ABC                       //
//                                                                          //
//==========================================================================//
//                                                                          //
//  1) CONFIGURATION:                                                       //
//  =================                                                       //
//    - Create a trigger, name doesn't matter                               //
//    - Go to Edit -> Convert to Custom Text                                //
//    - Copy-Paste this entire piece of code over the generated text        //
//                                                                          //
//  2) INSTRUCTIONS:                                                        //
//  ================                                                        //
//    For every multiboard action you want done, you MUST use the methods   //
//    described below. Other use of natives is at your own risk and may     //
//    cause the system to malfunction completely.                           //
//                                                                          //
//                                                                          //
//    Use .GetMultiboard() to get your multiboard.                          //
//                                                                          //
//    When setting colors, use a HEX code (6 letters).                      //
//    Giving a faulty color code will end up showing "FFFFFF" (White).      //
//                                                                          //
//    USE INTEGERS AS PLAYERS (Player 1 = 0, Player 2 = 1, etc.)            //
//                                                                          //
//  3) FUNCTION LIST:                                                       //
//  =================                                                       //
//                                                                          //
//    Display functions:                                                    //
//     .Create(title,rows,cols,showBoard,showValues,showIcons,width)        //
//     .Show()                                                              //
//     .Hide()                                                              //
//     .Fold()                                                              //
//     .Unfold()                                                            //
//     .SetItemWidth(row,col,width)                                         //
//                                                                          //
//                                                                          //
//    Retrieving functions:                                                 //
//     .GetItem(row,col) -> string                                          //
//     .GetItemPrefix(row,col) -> string                                    //
//     .GetItemSuffix(row,col) -> string                                    //
//     .GetItemColor(row,col) -> string                                     //
//     .GetItemPrefixColor(row,col) -> string                               //
//     .GetItemSuffixColor(row,col) -> string                               //
//     .GetTitle() -> string                                                //
//     .GetTitlePrefix() -> string                                          //
//     .GetTitleSuffix() -> string                                          //
//     .GetTitleColor() -> string                                           //
//     .GetTitlePrefixColor() -> string                                     //
//     .GetTitleSuffixColor() -> string                                     //
//                                                                          //
//     .GetValueState(row,col) -> boolean (show/hide)                       //
//     .GetIconState(row,col) -> boolean (show/hide)                        //
//     .GetIconPath(row,col) -> string                                      //
//                                                                          //
//     .GetColumnCount() -> integer                                         //
//     .GetRowCount() -> integer                                            //
//     .GetMultiboard() -> multiboard                                       //
//                                                                          //
//    Storing functions:                                                    //
//     .SetItem(row,col,value)                                              //
//     .SetItemPrefix(row,col,value)                                        //
//     .SetItemSuffix(row,col,value)                                        //
//     .SetItemColor(row,col,value)                                         //
//     .SetItemPrefixColor(row,col,value)                                   //
//     .SetItemSuffixColor(row,col,value)                                   //
//     .SetTitle(value)                                                     //
//     .SetTitlePrefix(value)                                               //
//     .SetTitleSuffix(value)                                               //
//     .SetTitleColor(value)                                                //
//     .SetTitlePrefixColor(value)                                          //
//     .SetTitleSuffixColor(value)                                          //
//                                                                          //
//     .SetIconPath(row,col,path)                                           //
//     .SetItemStyle(row,col,showValue,showIcon)                            //
//                                                                          //
//    Handy functions:                                                      //
//     .IncreaseItem(row,col,increment)                                     //
//     .SuspendItem(row,col,string)                                         //
//     .PrependItem(row,col,string)                                         //
//     .SuspendTitle(string)                                                //
//     .PrependTitle(string)                                                //
//                                                                          //
//    Sorting functions:                                                    //
//     .SortRowsOnce(start_row,end_row,sort_col,ascending)                  //
//     .SortRows(start_row,end_row,sort_col,interval,ascending)             //
//     .StopSorts()                                                         //
//     .SwapRows(row1,row2)                                                 //
//                                                                          //
//    Clock functions:                                                      //
//     .AddClock(asSuffix)                                                  //
//     .PauseClock()                                                        //
//     .ResumeClock()                                                       //
//     .ResetClock()                                                        //
//     .StopClock()                                                         //
//                                                                          //
//    Handy player functions:                                               //
//     .AddPlayers(startPlayer,amount,startRow,col,colorName)               //
//     .SetPlayerItem(player,col,value)                                     //
//     .GetPlayerItem(player,col) -> string                                 //
//     .SetPlayerRow(player,row)                                            //
//     .GetPlayerRow(player) -> integer                                     //
//                                                                          //
//                                                                          //
//     .Destroy()                                                           //
//                                                                          //
//==========================================================================//
//                                                                          //
//                      DO NOT EDIT BEYOND THIS POINT                       //
//                 PLEASE GIVE CREDIT WHEN USING THIS SYSTEM                //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

library AMS initializer Init requires TimerUtils, Table

globals
    private HandleTable ht
endglobals

//==============================================================================
//  TEXTMACROS
//==============================================================================

//! textmacro MBGetItem takes KEY, TYPE, VARNAME
method Get$KEY$ takes integer row, integer col returns $TYPE$
    return .GetItemData(((row-1)*.Cols)+col).$VARNAME$
endmethod
//! endtextmacro
//! textmacro MBGetTitle takes KEY, VARNAME
method Get$KEY$ takes nothing returns string
    return .$VARNAME$
endmethod
//! endtextmacro
//! textmacro MBSetItem takes KEY, VARNAME
method Set$KEY$ takes integer row, integer col, string value returns nothing
    set .GetItemData(((row-1)*.Cols)+col).$VARNAME$ = value
    call .UpdateItem(row,col)
endmethod
//! endtextmacro
//! textmacro MBSetTitle takes KEY, VARNAME
method Set$KEY$ takes string var returns nothing
    set .$VARNAME$ = var
    call .UpdateTitle()
endmethod
//! endtextmacro

//==============================================================================
//  STRUCTS
//==============================================================================

private struct ItemData
    string Value
    string Prefix
    string Suffix
    string Color
    string PrefixColor
    string SuffixColor
    string IconPath
    boolean ShowValue
    boolean ShowIcon
endstruct

private struct Item
    ItemData data
endstruct

private struct SortData
    integer SORT_COL
    integer START_ROW
    integer END_ROW
    boolean ASC
    Multiboard MB
endstruct

//==============================================================================
//  GLOBALS
//==============================================================================

globals
    private string array PlayerColors
    private Item array Items
    private Multiboard array Multiboards
    private integer MultiboardCounter = 0
endglobals

//==============================================================================
//  CALLBACKS
//==============================================================================

private function ClockCallback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local Multiboard mb = ht[t]
    local string s
    if (mb.STOP == false) then
        if (mb.seconds < 59) then
            set mb.seconds = mb.seconds + 1
        elseif (mb.minutes < 59) then
            set mb.seconds = 0
            set mb.minutes = mb.minutes + 1
        else
            set mb.seconds = 0
            set mb.minutes = 0
            set mb.hours = mb.hours + 1
        endif
        if (mb.hours < 10) then
            set s = "0"+I2S(mb.hours)+":"
        else
            set s = I2S(mb.hours)+":"
        endif
        if (mb.minutes < 10) then
            set s = s+"0"+I2S(mb.minutes)+":"
        else
            set s = s+I2S(mb.minutes)+":"
        endif
        if (mb.seconds < 10) then
            set s = s+"0"+I2S(mb.seconds)
        else
            set s = s+I2S(mb.seconds)
        endif
        if (mb.asSuffix) then
            call mb.SetTitleSuffix("- "+s)
        else
            call mb.SetTitle(s)
        endif
    else
        call ReleaseTimer(mb.ClockTimer)
    endif
    set s = null
    set t = null
endfunction
private function SortRowsCallback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local SortData dat = ht[t]
    if (dat.MB.SortStop == false) then
        call dat.MB.SortRowsOnce(dat.START_ROW, dat.END_ROW, dat.SORT_COL, dat.ASC)
    else
        call ht.flush(t)
        call dat.destroy()
        call ReleaseTimer(t)
        set dat.MB.SortCount = dat.MB.SortCount - 1
        if (dat.MB.SortCount == 0) then
            set dat.MB.SortStop = false
        endif
    endif
    set t = null
endfunction

//==============================================================================
//  Multiboard STRUCT
//==============================================================================

struct Multiboard
    // Array Initial Value
    integer ArrayStart = 0
    integer MultiboardNR = 1
    // Multiboard Values
    private multiboard MB
    private integer Rows
    private integer Cols
    private integer array PlayerRow[11]
    // Title Values
    private string Value
    private string Prefix
    private string Suffix
    private string Color
    private string PrefixColor
    private string SuffixColor
    // Clock Values
    timer ClockTimer
    integer seconds = 0
    integer minutes = 0
    integer hours = 0
    boolean asSuffix
    boolean STOP
    // Sort Values
    integer SortCount = 0
    boolean SortStop = false
    static method Create takes string title, integer rows, integer cols, boolean showBoard, boolean showValues, boolean showIcons, integer width returns Multiboard
        local Multiboard mb = Multiboard.allocate()
        local integer i = 1
        
        if (MultiboardCounter > 0) then
            set mb.ArrayStart = Multiboards[MultiboardCounter].ArrayStart + (Multiboards[MultiboardCounter].Rows * Multiboards[MultiboardCounter].Cols)
            set mb.MultiboardNR = MultiboardCounter + 1
        endif
        set MultiboardCounter = MultiboardCounter + 1
        set Multiboards[MultiboardCounter] = mb
        
        set mb.MB = CreateMultiboard()
        set mb.Rows = rows
        set mb.Cols = cols
        set mb.Value = title
        
        call MultiboardSetRowCount(mb.MB, mb.Rows)
        call MultiboardSetColumnCount(mb.MB, mb.Cols)
        call MultiboardSetTitleText(mb.MB, title)
        call MultiboardSetItemsStyle(mb.MB, showValues, showIcons)
        
        if (width <= 0) then
            set width = 25
        endif
        
        call MultiboardSetItemsWidth(mb.MB, (width/cols)/100.00)
        call MultiboardDisplay(mb.MB, showBoard)
        
        loop
            exitwhen (i > mb.Rows * mb.Cols)
            set Items[mb.ArrayStart+i] = Item.create()
            set Items[mb.ArrayStart+i].data = ItemData.create()
            set Items[mb.ArrayStart+i].data.ShowIcon = showIcons
            set Items[mb.ArrayStart+i].data.ShowValue = showValues
            set Items[mb.ArrayStart+i].data.IconPath = "UI\\Widgets\\EscMenu\\Human\\observer-icon.blp"
            set i = i + 1
        endloop
        
        return mb
    endmethod
    
    
    private method GetItemData takes integer ItemNR returns ItemData
        return Items[.ArrayStart+ItemNR].data
    endmethod
    
    
    method ShowItem takes integer row, integer col returns nothing
        local ItemData I = .GetItemData(((row-1)*.Cols)+col)
        call BJDebugMsg(I.Value)
    endmethod

    //! runtextmacro MBGetItem("Item","string","Value")
    //! runtextmacro MBGetItem("ItemPrefix","string","Prefix")
    //! runtextmacro MBGetItem("ItemSuffix","string","Suffix")
    //! runtextmacro MBGetItem("ItemColor","string","Color")
    //! runtextmacro MBGetItem("ItemPrefixColor","string","PrefixColor")
    //! runtextmacro MBGetItem("ItemSuffixColor","string","SuffixColor")
    //! runtextmacro MBGetItem("ValueState","boolean","ShowValue")
    //! runtextmacro MBGetItem("IconState","boolean","ShowIcon")
    //! runtextmacro MBGetItem("IconPath","string","IconPath")
    //! runtextmacro MBGetTitle("Title","Value")
    //! runtextmacro MBGetTitle("TitlePrefix","Prefix")
    //! runtextmacro MBGetTitle("TitleSuffix","Suffix")
    //! runtextmacro MBGetTitle("TitleColor","Color")
    //! runtextmacro MBGetTitle("TitlePrefixColor","PrefixColor")
    //! runtextmacro MBGetTitle("TitleSuffixColor","SuffixColor")
    
    method GetPlayerRow takes integer p returns integer
        return .PlayerRow[p]
    endmethod
    
    method GetColumnCount takes nothing returns integer
        return .Cols
    endmethod
    
    method GetRowCount takes nothing returns integer
        return .Rows
    endmethod
    
    method GetMultiboard takes nothing returns multiboard
        return .MB
    endmethod
    
    method Show takes nothing returns nothing
        call MultiboardDisplay(.MB, true)
    endmethod
    
    method Hide takes nothing returns nothing
        call MultiboardDisplay(.MB, false)
    endmethod
    
    method Fold takes nothing returns nothing
        call MultiboardMinimize(.MB, true)
    endmethod
    
    method Unfold takes nothing returns nothing
        call MultiboardMinimize(.MB, false)
    endmethod
    
    method SetItemWidth takes integer row, integer col, real width returns nothing
        local multiboarditem mbi = MultiboardGetItem(.MB,row-1,col-1)
        
        call MultiboardSetItemWidth(mbi, width/100.00)
        call MultiboardReleaseItem(mbi)
        
        set mbi = null
    endmethod
    
    
    private method UpdateItem takes integer row, integer col returns nothing
        local string full = ""
        local multiboarditem mbi
        local ItemData I = .GetItemData(((row-1)*.Cols)+col)
        
        if (I.Prefix != null) then
            if (I.PrefixColor != null and StringLength(I.PrefixColor) == 6) then
                set full = "|cFF"+I.PrefixColor+I.Prefix+"|r "
            else
                set full = "|cFFFFFFFF"+I.Prefix+"|r "
            endif
        endif
        if (I.Color != null and StringLength(I.Color) == 6) then
            set full = full+"|cFF"+I.Color+I.Value+"|r"
        else
            set full = full+"|cFFFFFFFF"+I.Value+"|r"
        endif
        if (I.Suffix != null) then
            if (I.SuffixColor != null and StringLength(I.SuffixColor) == 6) then
                set full = full+" |cFF"+I.SuffixColor+I.Suffix+"|r"
            else
                set full = full+" |cFFFFFFFF"+I.Suffix+"|r"
            endif
        endif
        
        set mbi = MultiboardGetItem(.MB,row-1,col-1)
        call MultiboardSetItemValue(mbi, full)
        call MultiboardReleaseItem(mbi)
        
        set full = null
        set mbi = null
    endmethod
    
    private method UpdateTitle takes nothing returns nothing
        local string full = ""
        
        if (.Prefix != null) then
            if (.PrefixColor != null and StringLength(.PrefixColor) == 6) then
                set full = "|cFF"+.PrefixColor+.Prefix+"|r "
            else
                set full = "|cFFFFCC00"+.Prefix+"|r "
            endif
        endif
        if (.Color != null and StringLength(.Color) == 6) then
            set full = full+"|cFF"+.Color+.Value+"|r"
        else
            set full = full+"|cFFFFCC00"+.Value+"|r"
        endif
        if (.Suffix != null) then
            if (.SuffixColor != null and StringLength(.SuffixColor) == 6) then
                set full = full+" |cFF"+.SuffixColor+.Suffix+"|r"
            else
                set full = full+" |cFFFFCC00"+.Suffix+"|r"
            endif
        endif
        
        call MultiboardSetTitleText(.MB, full)
        set full = null
    endmethod
    
    
    //! runtextmacro MBSetItem("Item","Value")
    //! runtextmacro MBSetItem("ItemPrefix","Prefix")
    //! runtextmacro MBSetItem("ItemSuffix","Suffix")
    //! runtextmacro MBSetItem("ItemColor","Color")
    //! runtextmacro MBSetItem("ItemPrefixColor","PrefixColor")
    //! runtextmacro MBSetItem("ItemSuffixColor","SuffixColor")
    //! runtextmacro MBSetTitle("Title","Value")
    //! runtextmacro MBSetTitle("TitlePrefix","Prefix")
    //! runtextmacro MBSetTitle("TitleSuffix","Suffix")
    //! runtextmacro MBSetTitle("TitleColor","Color")
    //! runtextmacro MBSetTitle("TitlePrefixColor","PrefixColor")
    //! runtextmacro MBSetTitle("TitleSuffixColor","SuffixColor")
    
    method SetPlayerRow takes integer p, integer row returns nothing
    set .PlayerRow[p] = row
    endmethod
    
    method SetItemStyle takes integer row, integer col, boolean showValue, boolean showIcon returns nothing
        local multiboarditem mbi
        
        set .GetItemData(((row-1)*.Cols)+col).ShowValue = showValue
        set .GetItemData(((row-1)*.Cols)+col).ShowIcon = showIcon
        set mbi = MultiboardGetItem(.MB,row-1,col-1)
        call MultiboardSetItemStyle(mbi, showValue, showIcon)
        call MultiboardReleaseItem(mbi)
        
        set mbi = null
    endmethod
    
    method SetIconPath takes integer row, integer col, string path returns nothing
        local multiboarditem mbi
        
        set .GetItemData(((row-1)*.Cols)+col).IconPath = path
        set mbi = MultiboardGetItem(.MB,row-1,col-1)
        call MultiboardSetItemIcon(mbi, path)
        call MultiboardReleaseItem(mbi)
        
        set mbi = null
    endmethod

    method IncreaseItem takes integer row, integer col, integer increment returns nothing
        call .SetItem(row,col,I2S(S2I(.GetItem(row,col))+increment))
    endmethod
    
    method SuspendItem takes integer row, integer col, string Suffix returns nothing
        call .SetItem(row,col,.GetItem(row,col)+Suffix)
    endmethod
    
    method PrependItem takes integer row, integer col, string Prefix returns nothing
        call .SetItem(row,col,Prefix+.GetItem(row,col))
    endmethod
    
    method SuspendTitle takes string Suffix returns nothing
        call .SetTitle(.GetTitle()+Suffix)
    endmethod
    
    method PrependTitle takes string Prefix returns nothing
        call .SetTitle(Prefix+.GetTitle())
    endmethod
    
    method GetPlayerItem takes integer p, integer col returns string
        return .GetItem(.GetPlayerRow(p),col)
    endmethod
    
    method SetPlayerItem takes integer p, integer col, string value returns nothing
        call .SetItem(.GetPlayerRow(p),col,value)
    endmethod
    
    method AddPlayers takes integer startPlayer, integer amount, integer row, integer col, boolean colorName returns nothing
        local integer i = 0
        
        loop
        exitwhen i == amount
            call .SetItem(row+i,col,GetPlayerName(Player(startPlayer+i)))
            set .PlayerRow[startPlayer+i] = row+i
            if (colorName) then
                call .SetItemColor(row+i,col,PlayerColors[startPlayer+i])
            endif
            set i = i + 1
        endloop
    endmethod
    
    
    method AddClock takes boolean asSuffix returns nothing
        if (.ClockTimer != null) then
            call BJDebugMsg("Error: This multiboard already has a clock.")
        else
            set .ClockTimer = CreateTimer()
            set .asSuffix = asSuffix
            set .STOP = false
            set ht[.ClockTimer] = this
            call TimerStart(.ClockTimer,1.00,true,function ClockCallback)
        endif
    endmethod
    
    method PauseClock takes nothing returns nothing
        set .STOP = true
    endmethod
    
    method ResumeClock takes nothing returns nothing
        set .STOP = false
        call TimerStart(.ClockTimer,1.00,true,function ClockCallback)
    endmethod
    
    method ResetClock takes nothing returns nothing
        set .seconds = 0
        set .minutes = 0
        set .hours = 0
    endmethod
    
    method StopClock takes nothing returns nothing
        set .seconds = 0
        set .minutes = 0
        set .hours = 0
        call ht.flush(.ClockTimer)
        call ReleaseTimer(.ClockTimer)
        set .ClockTimer = null
        if (.asSuffix) then
            call .SetTitleSuffix("")
        else
            call .SetTitle("")
        endif
    endmethod
    
    
    method SwapRows takes integer row1, integer row2 returns nothing
        local integer i = 0
        local integer col = 1
        local ItemData I
        
        loop
        exitwhen i > 11
            if (.PlayerRow<i> == row1) then
                set .PlayerRow<i> = row2
            elseif (.PlayerRow<i> == row2) then
                set .PlayerRow<i> = row1
            endif
            set i = i + 1
        endloop
        
        loop
        exitwhen col &gt; .Cols
            set I = .GetItemData(((row1-1)*.Cols)+col)
            set Items[.ArrayStart+((row1-1)*.Cols)+col].data = .GetItemData(((row2-1)*.Cols)+col)
            set Items[.ArrayStart+((row2-1)*.Cols)+col].data = I
            call .UpdateItem(row1,col)
            call .UpdateItem(row2,col)
            set col = col + 1
        endloop
    endmethod
    
    method SortRowsOnce takes integer START_ROW, integer END_ROW, integer SORT_COL, boolean ASC returns nothing
        local integer k = END_ROW - 1
        local integer l
        local integer lv
        local integer Item1
        local integer Item2
        
        if (START_ROW &gt; END_ROW) then
            call BJDebugMsg(&quot;Error: START_ROW must be less than END_ROW when calling a RowSort().&quot;)
        else
            loop
            exitwhen (k &lt; START_ROW)
                set l = START_ROW
                set lv = START_ROW
                loop
                exitwhen (l &gt; k)                  
                    set Item1 = S2I(.GetItemData(((l-1)*.Cols)+SORT_COL).Value)
                    set Item2 = S2I(.GetItemData((l*.Cols)+SORT_COL).Value)
                    if ((Item1 &gt; Item2 and ASC) or (Item1 &lt; Item2 and not ASC)) then
                        call .SwapRows(l,l+1)
                        set lv = l 
                    endif
                    set l = l + 1
                endloop
            set k = lv - 1
            endloop
        endif
    endmethod
    

    method StopSorts takes nothing returns nothing
        set .SortStop = true
    endmethod
    
    method SortRows takes integer START_ROW, integer END_ROW, integer SORT_COL, real interval, boolean ASC returns nothing
        local timer t = CreateTimer()
        local integer i = 0
        local SortData dat = SortData.create()
        
        set dat.SORT_COL = SORT_COL
        set dat.START_ROW = START_ROW
        set dat.END_ROW = END_ROW
        set dat.ASC = ASC
        set dat.MB = this
        set ht[t] = dat
        call TimerStart(t,interval,true,function SortRowsCallback)
        set .SortCount = .SortCount + 1
        
        set t = null
    endmethod
    
    
    method onDestroy takes nothing returns nothing
        local integer i = 1
        
        loop
        exitwhen (i &gt; .Rows * .Cols)
            call Items[.ArrayStart+i].data.destroy()
            call Items[.ArrayStart+i].destroy()
            set i = i + 1
        endloop
        set i = 1
        
        loop
        exitwhen i &gt; Multiboards[MultiboardCounter].ArrayStart + (Multiboards[MultiboardCounter].Cols * Multiboards[MultiboardCounter].Rows) - (.ArrayStart + (.Cols * .Rows))
            set Items[.ArrayStart+i] = Items[.ArrayStart+i+(.Cols*.Rows)]
            set i = i + 1
        endloop
        set i = 1
        
        loop
        exitwhen i &gt; MultiboardCounter - .MultiboardNR
            set Multiboards[.MultiboardNR+i-1] = Multiboards[.MultiboardNR+i]
            set Multiboards[.MultiboardNR+i-1].MultiboardNR = Multiboards[.MultiboardNR+i-1].MultiboardNR - 1
            if (Multiboards[.MultiboardNR+i-1].MultiboardNR == 1) then
                set Multiboards[.MultiboardNR+i-1].ArrayStart = 0
            else
                set Multiboards[.MultiboardNR+i-1].ArrayStart = Multiboards[.MultiboardNR+i-2].ArrayStart + (Multiboards[.MultiboardNR+i-2].Cols * Multiboards[.MultiboardNR+i-2].Rows)
            endif
            set i = i + 1
        endloop

        set MultiboardCounter = MultiboardCounter - 1
        
        call .StopSorts()
        call DestroyMultiboard(.MB)
    endmethod
endstruct

//==============================================================================
//  INITIALIZER
//==============================================================================

private function Init takes nothing returns nothing
    set PlayerColors[0] = &quot;FF0303&quot;
    set PlayerColors[1] = &quot;0042FF&quot;
    set PlayerColors[2] = &quot;1CB619&quot;
    set PlayerColors[3] = &quot;540081&quot;
    set PlayerColors[4] = &quot;FFFF01&quot;
    set PlayerColors[5] = &quot;FE8A0E&quot;
    set PlayerColors[6] = &quot;20C000&quot;
    set PlayerColors[7] = &quot;E55BB0&quot;
    set PlayerColors[8] = &quot;959697&quot;
    set PlayerColors[9] = &quot;7EBFF1&quot;
    set PlayerColors[10] = &quot;106246&quot;
    set PlayerColors[11] = &quot;4E2A04&quot;
    
    set ht = HandleTable.create()
endfunction
endlibrary
</i></i></i></i>
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    So what it really is me trying to implement some kind of better site navigation not change the whole theme of the site
  • Varine Varine:
    How can you tell the difference between real traffic and indexing or AI generation bots?
  • The Helper The Helper:
    The bots will show up as users online in the forum software but they do not show up in my stats tracking. I am sure there are bots in the stats but the way alot of the bots treat the site do not show up on the stats
  • Varine Varine:
    I want to build a filtration system for my 3d printer, and that shit is so much more complicated than I thought it would be
  • Varine Varine:
    Apparently ABS emits styrene particulates which can be like .2 micrometers, which idk if the VOC detectors I have can even catch that
  • Varine Varine:
    Anyway I need to get some of those sensors and two air pressure sensors installed before an after the filters, which I need to figure out how to calculate the necessary pressure for and I have yet to find anything that tells me how to actually do that, just the cfm ratings
  • Varine Varine:
    And then I have to set up an arduino board to read those sensors, which I also don't know very much about but I have a whole bunch of crash course things for that
  • Varine Varine:
    These sensors are also a lot more than I thought they would be. Like 5 to 10 each, idk why but I assumed they would be like 2 dollars
  • Varine Varine:
    Another issue I'm learning is that a lot of the air quality sensors don't work at very high ambient temperatures. I'm planning on heating this enclosure to like 60C or so, and that's the upper limit of their functionality
  • Varine Varine:
    Although I don't know if I need to actually actively heat it or just let the plate and hotend bring the ambient temp to whatever it will, but even then I need to figure out an exfiltration for hot air. I think I kind of know what to do but it's still fucking confusing
  • The Helper The Helper:
    Maybe you could find some of that information from AC tech - like how they detect freon and such
  • Varine Varine:
    That's mostly what I've been looking at
  • Varine Varine:
    I don't think I'm dealing with quite the same pressures though, at the very least its a significantly smaller system. For the time being I'm just going to put together a quick scrubby box though and hope it works good enough to not make my house toxic
  • Varine Varine:
    I mean I don't use this enough to pose any significant danger I don't think, but I would still rather not be throwing styrene all over the air
  • The Helper The Helper:
    New dessert added to recipes Southern Pecan Praline Cake https://www.thehelper.net/threads/recipe-southern-pecan-praline-cake.193555/
  • The Helper The Helper:
    Another bot invasion 493 members online most of them bots that do not show up on stats
  • Varine Varine:
    I'm looking at a solid 378 guests, but 3 members. Of which two are me and VSNES. The third is unlisted, which makes me think its a ghost.
    +1
  • The Helper The Helper:
    Some members choose invisibility mode
    +1
  • The Helper The Helper:
    I bitch about Xenforo sometimes but it really is full featured you just have to really know what you are doing to get the most out of it.
  • The Helper The Helper:
    It is just not easy to fix styles and customize but it definitely can be done
  • The Helper The Helper:
    I do know this - xenforo dropped the ball by not keeping the vbulletin reputation comments as a feature. The loss of the Reputation comments data when we switched to Xenforo really was the death knell for the site when it came to all the users that left. I know I missed it so much and I got way less interested in the site when that feature was gone and I run the site.
  • Blackveiled Blackveiled:
    People love rep, lol
    +1
  • The Helper The Helper:
    The recipe today is Sloppy Joe Casserole - one of my faves LOL https://www.thehelper.net/threads/sloppy-joe-casserole-with-manwich.193585/

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top