[SOLVED] How do I make the custom dialog options stay on screen while speech?

Started by bx83, Tue 27/03/2018 09:02:32

Previous topic - Next topic

bx83

I've made a custom dialog screen; however it dissappears while people are talking (while there's speech), then comes back on when speech is finished.
How can I make it stay up there always?

Khris

Check the GUI's Visibility setting, check General Settings -> Visual -> When player interface is disabled... and SetGameOption(OPT_WHENGUIDISABLED, ...) in the manual.

bx83

Setting either one, to any other option, does nothing.
My OPT_WHENGUIDISABLED was set to 2; setting it to something else did nothing.
The custom screen dissappears during speech.

Crimson Wizard

I do not think there is a way to keep dialog options shown, as far as I know this behavior is hardcoded.

Guess only way is to make secondary fake GUI with the necessary content and display it on same place.

...or completely custom dialogs, if that's worth it.

bx83

Okay I had the same idea by taking a "screenshot"/sprite of the custom options and then displaying them while speech happens;
BUT
Where do I put this code? I can't figure out the entrypoint/exitpoint for dialogues. Put it in the custom dialog_options_render function? When does the "speech_is_happening_now" moment actualy occur?

Crimson Wizard

Quote from: bx83 on Wed 28/03/2018 00:14:57
Where do I put this code? I can't figure out the entrypoint/exitpoint for dialogues. Put it in the custom dialog_options_render function? When does the "speech_is_happening_now" moment actualy occur?

The moment when you choose an option, this is right before you call RunActiveOption().
I never tried that myself, so idk if that will work.
Also, if it actually does, another good idea is to do this:
Code: ags

mouse.Visible = false;
Wait(1);
do screenshot
mouse.Visible = true;


EDIT: to think of it, you do not really have to make a screenshot, since you are already drawing custom options, you may repeat similar drawing on a fake GUI.

bx83

So uh... which function combination would be used for this?
GetFromBackground, DynamicSprite, CopySprite,...?

I mean, I know this is the advanced technical forum, but when it comes to graphics, it took me about 1 month to come up with this:

Code: ags

DynamicSprite *sprite = DynamicSprite.CreateFromExistingSprite(SLOT, true);  //safe closed
DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
    
sprite.Crop(mouse.x-65, mouse.y-65, 240, 240);
sprite.CopyTransparencyMask(SLOT);
  
surface.DrawImage(mouse.x-65, mouse.y-65, sprite.Graphic, 20);
      
surface.DrawImage(0, 0, SLOT, 90);            //safe closed
surface.Release();
sprite.Delete();


...to make a circle which saw into another background (another background, just that circle thing, like Sam & Max: Hit the Road).



Here's my custom dialog code btw:

Code: ags

function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  // Create a 1024x64 dialog options area at (0,704)
  info.X = 0;
  info.Y = 704;
  info.Width = 1024;
  info.Height = 64;
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
  int i = 1, ypos=0, xpos=0;
	info.Surface.Clear(15);	
	while (i <= info.DialogToRender.OptionCount)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
			String str = info.DialogToRender.GetOptionText(i);
			int cur_img = str.AsInt;
			info.Surface.DrawImage(xpos, ypos, cur_img);
			xpos+=64;
    }
    i++;
  }
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
	int i = 1,  xpos = 0;
  while (i <= info.DialogToRender.OptionCount)
  {
	 if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (mouse.y >= info.Y && mouse.x >= xpos && mouse.x <= xpos+64)
      {
        info.ActiveOptionID = i;
				return;
      }
			xpos+=64;
    }
    i++;
	}
}

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
	if (info.ActiveOptionID > 0) {
            //PUT SPRITE COPY CODE HERE
            info.RunActiveOption();
	}
}


It works out like this, with the options at the bottom rather than text:

Crimson Wizard

Welp! I feel this might be easy actually.

You already have a option drawing code in the dialog_options_render. So, following good coding traditions, pick it out in a separate function, which requires DrawingSurface pointer to draw upon:

Code: ags

