About dialog options and templates

Started by Chomba, Tue 06/07/2021 01:11:46

Previous topic - Next topic

Chomba

Hello again,
This is perhaps a complicated query, or a simple one... I don't know, but it's something I haven't been getting good results with.

I'm using the BASS template in version 3.6.0

I'm not really fond of the way the dialog options are displayed in this template, I'd prefer something with a fixed size and a couple of up and down arrows, more like the one in the thimbleweed template.

At one point I used a "gui" (it was a black rectangle with transparency) for the dialogue options, but if I exceeded the number of options that went in, I had no way of accessing the rest.

I was trying to use some modules but I didn't have much success and most of them have command compatibility problems (one I was able to get working but I didn't like it).

I saw that there is a section in the manual dedicated to this, but I honestly can't understand it (AGS and this game are my first approach to anything related to the programming world).

My main queries would be:

* Is there any way to export the way to handle the thimbleweed template dialog options and use it in the BASS template?

* Is there a relatively simple way to put scrolling arrows in a custom gui (I saw a module that did this, but all the dialog had to be written in the global code and it was a major problem)?

* Is there any way, as a last resort, to use the BASS template as is, but make the background colour of the dialog options transparent?

eri0o

#1
Hey, Chomba! Custom Dialog Rendering is something I had a hard time too to understand but I did eventually, I will add the manual page below for reference.

https://adventuregamestudio.github.io/ags-manual/CustomDialogOptions.html

Now, let's try to work with them, ok?


  • dialog_options_get_dimensions -> this is used to pass the size of the rectangle that will be on screen with the options inside, and it's position too.
  • dialog_options_render -> If something changed or there's a need to redraw, ags calls this function to draw the dialog options.
  • dialog_options_repexec -> this will always run when the dialog is shown on screen, you can use to update the things on screen.

with that said, let's start to make this work. First, on the editor, create a new script module, let's work in a clean .asc file ok? let's write the following code:
Code: ags

// new module script
function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{

}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{

}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{

}


Spoiler
[close]

this is the minimal skeleton we need right now.

Now, let's create a dialog that we can use to test this.
Spoiler
[close]

On the room, we need to wire this dialog to an interaction.
Spoiler

[close]

If all went well, you have the following
Spoiler
[close]

Now it's time to write the code of the dialog rendering. I will copy and paste a bit from the manual for lazyness...
Spoiler
[close]

If you try to run now, your dialog options have disappeared, well, AGS now expects you to provide the rendering code, so time to do that. Let's fill the surface with a color just so we can see it.
Spoiler
Code: ags
// new module script
function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 200;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  info.Surface.Clear(41355);
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{

}

[close]

Right, so we need to draw this rectangle with a transparency, so let's do that.
Spoiler
Code: ags
// new module script
function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 200;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(41355);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 50);
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{

}
[close]


Now we can copy paste bits from the manual to get some text here...
Spoiler
Code: ags
// new module script
function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 200;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(41355);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 50);
  
  int ypos = 0;
  // Render all the options that are enabled
  for (int i = 1; i <= info.DialogToRender.OptionCount; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (info.ActiveOptionID == i)
        info.Surface.DrawingColor = 58923;
      else
        info.Surface.DrawingColor = 58511;

      info.Surface.DrawStringWrapped(5, ypos, info.Width - 10,
              eFontFont0, eAlignLeft, info.DialogToRender.GetOptionText(i));
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
    }
  }
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{

}
[close]

OK, so let's do some adjustments so we can get arrows rendered, we will figure interaction later. The idea here is getting there visually. I am using two arrows that are already in the template.
I am also going to create a little struct just to help me store the things we will interact. I am also reducing the size of the rectangle we are drawing just to make showcasing the scrolling easier.
Spoiler
Code: ags
// new module script
struct Rect {
  int x, y, w, h, Graphic;
};
Rect arrow_up;
Rect arrow_down;

