• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Drawing a Paragraph onto a Multiboard (+LocalPlayer)

Status
Not open for further replies.
Level 13
Joined
Jul 26, 2008
Messages
1,009
Alright, so I wanted to create a fairly simple multiboard that would display a description (In this case of a skill) to the player.

I realized not all the text would fit neatly on a multiboard if I shoved it all into one row.

So I decided to create a loop that would draw the text onto the row up to a certain point, then save the rest of the text and start a new row.

Simple enough.

Well this is how the Hashtable for the description is initialized:

JASS:
    call SaveStr(AH, 'WhWi', 1, "|cffaca899W|rhirlwind:/    Create a whirling wind that sucks up units that get to close. As you channel the units raise higher and higher, causing more damage on impact with the ground when the whirlwind is released.//|cffffd700Level increases duration of the whirlwind.|r" )

This is the multiboard initialize:

JASS:
    set DescrBoard = CreateMultiboard()
        call MultiboardSetItemsStyle(DescrBoard, true, false)
        call MultiboardSetColumnCount(DescrBoard, 1)
        call MultiboardSetItemsWidth(DescrBoard,0.2)

And this is the code that calls up the multiboard:

JASS:
//(Note that skillhash[text] returns a rawcode based on the text entered.)
            call MultiboardSetTitleText(DescrBoard, GetObjectName(skillhash[text])+" Description")

            set text = LoadStr(AH, skillhash[text], 1)
            set num = 1

            loop
                exitwhen StringLength(text) < 2

                set i2 = 1
                loop
                    exitwhen i2 > StringLength(text) or SubString(text, i2-1, i2) == "/" or i2 > 46
                    set i2 = i2 + 1
                endloop

                if SubString(text, i2-1, i2) == "/" then
                    call MultiboardSetItemValueBJ(DescrBoard, 1, num, SubString(text, 0, i2-1))
                    set text = SubString(text, i2, StringLength(text))
                else
                    call MultiboardSetItemValueBJ(DescrBoard, 1, num, SubString(text, 0, i2))
                    set text = SubString(text, i2, StringLength(text))
                endif


                set num = num + 1
            endloop

            call MultiboardSetRowCount(DescrBoard, num)
            call MultiboardDisplay(DescrBoard, true)

Well the two problems currently are these:

The first time I enter a skill name it gives me a blank board, but from there it's fine.

I need a way to create a "linebreak" on a space instead of in the middle of a word.

Bonus points to anyone who can also help me make this multiboard different per player. I assume it's localplayer stuff but I'm not always sure how to play with it properly, and messing it up is disastrous.
 
This is a pretty annoying issue, but it can be resolved with enough work put into it. However, there aren't any systems that will do it automatically. Perhaps I should look into making a multiboard system that will allow for this, it would probably be useful since I've seen this mentioned a lot before.

Anyway, overlord_ice made some more recent systems involving text and line breaks and what not, but sadly he didn't finish. The only "completed" ones I know of are my own. To find them, go here:
[Snippet] StringSize
[Snippet] LineBreak (requires StringSize)

What this will do is allow you to modify strings to be split into multiple ones, depending on how long you want the cutoff point to be. However, this won't do everything you need, as you still need to do the multiboard manipulation yourself.

Anyway, as for the API, you will want to look at LineBreak in particular.
JASS:
// LineBreak.create( string source , real size, boolean preserveColors)
//
//      Divides the "source" string into several lines. Each line has a maximum width of the "size" provided.
//      "Preserve Colors" will activate a feature to make sure that colors transfer to the next line as well
//      if they are supposed to.
//
/*      string array LineBreak.Line[]                                                                               */
/*      integer      LineBreak.Count                                                                                */
//
//            LineBreak.Count returns how many lines were created.
//            LineBreak.Line[n] returns the nth line of the line breaks.

So if you have a string s, and you want to have it cutoff after a size of "500" (and preserve colors), then you will just do
JASS:
call LineBreak.create( s, 500, true)