// Note that although we are passing DialogOptionsRenderingInfo here, we also provide a separate
// DrawingSurface pointer. We do this to be able to draw on some other surface, not necessarily
// the one from the Info.
// 
void DrawDialogOptions(DrawingSurface *ds, DialogOptionsRenderingInfo *info)
{
  int i = 1, ypos=0, xpos=0;
  ds.Clear(15); // Notice we are using "ds" instead of "info.Surface" here!
                // and everywhere below too!
  while (i <= info.DialogToRender.OptionCount)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
                        String str = info.DialogToRender.GetOptionText(i);
                        int cur_img = str.AsInt;
                        ds.DrawImage(xpos, ypos, cur_img);
                        xpos+=64;
    }
    i++;
  }
}


Now you can call this same function in two ways: for the actual Dialog option GUI:
Code: ags

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
    // Just call the drawing function, making it draw on the correct surface taken from the Info.
    DrawDialogOptions(info.Surface, info);
}


And when option is selected, you draw this on a separate DynamicSprite:
Code: ags

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
        if (info.ActiveOptionID > 0) {
            //PUT SPRITE COPY CODE HERE
            DrawingSurface *ds = MyDynamicSpriteForTheFakeGUI.GetDrawingSurface();
            DrawDialogOptions(ds, info); // notice we are drawing same options, but on special surface now!
            ds.Release();
            info.RunActiveOption();
        }
}


So, obviously you need to have DynamicSprite *MyDynamicSpriteForTheFakeGUI declared in the script, and assigned to fake GUI as a background image.

bx83

Not quite understanding this:
Code: ags


function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
	if (info.ActiveOptionID > 0) {
		DynamicSprite *MyDynamicSpriteForTheFakeGUI = DynamicSprite.CreateFromBackground();  //???????
		DrawingSurface *ds = MyDynamicSpriteForTheFakeGUI.GetDrawingSurface();
		DrawDialogOptions(ds, info);
		ds.Release();
		info.RunActiveOption();
	}
}


Do you want it to create drawing surface so that... a drawing surface... can... ????
I know this is simple code but my brain get's pretty easily confused.

Anyway, the above code still doesn't work :/

Snarky

Quote from: bx83 on Wed 28/03/2018 05:59:30
Not quite understanding this:
Code: ags

		DynamicSprite *MyDynamicSpriteForTheFakeGUI = DynamicSprite.CreateFromBackground();  //???????

Yeah, I think that part is wrong. You don't necessarily want the GUI background to be the size of the room, you want it to be the size of the dialog GUI, and you certainly don't want to fill it with the room background. I would try:

Code: ags
    DynamicSprite *MyDynamicSpriteForTheFakeGUI = DynamicSprite.Create(info.Width, info.Height, true);


QuoteDo you want it to create drawing surface so that... a drawing surface... can... ????

The drawing surface gives you access to draw on something (in this case a sprite). This is how you show the dialog options: by drawing them and then displaying the resulting sprite.

QuoteAnyway, the above code still doesn't work :/

Did you do this part?

QuoteSo, obviously you need to have DynamicSprite *MyDynamicSpriteForTheFakeGUI declared in the script, and assigned to fake GUI as a background image.

(You also need to actually display that GUI during speech.)

bx83

Okay, still doesn't work.

How do I display the GUI during speech?

Snarky

Please be more specific. "Doesn't work" is not a useful description. When you're having problems, always describe:

-What you have done (in this case, what you've done differently than in previous attempts)
-What you expected to happen
-What did in fact happen

"How do I display the GUI during speech?" indicates that there's a step you don't know how to do, so what have you in fact done and what did you think it would do?

Let's not jump straight ahead to trying to get the whole thing working in one step. First, let's just check that you can display the fake dialog options GUI at all.

Let's say the fake GUI you've created is called gFakeDialogOptions, set to Visibility: Normal (initially off). Try this:

Code: ags
function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
        if (info.ActiveOptionID > 0) {
                DynamicSprite *MyDynamicSpriteForTheFakeGUI = DynamicSprite.Create(info.Width, info.Height, true);
                DrawingSurface *ds = MyDynamicSpriteForTheFakeGUI.GetDrawingSurface();
                DrawDialogOptions(ds, info);
                ds.Release();

                // Format our fake GUI to correspond to the real dialog options. This could probably go in dialog_options_get_dimensions() instead
                gFakeDialogOptions.X = info.X;
                gFakeDialogOptions.Y = info.Y;
                gFakeDialogOptions.Width = info.Width;
                gFakeDialogOptions.Height = info.Height;
                gFakeDialogOptions.Clickable = false;

                // Now display the fake GUI and run the conversation choice
                gFakeDialogOptions.BackgroundGraphic = MyDynamicSpriteForTheFakeGUI.Graphic;
                gFakeDialogOptions.Visible = true;
                info.RunActiveOption();
        }
}