function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 60;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
  arrow_up.w = 32;
  arrow_up.h = 27;
  arrow_up.x = info.Width - arrow_up.w;
  arrow_up.y = 0;
  arrow_up.Graphic = 2147;
  arrow_down.w = 32;
  arrow_down.h = 27;
  arrow_down.x = info.Width - arrow_down.w;
  arrow_down.y = info.Height - arrow_down.h;
  arrow_down.Graphic = 2144;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(41355);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 50);
  info.Surface.DrawImage(arrow_up.x, arrow_up.y, arrow_up.Graphic, 50);
  info.Surface.DrawImage(arrow_down.x, arrow_down.y, arrow_down.Graphic, 50);
  
  int ypos = 0;

  // Render all the options that are enabled
  for (int i = 1; i <=info.DialogToRender.OptionCount ; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (info.ActiveOptionID == i)
        info.Surface.DrawingColor = 58923;
      else
        info.Surface.DrawingColor = 58511;

      info.Surface.DrawStringWrapped(5, ypos, info.Width - 10,
              eFontFont0, eAlignLeft, info.DialogToRender.GetOptionText(i));
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
    }
  }
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  
}
[close]

OK, now we are going to add a little of interaction. The general gist is we need to make the up and down arrow clickable.

  • we will create an int to store our scroll position, it's called scroll
  • we will create two functions, ScrollUp and ScrollDown, for up and down in this scroll - this makes the code more readable and we can repurpose those later for keyboard support.
  • we will add a new callback event, dialog_options_mouse_click, for detecting clicks
  • and in this function, we will detect if the rectangle area of either arrow buttons are clicked, when they are, we will call the required functions

Spoiler
Code: ags
// new module script
struct Rect {
  int x, y, w, h, Graphic;
};
Rect arrow_up;
Rect arrow_down;
int scroll;
int option_count;

function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 60;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
  arrow_up.w = 32;
  arrow_up.h = 27;
  arrow_up.x = info.Width - arrow_up.w;
  arrow_up.y = 0;
  arrow_up.Graphic = 2147;
  arrow_down.w = 32;
  arrow_down.h = 27;
  arrow_down.x = info.Width - arrow_down.w;
  arrow_down.y = info.Height - arrow_down.h;
  arrow_down.Graphic = 2144;
  scroll = 0;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(41355);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 50);
  info.Surface.DrawImage(arrow_up.x, arrow_up.y, arrow_up.Graphic, 50);
  info.Surface.DrawImage(arrow_down.x, arrow_down.y, arrow_down.Graphic, 50);
  
  int ypos = 0;
  option_count = info.DialogToRender.OptionCount;
  if (option_count>4) option_count = 4;

  // Render all the options that are enabled
  for (int i = 1+scroll; i <=option_count+scroll ; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (info.ActiveOptionID == i)
        info.Surface.DrawingColor = 58923;
      else
        info.Surface.DrawingColor = 58511;

      info.Surface.DrawStringWrapped(5, ypos, info.Width - 10,
              eFontFont0, eAlignLeft, info.DialogToRender.GetOptionText(i));
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
    }
  }
}

void ScrollDown(int max_opt) {
  scroll+=1;
  if((scroll + option_count) > max_opt) scroll = max_opt - option_count;
}

void ScrollUp() {
  scroll-=1;
  if(scroll < 0) scroll = 0;
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  
}

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
  int d_x = info.X;
  int d_y = info.Y;
  if(button == eMouseLeft) {
    if(mouse.x > arrow_up.x + d_x && mouse.x < d_x + arrow_up.x + arrow_up.w &&
       mouse.y > arrow_up.y + d_y && mouse.y < d_y + arrow_up.y + arrow_up.h) 
    {
      ScrollUp();
      info.Update();
    }
    
    if(mouse.x > d_x + arrow_down.x && mouse.x < d_x + arrow_down.x + arrow_down.w &&
       mouse.y > d_y + arrow_down.y && mouse.y < d_y + arrow_down.y + arrow_down.h) 
    {
      ScrollDown(info.DialogToRender.OptionCount);
      info.Update();
    }
  }
}
[close]


