Tutorial Advanced Multiboards: Sorting with GUI

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
This tutorial will show you how you can have the goodies of both type of "boards" that are available in WE, namely:

- Sort/Player name ability of Leaderboards
- Graphical superiorness of Multiboards


Index:
  • Problem & Solution
  • Multiboard Structure
  • Variables
  • Triggers
  • Possible Options

Problem & Solution

Problem:
Multiboards use strings as entries and can't hence be sorted through standard GUI triggers.

Solution:
Use the following triggers which I based on a bubble sort algorythm (sp?)

Explanation of Bubble Sorting:

Let's say I have 5 elements in a row and I wanted to sort these.
[a] 1
4
[c] 3
[d] 5
[e] 2

What would happen is that it would compare A with B and if A was less than B, swap them.
Then it would _again_ compare A, but this time with C and if A was less than C, swap them.

[a] 1 --> [a] 4 --> [a] 4 --> [a] 5 --> [a] 5
4 --> 1 --> 1 --> 1 --> 1
[c] 3 --> [c] 3 --> [c] 3 --> [c] 3 --> [c] 3
[d] 5 --> [d] 5 --> [d] 5 --> [d] 4 --> [d] 4
[e] 2 --> [e] 2 --> [e] 2 --> [e] 2 --> [e] 2

Eventually, after comparing/swapping the first row with every other row: the highest row would contain the highest value.
So we could already "print" the above row as the highest value.

Knowing that the above row now contains the highest value, we will continue the sorting of the other rows, starting from the second row
This would eventually give us the second highest value in the second row, which we could then "print" in the second row.

Keep repeating this untill you compare the pre-last row with the last one.

NOW:
Since we cannot compare the last row with the row below it (there is no row below it),
we run this "comparing loop" a much as there are rows MINUS 1.

Every time that we establish a highest value, the next time we start comparing rows, there will be one comparing occurence less
(since we don't have to compare the recently established "top row" anymore.)

The amount of comparisons that you make for an amount of rows, is the amount -1 (Since you cannot compare yourself with yourself)
For 10 rows, you'll need 9 comparisons
For 5 rows, you'll need 4 comparisons
etc.

Now since we take one row less than the amount of rows we got, but we keep the amount of comparisons to be made:
The amount of comparisons = the amount of rows -1 (- 0 eliminated rows) to be made for the first loop
The amount of comparisons = the amount of rows - 1 (-1 eliminated rows) for the second loop
etc


This will lead to this logic:
Code:
For LoopIntegerA [1 to (Amount of rows -1)]
  For LoopIntegerB [1 to (Amount of rows - LoopIntegerA))]
    Compare A with A+B and swap if needed (B will increase each loop, so basically you compare A with A+1, A with A+2, etc)
  EndOfLoop
  Print row A (since it has the highest possible value for that row)
EndOfLoop
Print last row (since it will have the lowest value possible after it got compared with the pre-last row in the end)

So suppose we have 5 rows:
We'd set A as 1 -> rows -1, being 1 -> 4.
for the first row A=1, we'd need 4 comparisons: 5-A
- which would be A <-> A+1 // A <-> A+2 // A <-> A+3 // A <-> A+4
for the second row A=2, we'd need 3 comparisons: 5-A, because the top row (A from the previous loop) got established as the highest value.
- which would be A <-> A+1 // A <-> A+2 // A <-> A+3
for the third row A=3, we'd need 2 comparisons: 5-A, because the top 2 rows (A from the previous 2 loops) got established as the highest values.
- which would be A <-> A+1 // A <-> A+2
for the fourth row A=4, we'd need 1 comparison: 5-A, because the top 3 rows (A from the previous 3 loops) got established as the highest values.
- which would be A <-> A+1

This is the core thinking of my trigger, I hope it's a little clear to you :)



[ii] Multiboard Structure

For this version of the sorting trigger, you may build your Multiboard in the following fashion:

- 0 -> x Title rows (PrefixRows)
Usually 1 or 2, these rows show the description of what the values in the next rows mean.
- 1 -> 12 Player rows
These rows will contain the player names, followed by the value they have to be sorted by.
- 0 -> x Title rows (AffixRows)
Usually 1 or 2, these rows show something extra like "Lives remaining".

NOTE: A blank row in either PrefixRows or AffixRows COUNTS AS A ROW.


[iii] Variables

Player Group variables
- PlayerGroup_PlayerIsPlaying
Array of all playing human players.


Player variables
- Player_InPosition[]
Array of players, sorted by their position in the multiboard. (not their row number, but their position towards others)


Integer variables
- Integer_BoardRowForPlayer[]
This array keeps track of the row number of the player whom's player number you insert in the brackets.

