Solarus Forum

Solarus => Development => Topic started by: Diarandor on July 10, 2015, 04:29:00 pm

Title: About color text dialogs
Post by: Diarandor on July 10, 2015, 04:29:00 pm
Hi there!

I have modified Christopho's dialog_box.lua file so that the dialog box allows some commands for colored text.

For this to work correctly it is required that all letters have the same width (which happens for the font I am using, but may not be true for some of the fonts you use), because letters of different colors are drawn in different text surfaces, and to align the letters I use spaces when necessary.

The syntax of the new commands is the following:
${surface_name}: change to other surface. This allows to use several colors at the same time, one for each surface. The original one is "${default}". (These surfaces are destroyed after the dialog and the default one is reseted to white color.)

$[color] or $[(r,g,b)]: name of a color (red, blue,...) predefined in the function dialog_box:set_color(color), or RGB coordinates of some color. These commands only affect to the current surface.

(I was thinking that these surfaces could also be used to program other commands, for example to move letters up and down and make text vibration. I'll try to make this when I have some time.)

I'd like to share the code of the script. Should I post it here? Or maybe in the libsolarus-mudora repository?
Title: Re: About color text dialogs
Post by: Christopho on July 10, 2015, 05:05:48 pm
Nice!
Posting this to libsolarus-mudora is probably a good idea, you can make a pull request.
Title: Re: About color text dialogs
Post by: Diarandor on July 10, 2015, 05:42:14 pm
I made the pull request. I put a link to the repository, just in case someone is interested in the script when it is posted there:
https://github.com/Nate-Devv/libsolarus-mudora
Title: Re: About color text dialogs
Post by: Diarandor on July 10, 2015, 06:09:20 pm
It's already posted. I put an example of how to use the commands:
Code: [Select]
dialog{
  id = "put_the_dialog_id_here",
  text = [[
$[red]This is an ${g}$[green]example${default} to
show how the script
changes the ${y}$[(200,200,0)]colors.${default}$[white]
${y}Feel free ${g}to use or
modify it as you wish.${default}
=P
]]
}
Title: Re: About color text dialogs
Post by: wrightmat on July 11, 2015, 12:39:10 am
Wow, this is really cool! I tried to play around with colored dialogs and didn't get anywhere with it - great work!  8)

Is anyone else getting this repeating error?
Code: [Select]
In on_draw [string "menus/dialog_box.lua"]:564: attempt to index a nil valueThe only thing I changed was this section:
Code: [Select]
  -- Initialize dialog box data.
dialog_box.line_surfaces.default = {}; dialog_box.current_line_surface = dialog_box.line_surfaces.default
  local font, font_size = sol.language.get_dialog_font()
  for i = 1, nb_visible_lines do
    dialog_box.lines[i] = ""
    dialog_box.line_surfaces.default[i] = sol.text_surface.create{
      horizontal_alignment = "left",
      vertical_alignment = "top",
      rendering_mode = "antialiasing",
      font = font,
      font_size = font_size,
    }
  end
to take into account the global dialog font. Did I mess something up? I tried it with the exact dialog that you posted, but I think I'm still a little confused by the syntax.
Title: Re: About color text dialogs
Post by: Diarandor on July 11, 2015, 07:14:24 am
Hi! I don't have this error, and I don't see why it happens, it's very strange. Did you have it before making the changes? (We can discuss this by email if you want.)

I think the error is in the line with "surface:draw(self.dialog_surface, text_x, text_y)", but not sure, isn't it? (This could mean that some of the other surfaces has not been created correctly and is nil.)

In the script there are more text_surfaces, which are created if the commands ${surface_name} is used, so you would need to change the font in that part of the code too. (I would put all the properties of the font above, where the general properties are defined.) I will try to improve a bit the code of the file in the repository.

PS: If you find the syntax terrible, I can change it. Suggestions are welcome. (At present, ${surface_name} changes the current surface and the commands $[color] and $[(r,g,b)] change the color of the current surface. But I can make changes in the file to change the syntax.)

EDIT: I found a mistake on my code. I was using sol.text_surface.create{...} instead of sol.text_surface.create({...}), so the parentheses were missing. This may be the cause of your problem, although it is strange that I did not get an error with this.
Title: Re: About color text dialogs
Post by: Diarandor on July 12, 2015, 08:22:39 am
Hi wrightmat,

I have modified the script (see the repository) so that the dialog font and font size are set using the custom function sol.language.get_dialog_font(), which is defined on the main script, and also corrected a syntax problem which could be the cause of the error you got. I think this is what you needed. Tell me if you still get some error.

I'll be happy to help with these things, and any suggestion to improve the script is welcome.
Title: Re: About color text dialogs
Post by: wrightmat on July 12, 2015, 09:11:08 pm
Works great now - thanks!

I think the syntax is just fine, but I did go through and simplify things for my game. I wanted to be able to use $r, $g, $b, etc. for the colors just like $0 and $1 are used. If you'd like to check out my edited version, I just committed the change to zbom's github.

I am so excited to start adding colors to my dialogs! Thanks again!
Title: Re: About color text dialogs
Post by: Diarandor on April 13, 2017, 06:32:45 pm
Hi! Due to the fact that there was a lot of discussions about the color features of the dialog box (bugs and improvements), we can continue talking about this in this topic.

@llamazing: You said that you made a script that allows to change colors for any type of font (even non-monospaced fonts) and also working with special characters (multi-byte characters, like accents, Japanese characters, etc). Would it be possible for you to share it here? It may help others, including me, to improve our dialog box scripts.

@wrightmat: I think that your syntax is ok for your game, but it is not so good for other games if we plan to add more features that are combined with the color feature; for instance, we could allow to change the font type or size in the middle of a dialog, or even allow to code several "shaking" effects for part of a dialog, so the approach of changing surfaces (and give names to them) may be better in my opinion.

The only think one has to be careful, when using your syntax, is that when you change color before of a word, your syntax may be concatenated in a weird way sometimes. For instance, if the first word of a phrase (say, "Hello world") is in red and the rest in white color, you would have to write "$rHello$w world" without a space between the "r" and "H" because spaces are not ignored (unless we change the code). With my syntax it would be something like this: "${red_surface}$[color_name]Hello ${default}world", which makes slightly easier for translators to detect where the color syntax ends, I think. It is also good to allow choosing color with the "$[(r,g,b)]" syntax too, just in case we don't want to define a color name for a color that is used just once; for colors that are used a lot it is probably better to use the other syntax, "$[color_name]", so allowing both syntaxes seems a good idea to me.

Note that if we try to expand the features of the dialog box, for instance to add a shaking effect, it would be usefult too the change of surface. If we use a LaTeX-like command for the shaking effect, say "$\{shake}text to shake", an example for a shaking word would be: "This ${shaking_surface}$\{shake}word ${default}is shaking". I was thinking that it could be more intuitive if we use a math mode like in LaTeX, where dollar symbols $ are used to start and to end math mode in a way like this "blablabla $\command_name{optional_parameters}$ blablabla", and enviroinments can be started or finished in the same way (maybe we could omit the dollars, or just use the dollars as if they were the "\" symbol as I already did in my syntax).

@everybody: Well, we all should discuss which syntax for the dialog box could be more intuitive, but also versatile for all kind of general purposes, and it would be nice to fix a standard notation compatible between all games. (It could even be added to the Quest Editor if Christopho or someone else programs the Editor to display the text with that kind of features (colors, shaking effects, change of fonts or size, etc), but I guess that this would be too specific and is probably a bad idea for the Editor.)

Our main purpose in this topic would be then to fix an "official" syntax for dialog box features that produces no limitations (i.e., that allows to add more commands and as many of them as we want) and is intended to be used in most games of the community (for compatibility reasons). We could share the code here or in some github repo. We could even open some poll in the forum, if necessary, to make some decissions.
Title: Re: About color text dialogs
Post by: llamazing on April 14, 2017, 01:04:11 am
@llamazing: You said that you made a script that allows to change colors for any type of font (even non-monospaced fonts) and also working with special characters (multi-byte characters, like accents, Japanese characters, etc). Would it be possible for you to share it here? It may help others, including me, to improve our dialog box scripts.

This script parses the text of dialogs.dat and processes player inputs:
https://github.com/llamaizing/cythera-tech-demo/blob/master/data/scripts/menus/dialogs/conversation_dialog.lua

> Note: dialog_box.text_areas contains the text from dialogs.dat

I wrote a library of UI elements, and this one is for multi-line text, used by the script above for the dialog box. This script handles the drawing to the screen, including making the "hyperlink" text a different color:
https://github.com/llamaizing/cythera-tech-demo/blob/master/data/scripts/lib/uix/controls/multiline.lua

> See lines 151-166 for keeping track of the position(s) of the hyperlink text to be colored differently
> See the ml:refresh() function for drawing of the text (especially lines 301-321)

I provided some details about the syntax I use for the dialogs here (I'm not suggesting syntax to use for this topic, just to be able to make sense of my scripts):
http://forum.solarus-games.org/index.php/topic,873.msg4864.html#msg4864



FYI-- don't be confused by the way I named my scripts. I used 3 types of dialogs in my project:

/scripts/dialog_manager.lua - manages the 3 types of dialogs above and processes keyboard/mouse inputs from the player. Ignore this one, it's not relevant to this topic.
/scripts/conversation_manager.lua - maps out the conversation, deciding which text to display next. It has nothing to do with drawing the dialog box and can be ignored for the purposes of this topic.
Title: Re: About color text dialogs
Post by: Diarandor on April 14, 2017, 02:21:23 am
Thanks a lot @llamazing!
I'm sure your scripts will be useful to others to program similar features.
Title: Re: About color text dialogs
Post by: llamazing on April 14, 2017, 07:51:56 am
My suggestion for syntax is to keep it simple and just use a dollar sign followed by a single letter to specify the command name, e.g. $c{red} for red text. For changing fonts it could be $f{courier} and $s{12} for font size.

I like the idea for having additional options too, such as specifying a color code, e.g. $c{255,0,170}. It might be easier to parse if a hex color code were used, like $c{ff00aa} because then there would always be exactly 6 characters and the commas would not be necessary.

I'd even go a step farther and allow for a third option where up to 9 preset values can be used, as hard-coded somewhere in the script, e.g. $c1 thru $c9. $c0 could be used as shorthand for $c{default}. This has the advantage of being very few characters.

I'd recommend against using the \ character in the syntax. It would make the parsing more difficult for separating out special characters like \n or \t. I also don't see any reason to include a second closing dollar sign. Adds one more character everywhere and potentially confusing for translators.
Title: Re: About color text dialogs
Post by: MetalZelda on April 15, 2017, 02:06:03 pm
Oooooo, i like this, i'll try this with different language to see if that works correctly

I also suggest adding a horizontal text alignment thing like $vertical{"center"}
i don't know, maybe centering some text be cool
Title: Re: About color text dialogs
Post by: Diarandor on April 15, 2017, 05:22:30 pm
It would be very useful too to add a feature that manages the change of line of the dialog box if the max lenght of one line is given. I don't have time these days to work on this, though.
Title: Re: About color text dialogs
Post by: MetalZelda on April 16, 2017, 01:54:20 am
There is still the spacing problem if you use a special characters such as é, è, ç, à and Asian type characters, even with a mono-spaced font, hmmm, this is one tough issue.
There is no problem when texts are in english though, but it is problematic, because, I am translating Book of Mudora in French and some texts overlap depending on if there is a special character before the colored text. This will also happen if you translate in Spanish / Russian / Asian languages.

This is the new surface's space that is problematic, the script already includes special characters it seems, but I can't figure out what is the real issue here ...
Title: Re: About color text dialogs
Post by: MetalZelda on April 17, 2017, 02:08:28 pm
Also, another cool feature you could add to your dialogbox script is savegame value parsing.
You will find example bellow and add it if you want. But a such basic feature is very useful for a lot of possibilities.

Example: displaying values (items, time, command, etc ...)

This could be useful for some texts, displaying the current value of multiple variable for example (since $v is only 1 value)
Here, using this method, I'm displaying all item commands for using an item, keyboard and Joypad.
Good news is, you can even use color
(http://i.imgur.com/lY7cWIw.png)

It's plug & play for the most part
Code: [Select]
Vous obtenez l'$[red]Arc du Héros$[white]!$0
Dans le menu $[yellow]pause$[white], écran $[blue]Inventaire$[white],
assignez l'arc grâce aux touches $[red]$(item_1)$[white]
ou $[red]$(item_2)$[white].

And also, it's cheap stuff, you don't need to recreate a surface
Code: Lua
  1.  elseif current_char == "(" then
  2.             -- Predefined text (an input for example).
  3.             local next_char = line:sub(self.char_index, self.char_index)
  4.             -- The syntax is "$(text)".
  5.             local right_position = line:find (")", self.char_index, true)
  6.             local text = line:sub(self.char_index, right_position - 1)
  7.             self.char_index = right_position + 1
  8.                
  9.                 -- Is the text a valid savegame value ?
  10.                 if game:get_value(text) ~= nil then
  11.                   text = game:get_value(text)
  12.                 end
  13.                        
  14.         -- Using $(item_1) or such (warning, do not use a savagame value), as it is in the table bellow, will display a pre-defined text_properties
  15.         -- with as value keyboard / joypad binding             
  16.                 local actions = {"item_1", "item_2", "action", "attack", "pause", "up", "down", "left", "right"}
  17.             for i = 1, #actions do
  18.                   if text == actions[i] then
  19.                     text = game:get_command_keyboard_binding(text) .. " / " .. game:get_command_joypad_binding(text)
  20.                   end
  21.                 end
  22.                 self:set_text(text)

You just need
Code: Lua
  1. function dialog_box:set_text(text)
  2.     local current_line = self.current_line_surface[self.line_index]
  3.     current_line:set_text(current_line:get_text() .. text)
  4.   end

Another example of a clever usage
(http://i.imgur.com/SJPCDk3.png)

$v is already used by "Skulltula d'Or"(the object caption, so when translating, the item name will be already translated), so the item dialog is.
Code: [Select]
$[red]- $v -$[white]
On dit que ces $[yellow]$v$[white] ont
la possibilité de détruire des malédictions.
Vous en avez tué $[red]$(amount_of_skulltulas)$[white] sur 100 !

The value of killed skulltulas is parsed from the code above

The next cool stuff to add is icons in texts
Title: Re: About color text dialogs
Post by: Diarandor on April 17, 2017, 04:44:21 pm
I agree with @llamazing and @MetalZelda that putting names to new text surfaces in the dialog_box is really unnecessary. The idea I had in mind when I coded that was to allow to go back to the previous text surface if needed, to reduce the number of surfaces, but since the dialog box is small we should not worry about this kind of things. Better to reduce the syntax as the ones you use.

A good idea, and probably a better syntax, would be allowing to call functions in dialogs. So I propose a slight modification of the same syntax, which is even shorter:
Code: [Select]
$function_identifier
The functions associated to each "function_identifier" would be defined in the dialog box as usual: "dialog_box:function_name()".

To avoid using long function names in the dialog box (the syntax would be too long) and at the same time keep the long name in the definition of the functions of the form "dialog_box:function_name()" (which is clearer), we could use a short identifier after the dollar symbol "$" instead of the name of the function. For this purpose, another function "dialog_box:start_function(short_id, parameters)" would be needed, just to start the convenient function assotiated to that "short id" used in the syntax.

Furthermore, to keep the dialog as clean as possible, the parameters of each function should better be given as properties of the dialog and not in the middle of the text. For instance, if the color is changed 3 times in a dialog, we would define an array of color properties, and each time $c is called, the next color of the array would be applied.

Remark: $c could be used to call a function "dialog_box:set_color(color)". This function should be overloaded to be compatible too with this other useful syntax: "dialog_box:set_color(r, g, b)", whose parameters would be sent as strings and then "dialog_box:set_color(r, g, b)" would first convert the three strings into integers and then make the color change.

An example to change color and a shaking effect:
dialog{
  id = "_cannot_lift_too_heavy",
  skip = "all",
  color = {"red", "white", {200, 0, 100}},
  movement = {{"horizontal", "fast"}, nil, {"vertical", "slow"}, nil},
  text = [[
Oh là là, c'est l'$camour$c !

$cWe will $mshake$m and $mbounce$m !
]]
}

I propose some short function ids (i.e., for the dialog syntax):

$0, $1, $2, $3, etc: as usual, for the "text speed"
$c: change color; allows color_id_string  or (r, g, b) as parameters
$s: change the size of the text; integer parameter
$f: change the font type; font_id_string parameter
$m: movements and shaking effects; parameters: movement_type_string, and other optional_parameters
$d: "dynamic" (i.e., continuous) color changes (rainbow color-shift, etc). parameters: effect_id_string, and others
$b: change the "beeping" sounds, which may be different for different NPCs, etc; parameter: sound_id_string
$i: draw image/icon (the width may be given as parameter if necessary). parameters: image_id_string, etc

If you have more ideas for other different effects that we may implement, or a suggestion for a different syntax, we can discuss it.

A different syntax, much clearer for translators and easier to read, but harder to code (because there could be a "nested" use), would be to use "{", "}" symbols (these could be optional) to indicate where the effects will be applied. For instance:
blablabla this $c{word} and $c{this} are in red.
Another example:
dialog{
  id = "_cannot_lift_too_heavy",
  skip = "all",
  color = {"red", {200, 0, 100}},
  movement = {{"horizontal", "fast"}, {"vertical", "slow"}},
  text = [[
Oh là là, c'est l'$c{amour} !

We will $c{$m{shake} and $m{bounce}} !
]]
}
Title: Re: About color text dialogs
Post by: MetalZelda on April 17, 2017, 06:53:25 pm
That could be cool, but it could also be tricky, if we use a lot of texts effects (using different colors in the same line for example), but I agree that text properties should be exploited.

I should also give these idea to exploit the text properties, it will make things better and easier, since I am, in parallel to y project, porting the Project Zelda Engine from RPG Maker to Solarus

  -> Dialog Box style (aka graphics), allow to define at the start of the text the dialog box graphics, automatically reset to "default" at the end of the dialog (https://www.youtube.com/watch?v=6u20RV_GwzE)
  -> Dialog Box positionning, sometimes, the dialogbox can clip automatically depending on the hero position or other stuffs, this parameter will set the position of this dialog, no matter the hero position or such
  -> Bank system (Idea from Zefk, http://forum.solarus-games.org/index.php/topic,806.0.html), where the system will be triggered by a text property and integrated entirely in the Dialog box script.
Title: Re: About color text dialogs
Post by: Diarandor on April 17, 2017, 07:05:49 pm
What do you think would be better of these options for the dialog box script? (I mean, for a new script that I will make.)
Non-nested properties (as the ones you use)? Or nested ones (like the ones of the end of my last comment)?
Title: Re: About color text dialogs
Post by: MetalZelda on April 17, 2017, 07:14:30 pm
I think both of our idea will be useful for other, dialog style and positionning is kinda easy to do

Code: Lua
  1. if dialog.position then
  2.           local pos = dialog.position  
  3.           if pos == "top" then
  4.             y = 24
  5.       elseif pos == "middle" then
  6.         y = 88
  7.       else
  8.         y = 144
  9.           end
  10.           self.box_dst_position.y = y
  11.         end

Of course, this example assume that you are constantly using a 240 height resolution

Code: Lua
  1.         if dialog.style then
  2.           game:set_dialog_style(dialog.style)
  3.         end

game:set_dialog_style (if not defined) just change and reload a surface.
Title: Re: About color text dialogs
Post by: wrightmat on April 17, 2017, 09:08:14 pm
MetalZelda, I added the dialog_style options to my dialog box - I actually had forgotten this wasn't standard.
Code: Lua
  1. function game:set_dialog_style(style)
  2.   dialog_box.style = style
  3.   if style == "wood" then
  4.     dialog_box.box_img = sol.surface.create("hud/dialog_box_wood.png")
  5.     dialog_box.end_lines_sprite:set_animation("wood")
  6.   elseif style == "stone" then
  7.     dialog_box.box_img = sol.surface.create("hud/dialog_box_stone.png")
  8.     dialog_box.end_lines_sprite:set_animation("stone")
  9.   else
  10.     dialog_box.box_img = sol.surface.create("hud/dialog_box.png")
  11.     dialog_box.end_lines_sprite:set_animation("default")
  12.   end
  13. end

I also recently added the ability to pass, for example, an NPC name to the dialog box so it would display above it. This might be a useful feature. I also know someone (maybe it was Diarandor?) added NPC images to the dialog box, which could be a good standard feature.
Title: Re: About color text dialogs
Post by: MetalZelda on April 17, 2017, 09:39:07 pm
MetalZelda, I added the dialog_style options to my dialog box - I actually had forgotten this wasn't standard.
Code: Lua
  1. function game:set_dialog_style(style)
  2.   dialog_box.style = style
  3.   if style == "wood" then
  4.     dialog_box.box_img = sol.surface.create("hud/dialog_box_wood.png")
  5.     dialog_box.end_lines_sprite:set_animation("wood")
  6.   elseif style == "stone" then
  7.     dialog_box.box_img = sol.surface.create("hud/dialog_box_stone.png")
  8.     dialog_box.end_lines_sprite:set_animation("stone")
  9.   else
  10.     dialog_box.box_img = sol.surface.create("hud/dialog_box.png")
  11.     dialog_box.end_lines_sprite:set_animation("default")
  12.   end
  13. end

I also recently added the ability to pass, for example, an NPC name to the dialog box so it would display above it. This might be a useful feature. I also know someone (maybe it was Diarandor?) added NPC images to the dialog box, which could be a good standard feature.

You are right, yet, I explained that set_dialog_style only recreate a new surface with a different graphic  :P
Title: Re: About color text dialogs
Post by: Diarandor on April 17, 2017, 09:48:09 pm
@wrightmat: Yes, I modified Christopho's script to allow displaying a sprite and choosing its animation.
Your idea that allows passing the name of the NPC is really good too; it is a nice feature to add to the scripts.
Title: Re: About color text dialogs
Post by: llamazing on April 22, 2017, 04:58:49 am
I also suggest adding a horizontal text alignment thing like $vertical{"center"}

An example more in-line with what I posted earlier would be something more like the following, using $a for horizontal alignment:
Code: [Select]
$a{center}centered text$a0
Although horizontal alignment is a tricky one because it doesn't really make sense to have more than one alignment style per line. Maybe alignment settings should be ignored unless specified at the beginning of a line/paragraph?

Also, horizontal alignment is very doable, but I'm not sure how vertical alignment would work, since isn't each line sized vertically to fit the text anyway? Maybe if you were using multiple font sizes on a single line? Or perhaps you mean to vertically align an entire paragraph of text relative to the text box?



It would be very useful too to add a feature that manages the change of line of the dialog box if the max lenght of one line is given. I don't have time these days to work on this, though.

My Cythera dialog script does this.



There is still the spacing problem if you use a special characters such as é, è, ç, à and Asian type characters

My Cythera dialog script seemed to work just fine with the European accents. I didn't try Asian characters, but that would only be a problem if the characters exceeded the bounds specified by text_surface:get_size().



Also, another cool feature you could add to your dialogbox script is savegame value parsing.

In keeping with the other notation, I'd suggest $g for savegame variables, e.g.:
Code: [Select]
assignez l'arc grâce aux touches $c{red}$g{item_1}$c{white}
ou $c{red}$g{item_2}$c{white}.

Also, there's no reason the dialog has to be limited to only one instance of $v. I allowed multiple in my Cythera dialog script.



What do you think would be better of these options for the dialog box script? (I mean, for a new script that I will make.)
Non-nested properties (as the ones you use)? Or nested ones (like the ones of the end of my last comment)?

I can't say I'm a fan of the nested notation. It would be burdensome with lots of different values in a single dialog and potentially confusing to translators.

Another advantage to using the non-nested notation is that it works better with dynamic text. For example, say the player is selling their items at an item shop. A dialog may be something like "You sold the Hero Shield for 15g", which could be coded like:
Code: [Select]
"You sold the $v for $c{yellow}$vg$c0"
Then you could have strings.dat entries defining item names like so:
Code: [Select]
text{ key="item_hero_shield", value="$c{green}Hero Shield$c0"}
text{ key="item_ice_rod", "value="$c{blue}Ice Rod$c0"}

In this example, different items have different colors, so the color to use is dynamic and depends on which item the player sells. Also note that the color gets defined by the strings.dat entry rather than the dialogs.dat text.

As for the functions calls idea, it could work with the shorthand notation, but the parsing full function names becomes much trickier and is error prone if the function name is typo'ed, for example.
Title: Re: About color text dialogs
Post by: Neovyse on April 22, 2017, 12:33:36 pm
Instead of rechoosing whiteafter changing color, you could choose default. So that, if the default color of the text is black (for example) it will become black again. For portabilty, it may be easier.