And now comes the interaction stuff... Please let me know if this is making sense.  (laugh)

Chomba

Wow, eri0o!

Thank you so much for taking the time to make such an elaborate response! I'm going to get on it and let you know how it went!

Again, thank you so much for taking the time to answer my question  :grin:!

Chomba

Ok, so far so good!



I would be lying if I told you that I understand exactly what each line of code does or that I understand how each command works. But I'm starting to understand what small sets of code do!
The step by step is very helpful to understand all this!

eri0o

#4
Cool!

Let's rool a bit more. Your dialog_options_repexec should be empty yet. We are gonna fill it! It's almost going to be a copy paste of what's on the manual...

Code: ags
function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  info.ActiveOptionID = 0;
  if (mouse.y < info.Y || mouse.y >= info.Y + info.Height ||
      mouse.x < info.X || mouse.x >= info.X + info.Width) // look at me next time I show this
  {
    return; // return if the mouse is outside UI bounds
  }

  int ypos = 0;
  // Find the option that corresponds to where the mouse cursor is
  for (int i = 1+scroll; i <=option_count+scroll; i++)  // <<--- THIS IS DIFFERENT FROM THE MANUAL, the scroll here allows... scrolling.
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
      if ((mouse.y - info.Y) < ypos)
      {
        info.ActiveOptionID = i;
        return;
      }
    }
  }
}


so the basic difference here is that we only want that for to traverse the options we have on the section the scroll is active. Full code is under spoiler.
Spoiler
Code: ags
// new module script
struct Rect {
  int x, y, w, h, Graphic;
};
Rect arrow_up;
Rect arrow_down;
int scroll;
int option_count;

function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 60;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
  arrow_up.w = 32;
  arrow_up.h = 27;
  arrow_up.x = info.Width - arrow_up.w;
  arrow_up.y = 0;
  arrow_up.Graphic = 2147;
  arrow_down.w = 32;
  arrow_down.h = 27;
  arrow_down.x = info.Width - arrow_down.w;
  arrow_down.y = info.Height - arrow_down.h;
  arrow_down.Graphic = 2144;
  scroll = 0;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(41355);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 50);
  info.Surface.DrawImage(arrow_up.x, arrow_up.y, arrow_up.Graphic, 50);
  info.Surface.DrawImage(arrow_down.x, arrow_down.y, arrow_down.Graphic, 50);
  
  int ypos = 0;
  option_count = info.DialogToRender.OptionCount;
  if (option_count>4) option_count = 4;

  // Render all the options that are enabled
  for (int i = 1+scroll; i <=option_count+scroll ; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (info.ActiveOptionID == i)
        info.Surface.DrawingColor = 58923;
      else
        info.Surface.DrawingColor = 58511;

      info.Surface.DrawStringWrapped(5, ypos, info.Width - 10,
              eFontFont0, eAlignLeft, info.DialogToRender.GetOptionText(i));
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
    }
  }
}

void ScrollDown(int max_opt) {
  scroll+=1;
  if((scroll + option_count) > max_opt) scroll = max_opt - option_count;
}

void ScrollUp() {
  scroll-=1;
  if(scroll < 0) scroll = 0;
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  info.ActiveOptionID = 0;
  if (mouse.y < info.Y || mouse.y >= info.Y + info.Height ||
      mouse.x < info.X || mouse.x >= info.X + info.Width)
  {
    return; // return if the mouse is outside UI bounds
  }

  int ypos = 0;
  // Find the option that corresponds to where the mouse cursor is
  for (int i = 1+scroll; i <=option_count+scroll; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
      if ((mouse.y - info.Y) < ypos)
      {
        info.ActiveOptionID = i;
        return;
      }
    }
  }
}

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
  int d_x = info.X;
  int d_y = info.Y;
  if(button == eMouseLeft) {
    if(mouse.x > arrow_up.x + d_x && mouse.x < d_x + arrow_up.x + arrow_up.w &&
       mouse.y > arrow_up.y + d_y && mouse.y < d_y + arrow_up.y + arrow_up.h) 
    {
      ScrollUp();
      info.Update();
    }
    
    if(mouse.x > d_x + arrow_down.x && mouse.x < d_x + arrow_down.x + arrow_down.w &&
       mouse.y > d_y + arrow_down.y && mouse.y < d_y + arrow_down.y + arrow_down.h) 
    {
      ScrollDown(info.DialogToRender.OptionCount);
      info.Update();
    }
  }
}
[close]