This should now display the fake GUI during dialog after you make your first conversation choice (and never remove it, so it stays up for the rest of the game). If you get this working, we can move on to showing and hiding it more intelligently.

bx83

Quote-What you have done (in this case, what you've done differently than in previous attempts)
Wrote the code crimson wizard wrote.

Quote-What you expected to happen
A copy of the GUI would be displayed.

Quote-What did in fact happen
Selecting a question did the same as before; speech erased the dialogue options window, and it was only brought back when speech was over.
This happened with your code also.

QuoteLet's say the fake GUI you've created is called gFakeDialogOptions, set to Visibility: Normal (initially off). Try this:
How do you define the GUI? With 'GUI *gFakeDialogOptions = ???' or by designing a GUI with this name in the editor?

Still don't fully understand it; but copying all code as you write it.

Here's a video of what happens:
this

bx83

Quote-What you have done (in this case, what you've done differently than in previous attempts)
Wrote the code crimson wizard wrote.

Quote-What you expected to happen
A copy of the GUI would be displayed.

Quote-What did in fact happen
Selecting a question did the same as before; speech erased the dialogue options window, and it was only brought back when speech was over.
This happened with your code also.

QuoteLet's say the fake GUI you've created is called gFakeDialogOptions, set to Visibility: Normal (initially off). Try this:
How do you define the GUI? With 'GUI *gFakeDialogOptions = ???' or by designing a GUI with this name in the editor?

Still don't fully understand it; but copying all code as you write it.

Here's a video of what happens (by designing the GUI in the editor;
this

Snarky

QuoteHow do you define the GUI? With 'GUI *gFakeDialogOptions = ???' or by designing a GUI with this name in the editor?

The latter. If you haven't done that, the code should not compile, so there's something missing in your description.

Your second video shows that it's close to working. It looks like you're either showing the wrong GUI, drawing to the wrong GUI, or using the same GUI or dynamic sprite for the fake dialog options as for the speech bubble module.

bx83

Here's my code so far. I've created a GUI called gFakeDialogOptions in the editor.

Code: ags

function dialog_options_get_dimensions(DialogOptionsRenderingInfo *info)
{
  info.X = 0;
  info.Y = 704;
  info.Width = 1024;
  info.Height = 64;
}

function DrawDialogOptions(DrawingSurface *ds, DialogOptionsRenderingInfo *info)
{
  int i = 1, ypos=0, xpos=0;
  ds.Clear(15);
  while (i <= info.DialogToRender.OptionCount)
  {
    if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
			String str = info.DialogToRender.GetOptionText(i);
			int cur_img = str.AsInt;
			ds.DrawImage(xpos, ypos, cur_img);
			xpos+=64;
	}
    i++;
  }
}

function dialog_options_render(DialogOptionsRenderingInfo *info)
{
	DrawDialogOptions(info.Surface, info);
}

function dialog_options_repexec(DialogOptionsRenderingInfo *info)
{
	int i = 1,  xpos = 0;
  while (i <= info.DialogToRender.OptionCount)
  {
	 if (info.DialogToRender.GetOptionState(i) == eOptionOn)
    {
      if (mouse.y >= info.Y && mouse.x >= xpos && mouse.x <= xpos+64)
      {
        info.ActiveOptionID = i;
				return;
      }
			xpos+=64;
    }
    i++;
	}
}

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
	if (info.ActiveOptionID > 0) {
		DynamicSprite *MyDynamicSpriteForTheFakeGUI = DynamicSprite.Create(info.Width, info.Height, true);
		DrawingSurface *ds = MyDynamicSpriteForTheFakeGUI.GetDrawingSurface();
		DrawDialogOptions(ds, info);
		ds.Release();

		gFakeDialogOptions.X = info.X;
		gFakeDialogOptions.Y = info.Y;
		gFakeDialogOptions.Width = info.Width;
		gFakeDialogOptions.Height = info.Height;
		gFakeDialogOptions.Clickable = false;

		gFakeDialogOptions.BackgroundGraphic = MyDynamicSpriteForTheFakeGUI.Graphic;
		gFakeDialogOptions.Visible = true;
		info.RunActiveOption();
	}
}