- Integer_MultiboardPrefixRows
These are the rows you use for titles/spaces/etc before you create the player rows

- Integer_MultiboardAffixRows
These are the rows you use for subtitles/spaces below the player rows

- Integer_MultiboardRows
Total amount of rows in the multiboard. This is PrefixRows+EnteredPlayers+AffixRows

- Integer_KillCount[]
Counts kills for the player whom's player number you put in the brackets. Will remain 0 untill first kill

- Integer_BubbleSortA
Integer you create to use in the outer loop. (Will remain un-initiated untill first loop)

- Integer_BubbleSortB
Integer you create to use in the inner loop. (Will remain un-initiated untill first loop)

- tempInteger
Overall "buffer" integer, make sure not to run multiple triggers with this integer at once


String variables
- String_ColorCodeStart
Standard "gold" colored text Color Code

- String_ColorCodePlayer[]
Color Code for player whom's player number you enter between the brackets

- String_ColorCodeEnd
Ends an opened Color Code


[iv] Triggers

Setting variables:
Code:
Initialization Settings
    Events
        Map initialization
    Conditions
    Actions
        Set PlayerGroup_IsPlaying = (All players matching ((((Matching player) slot status) Equal to Is playing) and (((Matching player) controller) Equal to User)))
        Set String_ColorCodeStart = |cffffcc00
        Set String_ColorCodePlayer[1] = |cCFFF0202
        Set String_ColorCodePlayer[2] = |cCF0041FF
        Set String_ColorCodePlayer[3] = |cCF1BE5B8
        Set String_ColorCodePlayer[4] = |cCF530080
        Set String_ColorCodePlayer[5] = |cCFFFFC00
        Set String_ColorCodePlayer[6] = |cCFFE890D
        Set String_ColorCodePlayer[7] = |cCF1FBF00
        Set String_ColorCodePlayer[8] = |cCFE45AAF
        Set String_ColorCodePlayer[9] = |cCF949596
        Set String_ColorCodePlayer[10] = |cCF7DBEF1
        Set String_ColorCodePlayer[11] = |cCF0F6145
        Set String_ColorCodeEnd = |r
This trigger:
- selects all human playing players and adds them into the right array
- sets the general gold Color Code and the Color Code for every player

Creating multiboard/Setting multiboard variables:
Code:
Post Initialization
    Events
        Time - Elapsed game time is 0.00 seconds
    Conditions
    Actions
        -------- MULTI BOARD --------
        -------- SET ROW AMOUNTS --------
        Set Integer_MultiboardPrefixRows = 1
        Set Integer_MultiboardAffixRows = 2
        Set Integer_MultiboardRows = ((Number of players in PlayerGroup_IsPlaying) + (Integer_MultiboardPrefixRows + Integer_MultiboardAffixRows))
        -------- SET A VARIABLE FOR THE LOOP --------
        Set tempInteger = Integer_MultiboardPrefixRows
        -------- CREATE THE MULTI BOARD --------
        Multiboard - Create a multiboard with 2 columns and Integer_MultiboardRows rows, titled Kill Count
        -------- TURN OFF ICONS IN ALL ROWS AND SET FIRTS COLUMN TO 15% WIDTH--------
        For each (Integer A) from 1 to Integer_MultiboardRows, do (Actions)
            Loop - Actions
                Multiboard - Set the display style for (Last created multiboard) item in column 1, row (Integer A) to Show text and Hide icons
                Multiboard - Set the display style for (Last created multiboard) item in column 2, row (Integer A) to Show text and Hide icons
                Multiboard - Set the width for (Last created multiboard) item in column 1, row (Integer A) to 15.00% of the total screen width
        -------- SET FIRST ROW VALUES (TITLES) --------
        Multiboard - Set the text for (Last created multiboard) item in column 1, row 1 to (String_ColorCodeStart + ([Player Name] + String_ColorCodeEnd))
        Multiboard - Set the text for (Last created multiboard) item in column 2, row 1 to (String_ColorCodeStart + ([Kills] + String_ColorCodeEnd))
        -------- SET PLAYER ROW VALUES --------
        Player Group - Pick every player in PlayerGroup_IsPlaying and do (Actions)
            Loop - Actions
                Set tempInteger = (tempInteger + 1)
                Set Player_InPosition[(tempInteger - Integer_MultiboardPrefixRows)] = (Picked player)
                Set Integer_BoardRowForPlayer[(Player number of (Picked player))] = tempInteger
                Multiboard - Set the text for (Last created multiboard) item in column 1, row tempInteger to (String_ColorCodePlayer[(Player number of (Picked player))] + ((Name of (Picked player)) + String_ColorCodeEnd))
                Multiboard - Set the text for (Last created multiboard) item in column 2, row tempInteger to (String(0))
        -------- SET LAST ROW VALUES (LIVES) --------
        Multiboard - Set the text for (Last created multiboard) item in column 1, row Integer_MultiboardRows to Lives remaining:
        Multiboard - Set the text for (Last created multiboard) item in column 2, row Integer_MultiboardRows to (String(Integer_LivesAmount))
        -------- SHOW THE MULTI BOARD --------
        Multiboard - Show (Last created multiboard)
        -------- TURN ON THE AUTO-SORT --------
        Trigger - Turn on Sort Multiboard <gen>