If everything is right, you should see that the option your mouse is over gets highlighted.


Now you need to actually make the dialog interactive! This is super easy, we just need to see if any option is active, and if one is, we will run it!
Code: ags
    if (info.ActiveOptionID > 0) {
      info.RunActiveOption();
    }


We need to add this code on dialog_options_mouse_click.

But if you do that, you will notice you can't scroll anymore... This is because the active region we made before considers the whole width of the dialog. So we need to reduce this width to account for the arrows we have in place.

Code: ags
function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  info.ActiveOptionID = 0;
  if (mouse.y < info.Y || mouse.y >= info.Y + info.Height ||
      mouse.x < info.X || mouse.x >= info.X + info.Width - arrow_down.w) /* <<--- this is the change! */
....


Now if everything is right we have this!


Spoiler
Code: ags
// new module script
struct Rect {
  int x, y, w, h, Graphic;
};
Rect arrow_up;
Rect arrow_down;
int scroll;
int option_count;

function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 60;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
  arrow_up.w = 32;
  arrow_up.h = 27;
  arrow_up.x = info.Width - arrow_up.w;
  arrow_up.y = 0;
  arrow_up.Graphic = 2147;
  arrow_down.w = 32;
  arrow_down.h = 27;
  arrow_down.x = info.Width - arrow_down.w;
  arrow_down.y = info.Height - arrow_down.h;
  arrow_down.Graphic = 2144;
  scroll = 0;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(41355);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 50);
  info.Surface.DrawImage(arrow_up.x, arrow_up.y, arrow_up.Graphic, 50);
  info.Surface.DrawImage(arrow_down.x, arrow_down.y, arrow_down.Graphic, 50);
  
  int ypos = 0;
  option_count = info.DialogToRender.OptionCount;
  if (option_count>4) option_count = 4;

  // Render all the options that are enabled
  for (int i = 1+scroll; i <=option_count+scroll ; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (info.ActiveOptionID == i)
        info.Surface.DrawingColor = 58923;
      else
        info.Surface.DrawingColor = 58511;

      info.Surface.DrawStringWrapped(5, ypos, info.Width - 10,
              eFontFont0, eAlignLeft, info.DialogToRender.GetOptionText(i));
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
    }
  }
}

void ScrollDown(int max_opt) {
  scroll+=1;
  if((scroll + option_count) > max_opt) scroll = max_opt - option_count;
}

void ScrollUp() {
  scroll-=1;
  if(scroll < 0) scroll = 0;
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  info.ActiveOptionID = 0;
  if (mouse.y < info.Y || mouse.y >= info.Y + info.Height ||
      mouse.x < info.X || mouse.x >= info.X + info.Width - arrow_down.w)
  {
    return; // return if the mouse is outside UI bounds
  }

  int ypos = 0;
  // Find the option that corresponds to where the mouse cursor is
  for (int i = 1+scroll; i <=option_count+scroll; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
      if ((mouse.y - info.Y) < ypos)
      {
        info.ActiveOptionID = i;
        return;
      }
    }
  }
}

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
  int d_x = info.X;
  int d_y = info.Y;
  if(button == eMouseLeft) {
    if(mouse.x > arrow_up.x + d_x && mouse.x < d_x + arrow_up.x + arrow_up.w &&
       mouse.y > arrow_up.y + d_y && mouse.y < d_y + arrow_up.y + arrow_up.h) 
    {
      ScrollUp();
      info.Update();
    }
    
    if(mouse.x > d_x + arrow_down.x && mouse.x < d_x + arrow_down.x + arrow_down.w &&
       mouse.y > d_y + arrow_down.y && mouse.y < d_y + arrow_down.y + arrow_down.h) 
    {
      ScrollDown(info.DialogToRender.OptionCount);
      info.Update();
    }
    
    if (info.ActiveOptionID > 0) {
      info.RunActiveOption();
    }
  }
}
[close]


