+1 vote
by (2.4k points)

Hey there friends. 
I've been doing some stuff with SugarCube, and despite my efforts, I am failing. 

I'd like to code a function that would take some strings, and would utimately print them in order, in order to simulate a messenger conversation. 

Yet, so far, I can't even get my function to print anything. Not the way I'd like to, not without a "return". I don't want a return, I want my function to work with what I send , and that's all. Any ideas ?  

I'm *really* bad. So I've been trying stuff like : 

 

<<print setup.chat("Bob","jejej","hsjasja","sajsj")>>

into my twine story, and 

setup.chat = function(name,sOne,sTwo,sThree){
    
print (name "," sOne "," sTwo "," sThree); 

}

 

within my javascript block. 

It hurts my eyes as well. Please, teach me... 

1 Answer

+1 vote
by (63.1k points)
selected by
 
Best answer
1. Why are you doing this? You could just save the strings to an array and join them, or just pass the content directly to <<print>>. It seems like there's something missing here.

2. Why on earth must we avoid a return? The only way to get the function's values back to the <<print>> macro would be to return them. Otherwise we'll need to create a new space on the page for the output and then we need more code and the <<print>> is unnecessary.

3. Right now, the only easy way to give you what you want with your (seemingly arbitrary) stipulations would be to actually create a less functional stripped down version of the print macro, and that seems like a lot of work just to create a gimped version of a macro that can already do exactly what you want in a number of ways.

It seems like we just need more information. Why can't we use return statements? Why do you need a function to print strings? What exact problem are you trying to solve?

Edit: on rereading, this is harsher-sounding than I meant it to be. I understand that you're new, and I don't want to discourage you at all, you've clearly done some reading, what with the use of the setup object and such, and I applaud that.  I just don't have a picture of what problem this is meant to solve, and I think the functionality you describe might not actually be what you want. It's hard to balance an explanation that essentially boils down to "what? why? that's probably not a good idea" without coming off a bit pedantic.
by (2.4k points)
edited by
I knew I wasn't clear on what I asked, but I had no way of knowing why until someone answered.

As I've said, what I'd like to do ultimately is create a function that would take as parameters some strings, and work with them. That way, my code in my Twine story won't be dully repetitive and I wouldn't have to re-write everything.

What I'd have loved this function to do is to print the strings I sent in order, in such a way :

"name" : "sentence 1 sent"
// Wait some seconds, while "name is writing" is appearing
"name" : "sentence 2 sent"
// Again, wait some seconds, while "name is writing" is appearing.

etc.

I'd like it to be a "conversation simulator". and it would be awesome if I didn't have to re-code the whole damn thing, thus the idea of a function doing it for me. I did that exact thing in Harlowe and it worked neatly, but I had to copy-paste everything everytime I needed to type down a conversation. But my idea of a function seems to be wrong here. My notions are mainly from C++.

I don't want a return because I don't need one, this function wouldn't be meant to return anything, it would be meant to work by itself. With a return, I'd be back to code everything within my twine story.
 

With a function, in my wildest dreams I could do :

chat("Seyru", "Why this damn function won't work", "I hate life", "Please help me");

and it would print out :

 

Seyru : Why this damn function won't work
// Seyru is writing
Seyru : I hate life
// Seyru is writing
Seyru : Please help me

This is essentially to facilitate future coding.
I only asked for how to use print within a function because I thought that, starting there, I'd be able to do everything else on my own. Didn't think it would confuse everything haha

Again, I know I ain't good with this stuff. But there aren't much tutorials out there, and what I've found didn't help with with what I wanted to do.

Thanks a lot for your help. Yep, that setup stuff I read in one of your own answer :)
by (63.1k points)
edited by

Well, the problem is that JavaScript doesn't really have any way to output things without using some element already on the DOM. 

setup.chat = function () {
    var args = [].slice.call(arguments);
    var name = args.shift();

    return name + ':\n' + args.join('\n');
};

Edit: Fixed an error (forgot to invoke the shift method).

This function will work as a helper function for <<print>>: 

<<print setup.chat('name', 'line1', 'line2', 'etc...')>>

We need the return because we need some type of value to be sent to print. 

Without a return, we need to do more work; we need to create an element on the page and pass that element to the function: 

setup.chat = function () {
    var args = [].slice.call(arguments);
    var name = args.shift();
    var $el  = $(args.shift());
    var str  = name + ':\n' + args.join('\n');

    $el.wiki(str);
};

Then, in passage: 

@@#chat;@@\
<<run setup.chat('name', '#chat', 'list of lines')>>

That's more work. 

We don't really need a function at all though. We could just use a widget. 

<<widget 'chat'>>
    <<set _name to $args.shift()>>
    <<print _name + ':\n' + $args.join('\n')>>
<</widget>>

Usage: 

<<chat 'name' 'line1' 'line2' 'etc...'>>

Overall, I believe the least efficient way to get what you want is with a function that returns nothing. 

I didn't test this code, let me know if you encounter any errors. 

Edit: I'll see if I can whip something up that's closer to the chat feature you describe later, when I have more time. 

by (2.4k points)

Once again, thanks for your time ! I learnt a lot right there. 

I've tested the function, and when I run it, it says : 

function shift() { [native code] }:
name
line1
line2
etc...

I have no idea where that printed "function shift()" is from. 

The widget sounds awesome. I had never heard of them before. I'll spend some time learning about their functionality. 

 

Now though, last step I'd love to know about : How do I have to proceed, within a function or a widget, to make it so line 2 is printed 2 seconds after line 1 ? (while having "name is writing" appearing instead ? 