QuoteYour second video shows that it's close to working. It looks like you're either showing the wrong GUI, drawing to the wrong GUI, or using the same GUI or dynamic sprite for the fake dialog options as for the speech bubble module.

None of these apply (I think; look at the code).
As for SpeechBubble (v0.8.0) using GUIs as well, perhaps there'e some cross-over? Though there's no GUI of the same name in SpeechBubble.

Snarky

No, unless you've done this there shouldn't be any overlap with GUIs in the SpeechBubble module.

I noticed that the MyDynamicSpriteForTheFakeGUI dynamic sprite is declared inside a function. It should be declared outside in order to be persistent, like so:

Code: ags
DynamicSprite *MyDynamicSpriteForTheFakeGUI;

function dialog_options_mouse_click(DialogOptionsRenderingInfo *info, MouseButton button)
{
  if (info.ActiveOptionID > 0) {
    *MyDynamicSpriteForTheFakeGUI = DynamicSprite.Create(info.Width, info.Height, true);
    DrawingSurface *ds = MyDynamicSpriteForTheFakeGUI.GetDrawingSurface();
    DrawDialogOptions(ds, info);
    ds.Release();

    gFakeDialogOptions.X = info.X;
    gFakeDialogOptions.Y = info.Y;
    gFakeDialogOptions.Width = info.Width;
    gFakeDialogOptions.Height = info.Height;
    gFakeDialogOptions.Clickable = false;

    gFakeDialogOptions.BackgroundGraphic = MyDynamicSpriteForTheFakeGUI.Graphic;
    gFakeDialogOptions.Visible = true;
    info.RunActiveOption();
  }
}


Check if that fixes it. By not storing the dynamic sprite persistently, it could very well be that the SpeechBubble module reuses the same sprite slot for its dynamic sprite, which would cause this behavior.

bx83

So just add the definition outside the functions in GlobalScript.acs? Isn't that illegal?

Crimson Wizard

Quote from: bx83 on Wed 28/03/2018 21:47:40
So just add the definition outside the functions in GlobalScript.acs? Isn't that illegal?

When variable is declared inside function, it is called local variable, and will be destroyed as soon as function ends.
When variable is declared outside of function, it is called global variable, and will stay until the end of the game (there are exceptions for room variables when room is reset, but this is another topic).

Related topic in the manual: http://www.adventuregamestudio.co.uk/manual/ags29.htm
Look for "Variables" and "Variable Scope".

bx83

It work's perfectly :D

But one more problem; it doesn't go away after the dialog finishes. Where is the exit point for the dialog script?

EDIT: found the closing statement in the dialog script:
Code: ags

...
cCharacter.Say("Goodbye")
Stop


But putting a 'gFakeDialogOptions.Visible = false;' at the end of every single script (after 'goodbye', before Stop) is, like, 60 scripts that needs editing. I would rather replace this with one line in a function, but I don't know where this function is.
Can't put it directly after 'dDialog.Start();', as Dialogs are non-blocking and this statement does nothing.
Is there a function like 'IsCharacterInDialog' or 'RunThisAtTheEndOfDialog'? It seems you .Start the dialog and then... the programme just dissapears into a dialog script. I don't really know where the compiler is after dDialog.Start

dialog_request look's promising, in that it can run StopDialog()....? Doesn't look workable for a dialog though, only a text parser (whatever the hell that is :P).

SMF spam blocked by CleanTalk