And that is it, you can customize this, use a font that automatic borders, change colors of things, make the graphics of the arrows change when the mouse is over or when click is held... The possibilities are endless!
Spoiler
like this is a change just to make the buttons a little nicer...

Code: ags
// new module script
struct Rect {
  int x, y, w, h, Graphic;
};
Rect arrow_up;
Rect arrow_down;
int scroll;
int option_count;

bool IsMouveOverScrollUp(int d_x, int d_y) {
  return (mouse.x > arrow_up.x + d_x && mouse.x < d_x + arrow_up.x + arrow_up.w &&
       mouse.y > arrow_up.y + d_y && mouse.y < d_y + arrow_up.y + arrow_up.h);
}

bool IsMouseOverScrollDown(int d_x, int d_y) {
  return (mouse.x > d_x + arrow_down.x && mouse.x < d_x + arrow_down.x + arrow_down.w &&
       mouse.y > d_y + arrow_down.y && mouse.y < d_y + arrow_down.y + arrow_down.h);
}

void ScrollDown(int max_opt) {
  scroll+=1;
  if((scroll + option_count) > max_opt) scroll = max_opt - option_count;
}

void ScrollUp() {
  scroll-=1;
  if(scroll < 0) scroll = 0;
}


function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 50;
  info.Y = 100;
  info.Width = 200;
  info.Height = 60;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
  arrow_up.w = 32;
  arrow_up.h = 27;
  arrow_up.x = info.Width - arrow_up.w;
  arrow_up.y = 0;
  arrow_up.Graphic = 2147;
  arrow_down.w = 32;
  arrow_down.h = 27;
  arrow_down.x = info.Width - arrow_down.w;
  arrow_down.y = info.Height - arrow_down.h;
  arrow_down.Graphic = 2144;
  scroll = 0;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(41355);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 50);  
  info.Surface.DrawImage(arrow_up.x, arrow_up.y, arrow_up.Graphic, 0);
  info.Surface.DrawImage(arrow_down.x, arrow_down.y, arrow_down.Graphic, 0);
  
  int ypos = 0;
  option_count = info.DialogToRender.OptionCount;
  if (option_count>4) option_count = 4;

  // Render all the options that are enabled
  for (int i = 1+scroll; i <=option_count+scroll ; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (info.ActiveOptionID == i)
        info.Surface.DrawingColor = 58923;
      else
        info.Surface.DrawingColor = 58511;

      info.Surface.DrawStringWrapped(5, ypos, info.Width - 10,
              eFontFont0, eAlignLeft, info.DialogToRender.GetOptionText(i));
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
    }
  }
}


function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  int d_x = info.X;
  int d_y = info.Y;
  info.ActiveOptionID = 0;
  
  if(IsMouveOverScrollUp(d_x, d_y)) { 
    if(arrow_up.Graphic != 2148) { 
      arrow_up.Graphic = 2148; 
      info.Update();
    }
  }
  else { 
    if(arrow_up.Graphic != 2147) { 
      arrow_up.Graphic = 2147; 
      info.Update();
    }
  } 
  if(IsMouseOverScrollDown(d_x, d_y)) { 
    if(arrow_down.Graphic != 2145) { 
      arrow_down.Graphic = 2145; 
      info.Update();
    }
  }
  else { 
    if(arrow_down.Graphic != 2144) {
      arrow_down.Graphic = 2144;
      info.Update();
    }
  } 
  
  if (mouse.y < info.Y || mouse.y >= info.Y + info.Height ||
      mouse.x < info.X || mouse.x >= info.X + info.Width - arrow_down.w)
  {
    return; // return if the mouse is outside UI bounds
  }
  

  int ypos = 0;
  // Find the option that corresponds to where the mouse cursor is
  for (int i = 1+scroll; i <=option_count+scroll; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
      if ((mouse.y - info.Y) < ypos)
      {
        info.ActiveOptionID = i;
        return;
      }
    }
  }
}

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
  int d_x = info.X;
  int d_y = info.Y;
  if(button == eMouseLeft) {
    if(IsMouveOverScrollUp(d_x, d_y)) 
    {
      ScrollUp();
      info.Update();
    }
    
    if(IsMouseOverScrollDown(d_x, d_y)) 
    {
      ScrollDown(info.DialogToRender.OptionCount);
      info.Update();
    }
    
    if (info.ActiveOptionID > 0) {
      info.RunActiveOption();
    }
  }
}