This trigger:
- sets the amount of Prefix and Affix rows
- creates the rows in this order: Prefix/Players/Affix
- sets the values for the prefix rows (each row in PrefixRows variable) and affix rows (last row = max rows, pre-last row = max rows -1, etc)

Details:
Code:
        Set tempInteger = Integer_MultiboardPrefixRows
            Loop - Actions
                Set tempInteger = (tempInteger + 1)
                Set Player_InPosition[(tempInteger - Integer_MultiboardPrefixRows)] = (Picked player)
                Set Integer_BoardRowForPlayer[(Player number of (Picked player))] = tempInteger
Will set the first player's assigned row (Integer_BoardRowForPlayer) to Prefixrows+1, which is in fact the first row after the prefix rows, thus the first player's row.
The second loop it will assign the second player's row, etc.

Will set the first player to be in the lead, using (Tempinteger-PrefixRows), which is in fact ((PrefixRows+1)-PrefixRows)
which is in fact 1 the first loop, 2 the second loop, etc. because every loop: 1 is added to tempInteger

Increasing the value of a player (Kills in this case):
Code:
Add Kills
    Events
        Unit - A unit Dies
    Conditions
        (Owner of (Dying unit)) Equal to Player_Creeps
    Actions
        Set Player_LastKiller = (Owner of (Killing unit))
        Set Integer_KillCount[(Player number of Player_LastKiller)] = (Integer_KillCount[(Player number of Player_LastKiller)] + 1)
        Multiboard - Set the text for (Last created multiboard) item in column 2, row Integer_BoardRowForPlayer[(Player number of Player_LastKiller)] to (String(Integer_KillCount[(Player number of Player_LastKiller)]))
This trigger:
- Increases a player's kills
- Uses the variables, set in the previous trigger, to lead us to the right row where we need to update the kills.
- Updates the kills for the killing player

Sorting the multiboard by a value (Kills in this case):
INITIALLY OFF
Code:
Sort Multiboard
    Events
        Time - Every 0.10 seconds of game time
    Conditions
        (Integer_MultiboardRows - (Integer_MultiboardPrefixRows + Integer_MultiboardAffixRows)) Greater than 1
    Actions
        For each (Integer Integer_BubbleSortA) from 1 to ((Integer_MultiboardRows - (Integer_MultiboardPrefixRows + Integer_MultiboardAffixRows)) - 1), do (Actions)
            Loop - Actions
                For each (Integer Integer_BubbleSortB) from 1 to ((Integer_MultiboardRows - (Integer_MultiboardPrefixRows + Integer_MultiboardAffixRows)) - Integer_BubbleSortA), do (Actions)
                    Loop - Actions
                        If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            If - Conditions
                                Integer_KillCount[(Player number of Player_InPosition[Integer_BubbleSortA])] Less than Integer_KillCount[(Player number of Player_InPosition[(Integer_BubbleSortA + Integer_BubbleSortB)])]
                            Then - Actions
                                Set tempInteger = (Player number of Player_InPosition[Integer_BubbleSortA])
                                Set Player_InPosition[Integer_BubbleSortA] = Player_InPosition[(Integer_BubbleSortA + Integer_BubbleSortB)]
                                Set Player_InPosition[(Integer_BubbleSortA + Integer_BubbleSortB)] = (Player(tempInteger))
                                Set Integer_BoardRowForPlayer[(Player number of Player_InPosition[Integer_BubbleSortA])] = (Integer_BubbleSortA + Integer_MultiboardPrefixRows)
                                Set Integer_BoardRowForPlayer[(Player number of Player_InPosition[(Integer_BubbleSortA + Integer_BubbleSortB)])] = ((Integer_BubbleSortA + Integer_MultiboardPrefixRows) + Integer_BubbleSortB)
                            Else - Actions
                Multiboard - Set the text for (Last created multiboard) item in column 1, row (Integer_BubbleSortA + Integer_MultiboardPrefixRows) to (String_ColorCodePlayer[(Player number of Player_InPosition[Integer_BubbleSortA])] + ((Name of Player_InPosition[Integer_BubbleSortA]) + String_ColorCodeEnd))
                Multiboard - Set the text for (Last created multiboard) item in column 2, row (Integer_BubbleSortA + Integer_MultiboardPrefixRows) to (String(Integer_KillCount[(Player number of Player_InPosition[Integer_BubbleSortA])]))
        Set tempInteger = (Integer_MultiboardRows - Integer_MultiboardAffixRows)
        Multiboard - Set the text for (Last created multiboard) item in column 1, row tempInteger to (String_ColorCodePlayer[(Player number of Player_InPosition[(tempInteger - Integer_MultiboardPrefixRows)])] + ((Name of Player_InPosition[(tempInteger - Integer_MultiboardPrefixRows)]) + String_ColorCodeEnd))
        Multiboard - Set the text for (Last created multiboard) item in column 2, row tempInteger to (String(Integer_KillCount[(Player number of Player_InPosition[(tempInteger - Integer_MultiboardPrefixRows)])]))