To clarify, I did quite manage to do it in Harlowe, months ago, it gave something like this : 

//Sent by// $name: "''Fuck off, why would you go and tell mom AND dad I didn't do shit ?!''"

(live:1s)[
(if: time >=2s and time <4s)[$nameC is writing...]\
(if: time >=4s)[
//Sent by// $nameC: $c["''Seriously ? Are you talking to me?!''"]
]\
(if: time >=5s and time <8s)[$nameC is writing...]\
(if: time >= 8s)[
//Sent by// $nameC: $c["''I told them BECAUSE you didn't do shit ffs!''"]
]\
(if: time >=9s and time <12s)[$nameC is writing...]\
(if: time >= 12s)[
//Sent by// $nameC: $c["''You didn't do ANYTHING !''"]
]\
(if: time >15s)[(stop:)]]\

 

But as I pointed out earlier, I had to copy-paste the entire thing and change the sentences within the code to re-use it. It was a mess. 

 

Is there any way I could manage to have that exact same thing happening, only by writing <<chat 'name' line1' 'line2' 'etc...'>> ? 

This is exactly what I'm looking for.

 

Edit : Just checked the doc of SugarCube. There's nothing about widgets here, eh. I guess I have to look through Javascript documentation ? 

 

by (63.1k points)

Here's a widget:

<<widget 'chat'>>\
    <<nobr>>
        <<set _name to $args.shift()>>
        <<set _msgs to $args>>
        <<set _output to []>> 
        <<set _i to 0>>
        _name: @@#chat;@@ @@#typing;//_name is typing...//@@
        <<repeat 1s>>
            <<run _output.push(_msgs[_i])>>
            <<set _i++>>
            <<replace '#chat'>>
                <<- _output.join('\n' + _name + ': ')>>
            <</replace>>
            <<if _i lt _msgs.length>>
                <<append '#chat'>>
                    <<- '\n'>>
                <</append>>
            <<else>>
                <<remove '#typing'>>
                <<stop>>
            <</if>>
        <</repeat>>
    <</nobr>>
<</widget>>

Example:

<<chat 'Bill' 'hey' 'how are you' 'everything okay?' 'be there soon'>>

I've tested the function, and when I run it, it says 

My fault there; I forgot the () after the shift method in the first function example.  I'll edit it.  Thanks for the catch.  It's what I get for not testing my code. 

Just checked the doc of SugarCube. There's nothing about widgets here, eh. I guess I have to look through Javascript documentation ? 

It's in there. You need to put widget definitions in a widget-tagged passage.  Widgets allow you to create custom macros in TwineScript (as opposed to JavaScript).  I would recommend widgets over custom macros/functions if the functionality you want is possible in SugarCube and all you really want to do is save time on code reuse, which is exactly what you're doing here.  Overall, some things are simpler to accomplish in JavaScript, but you can do a great deal of things with widgets alone.

by (2.4k points)

Thanks a lot !

This is exactly what I wanted to achieve. Now I'll just spend some time trying to understand what's going on with your code. Best way to improve :)

 

by (63.1k points)
Glad to help.  Let me know if you have any questions.
by (2.4k points)

Alright so, here's what I've understood so far : 

   

     <<set _name to $args.shift()>>  // Here you are putting the first place of the array into "name", then erasing that first place. 

        <<set _msgs to $args>> // You then place all that's left of the array into msgs. 

        <<set _output to []>> // You create an empty array

        <<set _i to 0>>

        _name: @@#chat;@@ @@#typing; _name is typing...@@ // This line I can't understand. It's not within the <<repeat>> macro, yet it seems it's being repeated anyway ? How ? Furthermore, what's those @@ ? I've looked into the documentation, but it doesn't seem to make sense that those would be for a "custom style" ? When I get them out nothing works. And what are the # for ? If you could explain it in detail, I'd be very grateful.

        <<repeat 1s>>

            <<run _output.push(_msgs[_i])>> // Here it adds a message to the array output 

            <<set _i++>>
            <<replace '#chat'>>

                <<- _output.join('\n' + _name + ': ')>> // Here you're separating each value of the array with what's within those (). But again, this "#chat" loses me. 

            <</replace>>
            <<if _i lt _msgs.length>>
                <<append '#chat'>> 
                    <<- '\n'>>
                <</append>>
            <<else>>
                <<remove '#typing'>>
                <<stop>>
            <</if>>
        <</repeat>>

I figured most of it out, but I'm lost with "_name: @@#chat;@@ @@#typing; _name is typing...@@" 

Once clarified, I'll manage to understand everything else :D 

Thanks a lot !

 

by (63.1k points)

@@...;...@@ is the custom style markup. As mentioned in the docs, you can add IDs and classes using this markup as well. 

@@#chat;@@

—> equivalent to the html markup: 
<span id='chat'></span>

This creates an element on the page and gives it an ID we can reference using a hash symbol (#). We can use this in CSS: 

#chat { color: red; }

In jQuery (a popular JavaScript library that is included in SugarCube): 

$('#chat').empty();

And in our DOM macros

<<replace '#chat'>>Hello!<</replace>>

All we're doing is taking a small portion of the page and giving it a name so that we can change it and otherwise reference it later. 

In this case, we're filling it with text populated from the list of arguments passes to our widget. We also want to append a new line to it, because we want the "so and so is typing..." message to appear on the line under it. After we've printed all the strings we need, we get rid of the #typing element and stop appending new lines. 

The thing is, we aren't actually adding new messages to the output; the whole set of messages is cleared and recreated with the new message as a part of it every second. This process is fast enough that there's no way for the user to notice that the message is actually being replaced completely, though. 

...