[close]

Now I notice maybe this could be copied in the wiki and someone could improve this as a step by step if it makes sense but I will leave this to others.

I fully recommend experimenting with dialog options and it's custom rendering system, it's a bit hard at first but it has lots of possibilities and you can do really amazingly neat stuff with it!

Chomba

the Gif runs very fast, but...

[imgzoom]https://i.imgur.com/cMFvXiP.gif[/imgzoom]

Now I'm going to customize it!
If all goes well, I'll send you later how it turned out haha

Chomba

Well, I was able to move forward to a certain point and got stuck!

(Here, a screenshot of what I was able to achieve)

[imgzoom]https://i.imgur.com/le8ljcP.png[/imgzoom]

I managed to set it to the dimensions I wanted, change the font (which I discovered I had to change from two different places in the code, otherwise weird things would happen), the background colour, change the graphics of the arrows (and their dimensions), the font colour, how far the line of written text could go and the distance between one line of dialogue and the next.

It may not be much, but for me it's quite an achievement :D

What I couldn't get is to make the arrows change graphics when the mouse passes over them or when they are pressed.

The closest I could get is that pressing the mouse over the image of the arrow changes it, but it doesn't go back to the original graphic.

For this I used the command

Code: ags
arrow_up.Graphic = 2149;
// is the predefined graphic of the pressed up arrow


in the section of

Code: ags
function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)


I tried several ways (I didn't keep track) and placing it in different parts of the subsequent code, but I couldn't achieve another effect, I wanted to use the "Wait" command (to wait a few milliseconds and go back to the other graphic), but of course it didn't work haha.

I also tried using

Code: ags
Mouse.IsButtonDown


I did it in different ways, but I always got the same result, that the arrow is pressed, but stays in that graphic (until I select a dialog option and it resets).


-------------------------------
Extra points:

Spoiler
I also had another problem, when I wanted to make the system but only with 3 lines, where the dialogue options were being removed when the character said them.
What happened was that at the beginning everything was fine, I chose one, it disappeared and the others moved up, but after choosing the second one (out of 4 in total), the last option was separated two spaces from the previous one...
When I did the 4-line option system this didn't happen.

In the end I decided to go for the 4-line system anyway, but it would be good to know why this could be happening.

the (recreated) code would look something like this

Code: ags

// new module script


struct Rect {
  int x, y, w, h, Graphic;
};
Rect arrow_up;
Rect arrow_down;
int scroll;
int option_count;

 
function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 200x200 dialog options area at (50,100)
  info.X = 0;
  info.Y = 158;
  info.Width = 320;
  info.Height = 42;
  // Enable alpha channel for the drawing surface
  info.HasAlphaChannel = true;
  arrow_up.w = 24;
  arrow_up.h = 26;
  arrow_up.x = info.Width - arrow_up.w;
  arrow_up.y = 0;
  arrow_up.Graphic = 2147;
  arrow_down.w = 24;
  arrow_down.h = 26;
  arrow_down.x = info.Width - arrow_down.w;
  arrow_down.y = info.Height - arrow_down.h;
  arrow_down.Graphic = 2144;
  scroll = 0;
}
 
