Hi everybody, total newbie here :smiley: I'm creating my first game in AGS, a first-person point-and-click adventure, and thanks to these amazing forums and the manual I already have a lot of basic stuff down, such as cursor changes, using inventory items etc. But now I'm completely stumped and I can't find anything in the forums that applies to my problem.
At a certain point I want the player to be able to click on a cellphone that's lying around and for this to trigger a scripted SMS/Whatsapp conversation, the kind where each participant's text is on each side of the screen and the text is contained inside speech bubbles or simply rounded rectangles.
Since the conversation is completely scripted, I don't need to complicate things for now with different dialog options and such (phew!).
The thing is, I'm completely stumped as to how to do this. Functions such as Display or Say would allow me to use a custom text window for the "speech bubble" background, but the problem is that these functions can only display one message on screen at a time, and of course, I want the whole conversation to be progressively displayed on the screen message by message, the same way you would see it on your phone.
Another option I thought about was creating a GUI with labels that are initially invisible and appear one by one after a short delay, but labels can't use custom text windows (as far as I know!), so I wouldn't be able to customize them as speech bubbles. So while it would work from a technical standpoint, I would sacrifice the "chat" look and feel.
I'm starting to fear that the solution is necessarily going to imply doing stuff with overlays, drawing surfaces, and/or dynamic sprites, but the thought is really intimidating, since I've never used any of that and I have no idea how it works. But if it's inevitable, I'd truly welcome a nudge or two in the right direction.
Any help would be dearly appreciated!
Here you go :)
https://www.adventuregamestudio.co.uk/forums/index.php?topic=54524.msg636554775#msg636554775
Oh wow, thanks Khris! I've been searching the forums for 3 days and I didn't even come close to finding this thread (found a lot of almost-what-I-needed-but-not-quite though :) ).
I'll probably bother you again at some point if/when I have issues understanding the code or the method, but this should keep me busy for a while. Thanks again!
If you're having trouble using the forum search function, it's often better to use Google to find what you're looking for.
In Google search bar type:
site:https://www.adventuregamestudio.co.uk/forums/ what I want to find
I found that thread by searching the two tech forums for "chat". :-D
Still, I usually don't find what I'm looking for, and have spent considerable time clicking through pages of topics in the past.
Retro Wolf I actually use both! I think I simply might have focused more on searching for terms such as "phone", "sms" or "whatsapp" and not "chat", but after days of losing my mind trying to crack this one, who knows :-D
Khris, your code has made it so painfully obvious that I need to learn SO much before I consider myself even barely competent at scripting :-[ I'm going to try implementing it tonight "as is" and if it works, I'll try my hand at customizing it (for example, I'd like to remove the "// author time" line over each message, but I'd like to figure it out how to do it by myself).
Just one question for now, though: you say "To use the module, put a button on a GUI". I'm guessing that the size of the GUI will determine the size of the chat window and that it doesn't matter where I place the button or what size it is?
Thanks again!
And since I'm here, another question related to my initial approach, even though I won't be going that route in the end but I'm curious as to how it would be done...
Say that I have 15 labels that I want to set to invisible and at some point back to visible again. Their names are lblMsg1, lblMsg2, etc, up to lblMsg15.
Is there a way to do this other than typing fifteen times "lblMsg1.Visible = false;", "lblMsg2.Visible = false;" etc etc? It feels like it should be possible to do it with a loop, but I haven't managed to figure out how.
for (i =1; i < 16; i++) {
Label*message = String.Format("lblMsg%s", i);
message.Visible = false;
}
This obviously doesn't work because I'm mixing up a String and a Label, but I feel like I'm on the right track? Maybe? Close enough?
Quote from: notarobotyet on Thu 07/03/2019 22:33:39
Say that I have 15 labels that I want to set to invisible and at some point back to visible again. Their names are lblMsg1, lblMsg2, etc, up to lblMsg15.
Is there a way to do this other than typing fifteen times "lblMsg1.Visible = false;", "lblMsg2.Visible = false;" etc etc? It feels like it should be possible to do it with a loop, but I haven't managed to figure out how.
The question is rather how to group them together so that you can perform action over all of them. Only for the sake of example, the variants are:
1) make sure their control IDs are sequential and run over GUI's Controls array from x to y.
for (int i = FIRST_LABEL_ID; i <= LAST_LABEL_ID; i++)
gMyGUI.Controls[i].Visible = true;
2) make sure they are only labels on GUI
you need and run over GUI's Controls array selecting only Labels.
for (int i = 0; i <= gMyGUI.ControlCount; i++)
{
Label *label = gMyGUI.Controls[i].AsLabel;
if (label != null)
label.Visible = true;
}
Note that you must get Label pointer of a control if you want to work with label-specific properties.
3) create your own array of Label* pointers in script, assign your labels to that array and run over array.
4) **UNEXPECTED SOLUTION** put them all on separate GUI and turn that gui's Visible on and off. (Of course if you want to do something else, like setting their texts, that won't be enough)
Quote from: notarobotyet on Thu 07/03/2019 22:33:39
for (i =1; i < 16; i++) {
Label*message = String.Format("lblMsg%s", i);
message.Visible = false;
}
This obviously doesn't work because I'm mixing up a String and a Label, but I feel like I'm on the right track? Maybe? Close enough?
Besides the looping over labels problem, the mistake here is that you are printinf integer "i", but using placeholder type for string "%s". The correct placeholder for integers is "%d".
So, for example:
for (i =1; i < 16; i++) {
Label *label = gMyGUI.Controls[i].AsLabel;
label.Text = String.Format("lblMsg%d", i);
label.Visible = false;
}
Crimson Wizard, thank you so much! This has taught me so much more in 5 minutes than all the hours I've spent poring over the manual ;-D I had a hunch that the solution would lie in using the label IDs rather than trying to build their names, but I was looking in the wrong place. I was expecting to be able to use something like a Label array and it turns out it's actually the Controls array. So close!
Edit: and yeah, using the %s placeholder instead of %d was such a dumb typo :facepalm:
Quote from: notarobotyet on Thu 07/03/2019 22:33:39
This obviously doesn't work because I'm mixing up a String and a Label, but I feel like I'm on the right track? Maybe? Close enough?
This is a common (and understandable) misunderstanding, but no, it doesn't work like that. As I recently explained (https://www.adventuregamestudio.co.uk/forums/index.php?topic=56957.msg636602275#msg636602275) in another thread:
Quote from: Snarky on Sun 24/02/2019 22:19:38
The variable names in code are not in this sense "strings" that can be manipulated by the code (that would be self-modifying code, which is beyond AGS), they're just arbitrary labels to make the script readable to humans. To the compiler, there's no relationship between aFile01 and aFile02.
Because you can't use an AGS script to rewrite its own AGS code, the script-name of a Label and the actual Label which that name refers to exist on two different planes: one is translated into the other at the time of compilation, but you can't make that link yourself. Trying to use string manipulation to change the script-name in order to make it refer to another Label is a little bit like an alchemist trying to change
horn into
corn by replacing a hydrogen atom with carbon.
One thing that might make it additionally confusing is that Strings are sometimes used in logic to
look up particular entities (like files, voice clips, custom properties, etc.), and in that case you
can use string manipulation to give you one item or another.
Thanks for the explanation, Snarky. This thread is giving me a lot of little "a-ha!" moments :)
What threw me off the right scent completely is that the manual kind of waves away label/control IDs as something you'd only use for compatibility with legacy code and at some point even remarks that "You should not normally need to do this, since accessing the controls by their name is far easier", so I assumed there HAD to be a way to do this using label names rather than IDs (although technically there is, by building your own array).
On the other hand, I haven't managed to get Khris' module to work. I think I might have bitten off more than I can chew with this, so I'll try to come up with a workaround at least until I have the skill and the familiarity with AGS scripting to understand what's going on in there rather than trying to apply the code blindly without knowing what I'm doing.
Thanks a lot, guys. I feel like I've learned a lot this last couple of days ;-D