Then they will be stored in a static variable named "Line". You can access it by using LineBreak.Line[int], and it will have split it up into LineBreak.Count different strings. Check out the sample in that link for more information.

Overall, it is a LOT of guesswork. You will probably be testing a lot to see if the values work out for your purposes. However, it should get the job done with enough work put in. I recommend that you have the paragraph part of the multiboard at the bottommost area, because if you want the line count to be dynamic then you will have to be changing the row count a lot. (which may lead to weird problems)

Try it out and see if it works. There are some problems with resolution, but that can't really be fixed without asking the user for their resolution. In my opinion, just make it work on something like 1024x768 and it should be fine.

------

As for the GetLocalPlayer() part, the easiest way is to just create 1 multiboard per player. Then, you can just display it via GetLocalPlayer(). This way, you can access each multiboard without using local blocks, and it will work just fine. For example:
JASS:
local integer i = 0
loop
    exitwhen i == 12
    set MultiboardVariable[i] = CreateMultiboard()
// i don't remember if they are default hidden, so this line may or may not be necessary
    call MultiboardDisplay(MultiboardVariable[i], false) 
    if GetLocalPlayer() == Player(i) then
        call MultiboardDisplay(MultiboardVariable[i], true)
    endif
    set i = i + 1
endloop
 
Level 13
Joined
Jul 26, 2008
Messages
1,009
This seems exactly what I was looking for. I'll go over it more tomorrow when I have more time. I'm not sure where to grab ASCII though, assuming it too is a library.
I shouldn't have a problem, since the board never shows anything beyond the paragraph, and is 1 column long.

Well some new issues arose with this new set of commands. I think the system I need is less complex than the one you're offering, and that the main problem I'm having is with multiboards.

So far this does what I want:

JASS:
            call MultiboardSetTitleText(DescrBoard, GetObjectName(skillhash[text])+" Description")
            call MultiboardDisplay(DescrBoard, true)

            set text = LoadStr(AH, skillhash[text], 1)

            if text == null then
                set text = "Not a learnable skill!"
                set num = 2
            else
            
                set num = 1
                loop
                    exitwhen StringLength(text) < 1

                    set i2 = 1
                    set i = 46
                    loop
                        exitwhen i2 > StringLength(text) or SubString(text, i2-1, i2) == "/" or i2 > i
                        if SubString(text, i2-1, i2+1) == "|c" then
                            set i = i + 10
                        elseif SubString(text, i2-1, i2+1) == "|r" then
                            set i = i + 2
                        endif
                        set i2 = i2 + 1
                    endloop

                    if SubString(text, i2-1, i2) == "/" or i2 > StringLength(text) then
                        call MultiboardSetItemValueBJ(DescrBoard, 1, num, SubString(text, 0, i2-1))
                    else
                        loop
                            set i2 = i2 - 1
                            exitwhen SubString(text, i2-1, i2) == " "
                        endloop
                        call MultiboardSetItemValueBJ(DescrBoard, 1, num, SubString(text, 0, i2))
                    endif
                    set text = SubString(text, i2, StringLength(text))

                    set num = num + 1
                endloop
            endif
            call MultiboardSetRowCount(DescrBoard, num-1)

But it gives rather strange results. When I pull up a string that's less rows than another, and then try to pull up any strings that are now more rows, it doesn't display the last few rows anymore. That's my only problem now.

Stupid Multiboards.

Also it refuses to show the last part of this:

JASS:
    call SaveStr(AH, 'WhWi', 1, "|cffaca899W|rhirlwind/    Create a whirling wind that sucks up units that get to close. As you channel the units raise higher and higher, causing more damage on impact with the ground when the whirlwind is released.//|cffffd700Level increases duration of the whirlwind.|r" )

If you want to see this in action, the map is attached. Basically start the game as Gray, hit the done button, type demote self, click a hero twice and then type any of these commands:

disp blastward
disp whirlwind
disp geode
disp rush
 
Last edited:
Status
Not open for further replies.
Top