System AMS - Advanced Multiboard System

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
This system was made for creating multiboards easily with little knowledge of how to call JASS functions.
The mods that were/are being developed for this system makes creating multiboard a piece of cake.

Requires:

Credits:
  • Cohadar: ABC Struct Attachement

Advantages:
  • No variables needed for values
  • Can sort Ascending/Descending by column
  • Can have a clock in it's header
  • Can sort periodicly
  • Has possibility to add mods for ease of use


Main 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 ABC

//==============================================================================
//  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 = GetTimerStructA(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 PauseTimer(mb.ClockTimer)
        call DestroyTimer(mb.ClockTimer)
    endif
    set s = null
    set t = null
endfunction
private function SortRowsCallback takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local SortData dat = GetTimerStructA(t)
    if (dat.MB.SortStop == false) then
        call dat.MB.SortRowsOnce(dat.START_ROW, dat.END_ROW, dat.SORT_COL, dat.ASC)
    else
        call ClearTimerStructA(t)
        call dat.destroy()
        call PauseTimer(t)
        call DestroyTimer(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
            call SetTimerStructA(.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 ClearTimerStructA(.ClockTimer)
        call PauseTimer(.ClockTimer)
        call DestroyTimer(.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
        call SetTimerStructA(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;
endfunction
endlibrary</i></i></i></i>



Make sure to check the mods for this system:


amsTS: Team Scores
  • Makes a scoreboard for one or more teams
  • Very adjustable in size, team amount and colors
  • Has an easy function to set, increase or decrease a player's score
  • Allows for non-score entries as well (SetTagValue)
  • Creates a nice scoreboard at the start of a game
  • Easy to implement

Specific limitations:
  • Teams have to be equal

When to use this mod:
If you have a map where you want to simply keep track of kills, lives, deaths, etc of several equal teams and their players, this is your mod.
It allows for increasing or decreasing the scores for each player on the board, as does it allow for teams to have their name displayed above the team's players.

Code:
JASS:
//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//                          TEAM SCORES - v1.02                             //
//                    A MAGENTIX&#039; AMS MOD BY MAGENTIX                       //
//                                                                          //
//              Requires vJASS, Magentix&#039; AMS &amp; Cohadar&#039;s ABC               //
//                                                                          //
//==========================================================================//
//                                                                          //
//  1) CONFIGURATION:                                                       //
//  =================                                                       //
//    - Create a trigger, name doesn&#039;t matter                               //
//    - Go to Edit -&gt; Convert to Custom Text                                //
//    - Copy-Paste this entire piece of code over the generated text        //
//                                                                          //
//                                                                          //
//  2) INSTRUCTIONS:                                                        //
//  ================                                                        //
//    Configure the variables at the bottom of these instructions.          //
//    ALWAYS start arrays from 0 (arrays are: TEAM_NAME, TEAM_COLOR, etc.)  //
//                                                                          //
//    This mod will automaticly create an AMS for you by the name of:       //
//    --&gt; amsTS &lt;--                                                         //
//    You can use this reference name to manipulate the Multiboard further, //
//    using AMS functions, should you feel the need to.                     //
//                                                                          //
//                                                                          //
//  3) FUNCTION LIST:                                                       //
//  =================                                                       //
//    Only a few functions:                                                 //
//     amsTS_IncreaseScore(Player,Tag,Amount)                               //
//     amsTS_SetScore(Player,Tag,Amount)                                    //
//     amsTS_SetTagValue(Player,Tag,Value) -&gt; Value = A STRING!             //
//                                                                          //
//     amsTS_FetchScore(Player,Tag) // CURRENTLY JASS ONLY!                 //
//                                                                          //
//     Remember: 0 = player 1, 1 = player 2, etc.                           //
//               You may use a negative Amount to decrease score            //
//               What a tag is will become clear while configuring TS       //
//                                                                          //
//                                                                          //
//  4) DETAILED GUIDE FOR THE NON-JASS PEOPLE:                              //
//  ==========================================                              //
//    Go to http://www.thehelper.net/forums/showthread.php?p=591918         //
//    to find the latest version of AMS and ABC                             //
//                                                                          //
//    Create 3 Triggers: AMS, ABC and amsTS and for all three, choose:      //
//    Edit -&gt; Convert to custom text                                        //
//                                                                          //
//    Delete everything that&#039;s generated and paste the 3 systems into the   //
//    correct triggers.                                                     //
//                                                                          //
//    Configure the variables below                                         //
//                                                                          //
//    To increase a player&#039;s score (deaths, kills, whatever..) in GUI       //
//    (= General User Interface), use the Custom Script action:             //
//                                                                          //
//    Custom script: call amsTS_IncreaseScore(x,y,z)                        //
//      Where x = the player number                                         //
//            y = the tag number                                            //
//            z = the amount (may be negative)                              //
//                                                                          //
//      Remember: player and tag starts counting from 0!                    //
//                same goes for the other &quot;Set&quot;-functions                   //
//                a string requires &quot; &quot; around itself                       //
//                                                                          //
//                                                                          //
//==========================================================================//
//                                                                          //
//                 PLEASE GIVE CREDIT WHEN USING THIS SYSTEM                //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

//! textmacro AMS_TeamScores_Configuration
//==============================================================================
//  CONFIGURE YOUR SCOREBOARD HERE
//==============================================================================
//
// First of all: choose the lay-out of your scoreboard.
    set ENABLE_TAG_TITLES       = true
    set ENABLE_PLAYER_COLORS    = false
    set ENABLE_TEAM_NAMES       = true
    set ENABLE_TEAM_COLORS      = false
    set ENABLE_TEAM_SORTING     = false
    //COMING SOON: set ENABLE_TEAM_SCORES    = false
    //COMING SOON: set ENABLE_DEBUG_LINE     = false
//
// NEW: Function that automaticly adjusts a tag to show a resource
    set ENABLE_RESOURCE_GOLD    = true
    set ENABLE_RESOURCE_LUMBER  = true
//
// EXPERIMENTAL: Function that automaticly adjusts colum widths to center scores
    set ENABLE_AUTO_LAYOUT      = false
//
//
// Set the title for the scoreboard
    set TITLE                   = &quot;Example for Pyramidal Defense&quot;
//
//
//
// Set the amount of teams and players for each team
// Team 1 starts with player red and subsequent teams start where the previous team ended
// While defining the team names and colors, make sure you start counting from 0
    set TEAM_AMOUNT             = 2
    set PLAYERS_PER_TEAM        = 5
    set TEAM_NAME[0]            = &quot;Pyramid 1:&quot;
    set TEAM_NAME[1]            = &quot;Pyramid 2:&quot;
    set TEAM_COLOR[0]           = &quot;FF0000&quot;
    set TEAM_COLOR[1]           = &quot;00FF00&quot;
//   
// 
//
// Set the amount of scores you want to keep track of for every player
// While defining the tags, make sure you start counting from 0
    set TAGS_PER_PLAYER         = 2
    set TAG[0]                  = &quot;[Gold]&quot;
    set TAG_DEFAULT_VALUE[0]    = &quot;0&quot;
    set TAG[1]                  = &quot;[Lumber]&quot;
    set TAG_DEFAULT_VALUE[1]    = &quot;0&quot;
//
// When setting ENABLE_RESOURCE_GOLD or ENABLE_RESOURCE_LUMBER to true, these settings will become active
// Assigning them to the same tag will only make lumber show
    set TAG_FOR_GOLD            = 0
    set TAG_FOR_LUMBER          = 1
//    
//
//
// Set whether you want the scoreboard to get sorted by kills, deaths, etc...
// When setting ENABLE_TEAM_SORTING to true, these settings will become active
    set SORT_TEAMS_BY_TAG       = 1
    set SORT_ASCENDING          = false
//
//
//==============================================================================
//  DO NOT EDIT BEYOND THIS POINT
//==============================================================================
//! endtextmacro

library amsTS initializer Init requires AMS

globals
    Multiboard amsTS
    
    private string TITLE
    private string array TAG
    private string array TAG_DEFAULT_VALUE
    private string array TEAM_NAME
    private string array TEAM_COLOR
    private integer TEAM_AMOUNT
    private integer PLAYERS_PER_TEAM
    private integer TAGS_PER_PLAYER
    private integer TAG_FOR_GOLD
    private integer TAG_FOR_LUMBER
    private integer SORT_TEAMS_BY_TAG
    private boolean SORT_ASCENDING
    
    private boolean ENABLE_TAG_TITLES
    private boolean ENABLE_PLAYER_COLORS
    private boolean ENABLE_TEAM_SORTING
    private boolean ENABLE_TEAM_NAMES
    private boolean ENABLE_TEAM_COLORS
    private boolean ENABLE_TEAM_SCORES
    private boolean ENABLE_DEBUG_LINE
    private boolean ENABLE_AUTO_LAYOUT
    private boolean ENABLE_RESOURCE_GOLD
    private boolean ENABLE_RESOURCE_LUMBER
endglobals

private function Actions takes nothing returns nothing
    local integer rows = 0
    local integer max = 0
    local integer first_max = 0
    local integer i = 0
    local integer j
    
    // Calculate the total rows
    if (ENABLE_TEAM_NAMES) then
        set rows = rows + TEAM_AMOUNT
    endif    
    if (ENABLE_TAG_TITLES) then
        set rows = rows + 2
    endif    
    set rows = rows + (TEAM_AMOUNT * PLAYERS_PER_TEAM) + (TEAM_AMOUNT-1)
    
    
    // Create the AMS Multiboard
    set amsTS = Multiboard.Create(TITLE,rows,TAGS_PER_PLAYER+1,true,true,false,5)
    
    
    // Set the tag title row
    if (ENABLE_TAG_TITLES) then
        set i = 1
        loop
        exitwhen i &gt; TAGS_PER_PLAYER
            call amsTS.SetItem(1,i+1,TAG[i-1])
            call amsTS.SetItemColor(1,i+1,&quot;FFCC00&quot;)
            set i = i + 1
        endloop
        set i = 0
    endif
    
    
    // Set the team titles and players
    set j = 1
    if (ENABLE_TAG_TITLES) then
        set j = 3
    endif
    loop
    exitwhen i == TEAM_AMOUNT
        if (ENABLE_TEAM_NAMES) then
            call amsTS.SetItem(j,1,TEAM_NAME<i>)
            if (ENABLE_TEAM_COLORS) then
                call amsTS.SetItemColor(j,1,TEAM_COLOR<i>)
            else
                call amsTS.SetItemColor(j,1,&quot;FFCC00&quot;)
            endif
            set j = j + 1
        endif
        
        call amsTS.AddPlayers(0+(PLAYERS_PER_TEAM * i),PLAYERS_PER_TEAM,j,1,ENABLE_PLAYER_COLORS)
        set j = j + PLAYERS_PER_TEAM + 1
        set i = i + 1
    endloop
    set i = 0
    
    
    // Fill in the default tag values
    loop
    exitwhen i == (PLAYERS_PER_TEAM * TEAM_AMOUNT)
        set j = 1
    
        loop
        exitwhen j &gt; TAGS_PER_PLAYER
            call amsTS.SetPlayerItem(i,j+1,TAG_DEFAULT_VALUE[j-1])
            set j = j + 1
        endloop
        
        set i = i + 1
    endloop
    
    
    // Sort teams if enabled
    if (ENABLE_TEAM_SORTING) then
        set j = 0
        set i = 0
        
        if (ENABLE_TAG_TITLES) then
            set j = 2
        endif
        
        loop
        exitwhen i == TEAM_AMOUNT
            if (ENABLE_TEAM_NAMES) then
                set j = j + 1
            endif
            call amsTS.SortRows(j,j+PLAYERS_PER_TEAM-1,2+SORT_TEAMS_BY_TAG,0.10,SORT_ASCENDING)
            set j = j + PLAYERS_PER_TEAM + 1

            set i = i + 1
        endloop
    endif
    set j = 1
    
    
    // Automaticly define the width of every column
    if (ENABLE_AUTO_LAYOUT) then
    
        loop
        exitwhen j &gt; 1 + TAGS_PER_PLAYER
            set i = 1 
            loop
            exitwhen i &gt; rows
                if (StringLength(amsTS.GetItem(i,j)) &gt; max) then
                    set max = StringLength(amsTS.GetItem(i,j))
                endif
                set i = i + 1
            endloop
            set i = 1
            
            if (j == 1) then
                loop
                exitwhen i &gt; rows
                    call amsTS.SetItemWidth(i,j,(max/1.80)+3.00)
                    set i = i + 1
                endloop
                set first_max = max
                set max = 0
            endif
            
            set j = j + 1
        endloop
        set j = 2
        
        loop
        exitwhen j &gt; 1 + TAGS_PER_PLAYER
            set i = 1
            loop
            exitwhen i &gt; rows
                if (j &lt; TAGS_PER_PLAYER + 1) then
                    call amsTS.SetItemWidth(i,j,(max/1.80)+0.50)
                else
                    call amsTS.SetItemWidth(i,j,max/1.80)
                endif
                if (i &gt; 2 and ENABLE_TAG_TITLES and j == 2) then
                    call amsTS.SetItemWidth(i,1,(first_max/1.80) + 3.00 + ((max/1.80)/2))
                endif
                set i = i + 1
            endloop
            set j = j + 1
        endloop
        
    else
    
        loop
        exitwhen j &gt; 1 + TAGS_PER_PLAYER
            set i = 1
             
            loop
            exitwhen i &gt; rows
                if (StringLength(amsTS.GetItem(i,j)) &gt; max) then
                    set max = StringLength(amsTS.GetItem(i,j))
                endif
                set i = i + 1
            endloop
            set i = 1
            
            loop
            exitwhen i &gt; rows
                if (j == 1) then
                    call amsTS.SetItemWidth(i,j,(max/1.80)+3.00)
                else
                    if (j &lt; TAGS_PER_PLAYER + 1) then
                        call amsTS.SetItemWidth(i,j,(max/1.80)+1.00)
                    else
                        call amsTS.SetItemWidth(i,j,max/1.80)
                    endif
                endif
                set i = i + 1
            endloop
            
            set max = 0
            set j = j + 1
        endloop
        
    endif
    
    
    // Refreshes the multiboard
    call amsTS.Fold()
    call amsTS.Unfold()
    call DestroyTrigger(GetTriggeringTrigger())
endfunction

private function ResourceActions takes nothing returns nothing
    local integer i = 0
    loop
    exitwhen i &gt; PLAYERS_PER_TEAM * TEAM_AMOUNT
        if (ENABLE_RESOURCE_GOLD) then
            call amsTS.SetPlayerItem(i,2+TAG_FOR_GOLD,I2S(GetPlayerState(Player(i),PLAYER_STATE_RESOURCE_GOLD)))
        endif
        if (ENABLE_RESOURCE_LUMBER) then
            call amsTS.SetPlayerItem(i,2+TAG_FOR_LUMBER,I2S(GetPlayerState(Player(i),PLAYER_STATE_RESOURCE_LUMBER)))
        endif
        set i = i + 1
    endloop
endfunction

function amsTS_IncreaseScore takes integer p, integer tag, integer amount returns nothing
    call amsTS.SetPlayerItem(p,2+tag,I2S(S2I(amsTS.GetPlayerItem(p,2+tag))+amount))
endfunction

function amsTS_SetScore takes integer p, integer tag, integer amount returns nothing
    call amsTS.SetPlayerItem(p,2+tag,I2S(amount))
endfunction

function amsTS_SetTagValue takes integer p, integer tag, string value returns nothing
    call amsTS.SetPlayerItem(p,2+tag,value)
endfunction

function amsTS_FetchScore takes integer p, integer tag returns integer
    return S2I(amsTS.GetPlayerItem(p,2+tag))
endfunction
   
private function Init takes nothing returns nothing
    local trigger T = CreateTrigger()
    //! runtextmacro AMS_TeamScores_Configuration()
    call TriggerRegisterTimerEventSingle(T, 0.00)
    call TriggerAddAction(T, function Actions)
    if (ENABLE_RESOURCE_GOLD or ENABLE_RESOURCE_LUMBER) then
        set T = CreateTrigger()
        call TriggerRegisterTimerEventPeriodic(T, 0.10)
        call TriggerAddAction(T, function ResourceActions)
    endif
    set T = null
endfunction
endlibrary</i></i>



Screenshot:
amstsexamplegw0.jpg
 

Cohadar

master of fugue
Reaction score
209
This system is like a raw, oily, smelly engine... it works already, but it'll need quite some cleaning and constructing before it can be called a genuine Benz ;)

Perhaps I can help a bit...

First of all coding looks nice, comments are also good.
But desyng is flawed a bit.

Instead of bunch MB_ prefixed functions make a struct MB
and make those functions methods of MB struct.

And don't put ABC inside the same trigger.
ABC just like any other library should be used in it's own trigger.
Days of horrible map header pasting are long gone.

For an example of symilar system look at my Dialog sys.
It might help you to set a better design.

Cheers.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Instead of bunch MB_ prefixed functions make a struct MB
and make those functions methods of MB struct.

Never used methods before:
- Why would they be better than functions here?
- I'm already using structs for most of my coding, so won't that cause errors? (as in: using a struct A within a struct B's method)
 

Cohadar

master of fugue
Reaction score
209
lolz.

I suggest you just do what I said,
learn to use methods it is for your own good, trust me.

You have some wrong beliefs about how this stuff works,
I suggest you read jasshelper documentation about structs and methods and learn to use them properly.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
No seriously, why would I want to use methods here?

"Just because" isn't the best argument to convince someone from going to "has never used methods before" to "genuine method junky".
 

waaaks!

Zinctified
Reaction score
255
will u release a demo map for it?
i need a flexible multiboard for my project though...

how about icons on the left side of the player names? can this system has an option for it?

im looking forward for this system
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
how about icons on the left side of the player names? can this system has an option for it?

It has that option already, only thing right now is the code doesn't support 0 row/col input yet. So you'd have to set it for every player. (which isn't that big of a deal actually, since you'll probably have a different icon for every player)

Upside is: When sorting players, the icons get sorted along with it, so every player will always keep his color, score, icons, etc. at any given time.

JASS:

local boolean showValue = true // shows the player&#039;s name
local boolean showIcon = true // shows the icon for this item
local integer row = MB_GetPlayerRow(MB,PlayerInt) // Fetches the row for the player in multiboard MB
local integer col = 1 // Player names and icons are set in column 1
call MB_SetIconPath(MB,row,col,&quot;path/to/some/icon&quot;) // Sets the path to the icon picture
call MB_SetItemStyle(MB,row,col,showValue,showIcon) // Tells the MB to display the icon for that item
 

Cohadar

master of fugue
Reaction score
209
No seriously, why would I want to use methods here?

"Just because" isn't the best argument to convince someone from going to "has never used methods before" to "genuine method junky".

Any programmer will tell you that when you have a bounch of functions that
all have same first argument it is time to go for methods.

You even have MB_Create and MB_Destroy functions!!!
Can it be more obvious that you need struct/methods here.

Just ask anyone who is good at jass, they will tell you the same.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Any programmer will tell you that when you have a bounch of functions that
all have same first argument it is time to go for methods.

You even have MB_Create and MB_Destroy functions!!!
Can it be more obvious that you need struct/methods here.

Just ask anyone who is good at jass, they will tell you the same.

Right, so I could do this (since it does indeed seem nice) but I will run into a little problem then.

Now i have the struct array ItemData, every Multiboard struct will still need several of those, so how am I supposed to get ItemData arrays into every struct when I don't know in advance how big the array will/should be?

(for a 4x4 board I'd need "private ItemData array I[15]" but for a 12x3board I'd need "private ItemData array I[35]")
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Care to elaborate on that one? Seems interesting... and yet useful.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Would this do it?
(or will it conflict in the ItemData next being private?)

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

struct Multiboard
    string Value
    string Prefix
    string Suffix
    string Color
    string PrefixColor
    string SuffixColor
    timer ClockTimer
    integer array PlayerRow[11]
    private ItemData first
    private method GetItemDataFromList takes integer Item returns ItemData
        local integer i = 0
        local ItemData I = first
        loop
        exitwhen i == Item
            set I = I.next
            set i = i + 1
        endloop
        return I
    endmethod
endstruct
 

Cohadar

master of fugue
Reaction score
209
Aha my bad, it should not be private.
(Actually it should, but in java not in jass)

Sorry for that, professional deformation.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
v2.00 released:

Everything now works with a variable of type Multiboard (not multiboard).


More info on how-to soon, but now I got a paper to make for uni...
 

Cohadar

master of fugue
Reaction score
209
I am not sure anyone would need subsorting,
but zero-param rows/cols are a must have.

Anyways congrats, you did a great job.
You are using libraries properly,
code is well commented and looks awesome in general.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Anyways congrats, you did a great job.
You are using libraries properly,
code is well commented and looks awesome in general.
Thanks, means a lot to me. :)

Update v2.01:
- Renamed library so it is consistent with the system's name.
- Added an example map containing a hero-arena like multiboard.
 

Cohadar

master of fugue
Reaction score
209
After examining the map:

This:
Code:
ABC Struct Attachement System
AMS Advanced Multiboard System
is a bad idea.

I prefer if you named ABC as it should be names, simply ABC,
someone might think that trigger needs to have that silly long name.
You can do what ever you want with your library,
but I recommend that you name it simple AMultiboard or something,
noone likes too long names.

Now for the code:

This:
JASS:
    call MultiboardDisplay(Example1.GetMultiboard(), false)
    call MultiboardDisplay(Example1.GetMultiboard(), true)


Should be this:
JASS:
    Example1.Display(false)
    Example1.Display(true)


Totally remove GetMultiboard() function,
internal multiboard is private and should stay that way.

-----

This I don't like:
JASS:
    call Example1.SetItem(1,1,&quot;[Players]&quot;) // Sets row 1, col 1 to [Players].
    call Example1.SetItem(1,2,&quot;[Kills]&quot;) // Sets row 1, col 2 to [Kills].
    call Example1.SetItem(1,3,&quot;[Deaths]&quot;) // Sets row 1, col 3 to [Deaths].
    call Example1.SetItem(3,1,&quot;Team 1&quot;) // Sets row 2, col 1 to Team 1.
    call Example1.SetItem(11,1,&quot;Team 2&quot;) // Sets row 10, col 1 to Team 2.
    call Example1.SetItemColor(3,1,&quot;FF0000&quot;) // Sets Team 1 to red.
    call Example1.SetItemColor(11,1,&quot;0000FF&quot;) // Sets Team 2 to blue.
    call Example1.AddPlayers(0,6,4,1,true) // adds 6 players starting with player 1 (0) at row 4 in column 1, coloring their names.
    call Example1.AddPlayers(6,6,12,1,true) // adds 6 players starting with player 7 (6) at row 12 in column 1, coloring their names.


What is a point of having a heavy complex jass system,
if users still have to write all column row indexes manually.
(Especially when they are going to be sorted anyway)

Perfect system would probably do it like this:
JASS:
    call Example1.AddHeader(&quot;[Players]&quot;)
    call Example1.AddHeader(&quot;[Kills]&quot;)
    call Example1.AddHeader(&quot;[Deaths]&quot;)

    // can add up to 4 teams (for footy maps for example)    
    call Example1.AddTeam(&quot;Team 1&quot;)
    call Example1.AddTeam(&quot;Team 2&quot;)
    call Example1.AddTeam(&quot;Team 3&quot;)
    call Example1.AddTeam(&quot;Team 4&quot;)

    call Example1.AddPlayerToTeam(1, Player(0))
    call Example1.AddPlayerToTeam(1, Player(4))
    call Example1.AddPlayerToTeam(1, Player(8))

    call Example1.AddPlayerToTeam(2, Player(1))
    call Example1.AddPlayerToTeam(2, Player(5))
    call Example1.AddPlayerToTeam(2, Player(9))

    call Example1.AddPlayerToTeam(3, Player(2))
    call Example1.AddPlayerToTeam(3, Player(6))
    call Example1.AddPlayerToTeam(3, Player(10))

    call Example1.AddPlayerToTeam(4, Player(3))
    call Example1.AddPlayerToTeam(4, Player(7))
    call Example1.AddPlayerToTeam(4, Player(11))


See how better it looks, it is actually easier to make a multiboard that way.
No need to write all that ugly constants.

That is what adds true value to a system, making it easy for people to use.

Just think of this:
The richest person on planet is Bill Gates, why?
Because he made a system that can be installed by clicking next -> next -> next...

----------

I hope I didn't scared you with all this, and I know this will be hard to do.

It takes great effort to make a great system,
if it was not that way everybody could be a great programmer.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      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