function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  DynamicSprite* spr = DynamicSprite.CreateFromDrawingSurface(info.Surface, 0, 0, info.Width, info.Height);
  DrawingSurface* surf = spr.GetDrawingSurface();
  surf.Clear(0);
  surf.Release();
  
  info.Surface.DrawImage(0, 0, spr.Graphic, 42);
  info.Surface.DrawImage(arrow_up.x, arrow_up.y, arrow_up.Graphic, 0);
  info.Surface.DrawImage(arrow_down.x, arrow_down.y, arrow_down.Graphic, 0);
  
  int ypos = 0;
  option_count = info.DialogToRender.OptionCount;
  if (option_count>3) option_count = 3;
 
  // Render all the options that are enabled
  for (int i = 1+scroll; i <=option_count+scroll ; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (info.ActiveOptionID == i)
              info.Surface.DrawingColor = 58923;
      else
        info.Surface.DrawingColor = 58511;
 
      info.Surface.DrawStringWrapped(5, ypos , info.Width - 10,
              eFontFont, eAlignLeft, info.DialogToRender.GetOptionText(i));
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont, info.Width - 10);
    }
  }
}
 
void ScrollDown(int max_opt) {
  scroll+=1;
  if((scroll + option_count) > max_opt) scroll = max_opt - option_count;
}
 
void ScrollUp() {
  scroll-=1;
  if(scroll < 0) scroll = 0;
}
 
function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
  info.ActiveOptionID = 0;
  if (mouse.y < info.Y || mouse.y >= info.Y + info.Height ||
      mouse.x < info.X || mouse.x >= info.X + info.Width - arrow_down.w)
  {
    return; // return if the mouse is outside UI bounds
  }
 
  int ypos = 0;
  // Find the option that corresponds to where the mouse cursor is
  for (int i = 1+scroll; i <=option_count+scroll; i++)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      ypos += GetTextHeight(info.DialogToRender.GetOptionText(i), eFontFont0, info.Width - 10);
      if ((mouse.y - info.Y) < ypos)
      {
        info.ActiveOptionID = i;
        return;
      }
    }
  }
  
}
 
function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
  int d_x = info.X;
  int d_y = info.Y;
  
  if(button == eMouseLeft) {
    if(mouse.x > arrow_up.x + d_x && mouse.x < d_x + arrow_up.x + arrow_up.w &&
       mouse.y > arrow_up.y + d_y && mouse.y < d_y + arrow_up.y + arrow_up.h) 
           
    {
      ScrollUp();
    
      info.Update(); 
    }
    
    if(mouse.x > d_x + arrow_down.x && mouse.x < d_x + arrow_down.x + arrow_down.w &&
       mouse.y > d_y + arrow_down.y && mouse.y < d_y + arrow_down.y + arrow_down.h) 
    {
      ScrollDown(info.DialogToRender.OptionCount);
      info.Update();
    }
    
    if (info.ActiveOptionID > 0) {
         info.RunActiveOption();
}}
}
[close]

Laura Hunt

Nota al margen: "alguna" no lleva tilde, y en ese contexto, "este" tampoco. Por otro lado, "por qué" debería llevarla ;)

eri0o

Chomba, I'm drunk and can't help now but I am happy seeing that game image!

Chomba

QuoteNota al margen: "alguna" no lleva tilde, y en ese contexto, "este" tampoco. Por otro lado, "por qué" debería llevarla ;)
Noted and correted!  I haven't done the spell check yet, to tell you the truth... but now I see with terrified eyes that I need it haha

QuoteChomba, I'm drunk and can't help now but I am happy seeing that game image!
HAHAHAHA I laughed out loud.
Good for you! the world of coding can wait haha

Chomba

QuoteWhat I couldn't get is to make the arrows change graphics when the mouse passes over them or when they are pressed.

The closest I could get is that pressing the mouse over the image of the arrow changes it, but it doesn't go back to the original graphic.

Hello again!

Could someone give me a hand with this part?
At least to know what commands I should use to achieve this effect. I think it's the only thing I'm missing to finish the base structure of the game :D

SMF spam blocked by CleanTalk