This trigger:
- Does exactly what i explained at start: Bubble Sorting by value
- Fetches the players' kills and uses these to sort the board by
- If it needs to swap, it updates the variables which lead the kill trigger to a row, so no kill is asigned to the wrong row.
- Uses a temprary variable so no data is lost while swapping.


[v] Possible Options


Add player suffix:

Say you want the multiboard to show if a player left; simply create a String_AffixOfPlayer[] variable and whenever a player leaves,
set String_AffixOfPlayer[Player number of(Leaving Player)] = " (Has left)".
(WITH the space in front)

Then, in every action that alters a player's name in the multiboard (usually every column 1 action), change the trigger so it doesn't show:
PlayerColor + Player Name + EndColor
but instead shows:
PlayerColor + Player Name + Player Affix + EndColor

That way,
- if nothing is set to the string: nothing happens
- if the string is set: it gets added behind the player's name



There, that's it for now: I hope you liked it
 

Tonks

New Member
Reaction score
160
I just skimmed over it, but it seems a little skimpy.
A good strategy, in my opinion, for making sure that inexperienced mappers will understand, is to explain everything. Explain what each line in your code does, why it does it, and why you need it.

Basically, all you have right now is a bunch of Gui triggers that would mean nothing to an inexperienced mapper, because it's a lot of code and it's fairly advanced.

You should explain a bit more about it. What else can you do with a multiboard? What other methods can you use to sort it? Etc. etc..
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Hmm, indeed...
Well, it is a bubble sort though, which in se is a rather advanced piece of coding.


But feart not children! For I shall make thee joyful by translating this double-tongued monster into common English.. or die trying.


basically what it does is:
- Setting variables

- Adding title rows
- Adding player rows
- Adding bottom rows

- Selecting those rows that involve players and sort them by value
- Re-assign variables that lead the right player's "value" (i.e.: kills) to the right row

- Show rows after they are sorted.


I implemented this in my TD and will update the tutorial once i got screenshots to show what it does in game.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
Updated the tutorial entirely; explaining variables, triggers and Bubble Sort thoroughly.

In short: I made it more user-friendly
 

AceHart

Your Friendly Neighborhood Admin
Reaction score
1,497
For the record, you can create leaderboards for groups of players, sort as needed, and simply show the players in order.
There's not really a need to do the sorting by hand...

With a bit of preparing, it's also possible to sort by two values at once.
As in, players with identical kill scores will be sub-sorted according to deaths:
Whenever you add a kill, add 10000 to that player's sort value, whenever you add a death, subtract 100.
Sort them by that value.


Things like
> Multiboard - Set the display style for (Last created multiboard) item in column 1, row (Integer A) to Show text and Hide icons

can be done in one line without loop: use 0 instead of "integer A".
With (0, 0), it applies to the entire board.
 

Magentix

if (OP.statement == false) postCount++;
Reaction score
107
For the record, you can create leaderboards for groups of players, sort as needed, and simply show the players in order.
There's not really a need to do the sorting by hand...

-->

This tutorial will show you how you can have the goodies of both type of "boards" that are available in WE, namely:

- Sort/Player name ability of Leaderboards
- Graphical superiorness of Multiboards

:) This is the main reason why I chose Multiboards: Graphical superiorness

Things like
> Multiboard - Set the display style for (Last created multiboard) item in column 1, row (Integer A) to Show text and Hide icons

can be done in one line without loop: use 0 instead of "integer A".
With (0, 0), it applies to the entire board.

Very useful info! I didn't know that :eek:
 

Sir Gordon

Decent User (I'm as good as you)
Reaction score
43
That's a good tutorial, which may need some implement, but it's good nevertheless :)
 
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