Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Grids and Dialog and Npc's and stuff...

Okay, so bare with me here

I am trying to write a story that involves quite some narration, NPC's and conversation's with such NPC's (with different options for the player to choose from and to influence the result).
Now, my idea was to have the narrated text in the middle of the passage, as the default text usually is, but have the dialog occur in a separate area of the passage. Sooo, like a small area at the foot of the passage (with a fixed size) where the dialog and the options were displayed. A lot like it's seen in RPG's and such... And then once the conversation is done, the narration continues on the central area of the passage.

Now I've been trying to do this with CSS and a grid, but I'm coming up short . Now, please note that I'm a total newbie at twine, and programming and CSS, and just... life.

This is the code I have on my stylesheet (don't mind the color choice, it's just an experiment, and the code itself is probably terrible):

.areas-wrapper{
display:grid;
grid-template-columns: 100%;
grid-template-rows:80% 20%;
grid-gap: 10px;
grid-template-areas:
"narration"
"dialog";
align-items:center
}


.areas-narration{
grid-area:narration;
background:blue;
padding:10px;
}

.areas-dialog{
grid-area:dialog;
background:red;
padding:10px;
}



My intention was for the dialog area to be always at the bottom of the page (like an actual footer, or even the same way the sidebar has a fixed position), but instead of just appending information, actual things could happen there.
It wouldn't bother me at all also, if, when there isn't dialog happening, if the bar was just there, as long as it remained at the bottom of the page.

Is this possible? Can anyone help me with my terrible coding?
I have some other questions too, slightly related, but I'd be sooo happy with just some help on this....

Thanks! :)

Oh, and I'm using Twine 2.0 and Sugarcube 2.18

Comments

  • Please use the code tag when posting examples - it's the C on the editor bar.

    The main issue with using CSS grid layout (MDN) to achieve what you want is that it is still only a Candidate Recommendation (W3) and it is not fully supported (Can-I-Use) by all web-browsers yet.
    If you do want to persist with using it then you may want to read the A Complete Guide to Grid (CSS-Tricks) article which demonstrates much of the functionality.

    SugarCube includes two special passages named PassageHeader and PassageFooter which can be used to append common content to the start and end of each passage, and you can use then <<if>> macro to make that content conditional. The Header/Footers and Graphic Overlays thread lightly covers one Author's attempt at doing this.

    Another option is to permanently add your own footer area (similar to the side-bar) to the page's layout, the Making a mobile friendly UI - few snags thread lightly covers one Author's attempt at doing this.

    If you supply a visual mock-up (image) of how you would like the end result to look then I am sure people here (of on the Q/A site) would be willing to help you achieve it. Remember that people use different devices (desktop -> mobile) to view their web content which in turn means different screen resolutions, you may want to take that into considerations when designing your layout.
  • @greyelf First of all, I wasn't aware of the issue with grid using for different browsers, so thanks. I'll be careful with that in the future.

    I did take a look at the options you showed, and the closest thing I got to what I wanted was using this in the CSS:
    #story-footer {
    	background-color: yellow;
    	color: black;
    	min-height: 3em;
    	width: 100%;
            position:absolute;
      	bottom:0;
    }
    
    Which does create the kind of bottom bar that I wanted. My problem is, and again, sorry for my stupidity in the matter, I can't seem to show text in that area.
    
    I created a passage named [i]PassageFooter[/i] and I wrote what I wanted there, but it's not working, nothing shows up. Correction: the text i want shows up, but it does so after the normal text of the passage, exactly the same as if I had written it in the passage itself. 
    
    

    I also added this in the JavaScript (unsure if I should):
    var story = $("#story");
    $('<div id="story-footer"></div>').insertAfter(story);
    
    postrender["Display Story Footer Contents"] = function (content, taskName) {
    	setPageElement('story-footer', 'StoryFooter');
    };
    

    Could you please tell me what I'm doing wrong? Thanks
  • edited June 28
    I'd just create a custom div-element in your Stylesheet:
    #dialogue-bar {
    	position: fixed;
    	z-index: 50;
      	background-color: rgba(0, 0, 0, 0.5);
    	border: #fff double 0.4em;
    	height: 10em;
    	right: 0.25em;
    	left: 18em;
      	bottom: 0.25em;
    	padding: 1em;
    }
    

    You'll have to adjust it's size, style and position to fit your story, then add it via javascript:
    $('<div id="dialogue-bar"></div>').appendTo(document.body);
    

    Adding something like:
    <<replace "#dialogue-bar">><<display "Dialogue">><</replace>>
    

    Will now display the content of a passage called "Diaolgue" within your newly created element.
    You can toggle the visibility of the element on and off too:
    <<set document.getElementById("dialogue-bar").style.visibility = "visible">>
    <<set document.getElementById("dialogue-bar").style.visibility = "hidden">>
    
  • @idling oh my god, this is exactly what I wanted... I feel even dumber now, seeing how simple it could have been.
    Can I ask if there's a way to make it as a default 'hidden' and then just call it to 'visible' in certain passages? Instead of having to make sure they're hidden in every other passage?

    Thank you so much, really!
  • edited June 28
    @Jajajewels
    In your last example the passage representing your footer should of been named StoryFooter not PassageFooter. You were mixing the two different solutions together.

    If you had done that then any TwineScript content you placed in the StoryFooter passage will automatically appear on the page without you needing to manually update it. This is due to the setPageElement('story-footer', 'StoryFooter'); line in your second peice of code.
  • Jajajewels wrote: »
    @idling oh my god, this is exactly what I wanted... I feel even dumber now, seeing how simple it could have been.
    Can I ask if there's a way to make it as a default 'hidden' and then just call it to 'visible' in certain passages? Instead of having to make sure they're hidden in every other passage?

    Thank you so much, really!

    I'm not sure hat you want here...
    <<set document.getElementById("dialogue-bar").style.visibility = "hidden">>
    

    That already turns it invisible in every passage, until its made visible once more.

    You can alter the "PassageReady" passage to automatically turn the bar visible/invisible in passages with specific tags. Like for example turn it visible in every passage tagged "talk":
    <<if tags(passage()).includesAny("talk")>>
        <<set document.getElementById("dialogue-bar").style.visibility = "visible">>
    <<else>>
        <<set document.getElementById("dialogue-bar").style.visibility = "hidden">>
    <</if>>
    
  • @idling thank you this is exactly what I needed, I'm still learning and this is a great help. I'm sorry if my questions sound redundant at some point.

    @greyelf Thanks for your help too. I realize the mistake I did, and I got it to work! This will be a great help in the future!
  • idling wrote: »
    <<if tags(passage()).includesAny("talk")>>
    
    As-is, that's better written as something like the following:
    <<if tags().includes("talk")>>
    
    The tags() function defaults to returning the tags of the current passage if no passage is specified, so passing it the return value of passage() is both redundant and inefficient. If you only need to test the array for a single member, <Array>.includes() is more efficient.

    Just as an FYI. If you ever needed to invert that check—i.e. to test if a tag was not there—you'd do something like the following:
    <<if not tags().includes("talk")>>
    
  • @TheMadExile thanks for the tip! that's really useful for me, beyond the dialogue-bar part :)
  • Also, as a follow up, I have a couple more questions if anyone, at all, would mind helping me with ... :sweat_smile:

    I've been using idling's dialog bar and it's been exactly what I wanted, visually speaking, and it works like wonders.
    But now, I was trying to create a conversation between two characters in that area and I've come up with a slight snag...

    So with all the code idling suggested, this is what I have in my passage:
    <<timed 2s transition>><<replace "#dialogue-bar">>
    One of the characters speak.<</replace>>
    
    <<next>><<replace "#dialogue-bar">>Someone else speaks<</replace>><</timed>>
    
    

    Now, this kind of does the job, but I was wondering if certain things were possible:

    a) first of all, is this the best way to have dialog follow each other up?

    b)instead of the <<timed>> macro, is it possible to have, for example, a button (or a symbol, like an arrow) that replaces the current text with the next line? (i feel like this could get complex and beyond my current capabilities, but I would love anyting that resembles this functionality.)---> I added a picture to better example what I mean.

    c)is it possible to have the transition between each line of dialog, be smoother? As it is right now, with my code, with each
    <<replace "#dialogue-bar">>
    
    the whole box disappears and appears again. Can I just replace the text inside?

    d)finally, and this is WAY less important, how would I do to have some of the text be align to the right? I've tried
    text-align:right
    
    and I've tried
    direction: rtl
    
    , but it doesn't work. This is more of a whim of mine, but I'd still like to know if it's possible...

    I'd really appreciate any help on any of these things. This forum has yet to disappoint me, so here's me hoping :smiley: Thanks
  • edited June 30
    Try something like this:
    <<nobr>>
    <<set $conversation to ["One of the characters speaks.", "Somebody else speaks.", "The conversation comes to an end"]>>
    <<set $count to 0>>
    
    <<replace "#dialogue-bar">>
    <p align="right">
    
    <span id="content">$conversation[$count]</span> <br>
    <<button Continue>>
    		<<if $count > $conversation.length - 2>>
    			<<set document.getElementById("dialogue-bar").style.visibility = "hidden">>
    		<<else>>
    			<<set $count += 1>>
    			<<replace "#content">>
    				<span id="content">$conversation[$count]</span>
    			<</replace>>
    		<</if>>
    <</button>>
    
    </p>
    <</replace>>
    
    <</nobr>>
    
  • @idling Thanks for getting back to me so quickly! This seems to work for straight forward conversations, but is there a version of this that could include player options? Like, an NPC will say something and the player can choose how to answer... It seems to complicate things... I've been using <span> to create more complex conversations, and I tried incorporating it with your code, but then my brain went dead. I've been using stuff like this...
    <span id="answer1">
    <<click "Stay quiet.">>
    <<replace "#answer1">>«First time in town?.»
    
    You stare back at her in silence.
    
    «Not much of a talker, are you? Got it. You still have to order something if you want to stay.»
    <</replace>>
    <</click>>
    <<click "Answer her.">>
    <<replace "#answer1">>«You make it sound like a good thing.»
    «I haven't figure that out yet.»
    
    She smiles.
    
    «So, what can I get you?»
    <</replace>>
    <</click>>
    </span>
    

    I don't know how to combine both...
  • edited June 30
    For multiple choice stuff I'd create a second passage - let's just call it "Dialogue" - then work with a <<switch>>. Something like:
    <<nobr>>
    
    <<if $lapass != passage()>>
        <<set $talk = "Hi, how are you?">>
    <</if>>
    <<set $lapass = passage()>>
    
    $talk <br>
    
    <<switch $talk>>
    
    <<case "Hi, how are you?">>
    <<button "I'm great. How are you?">>
    	<<set $talk = "I'm great too. Wanna hang out?">>
    	<<replace "#dialogue-bar">>
    		<<display "Dialogue">>
    	<</replace>>
    <</button>>
    <br>
    <<button "I'm feeling miserable.">>
    	<<set $talk = "What's wrong?">>
    	<<replace "#dialogue-bar">>
    		<<display "Dialogue">>
    	<</replace>>
    <</button>>
    
    <<case "I'm great too. Wanna hang out?">>
    <<button "Sure thing.">>
    	<<set $talk = "Let's head to the candy shop then.">>
    	<<replace "#dialogue-bar">>
    		<<display "Dialogue">>
    	<</replace>>
    <</button>>
    <br>
    <<button "Sorry I'm busy.">>
    	<<set $talk = "Aw... Maybe next time then.">>
    	<<replace "#dialogue-bar">>
    		<<display "Dialogue">>
    	<</replace>>
    <</button>>
    
    <<case "What's wrong?">>
    <<button "I ate too much candy...">>
    	<<set $talk = "Better lay down for a bit then.">>
    	<<replace "#dialogue-bar">>
    		<<display "Dialogue">>
    	<</replace>>
    <</button>>
    
    <</switch>>
    
    <</nobr>>
    

    In the passage, where you want this stuff to appear you'd then set:
    <<replace "#dialogue-bar">><<display "Dialogue">><</replace>>
    
  • @idling Again, you amaze me. Thank you so much. This is exactly what I needed. I'm gonna have to adapt it of course, but you've sent me on the right path.
    I wasn't familiar with the switch macro, but I'm gonna start using it!

    Also, I got it to work, but I don't understand exactly what you did in the first part of the code, with the $lappass:
    <<if $lapass != passage()>>
        <<set $talk = "Hi, how are you?">>
    <</if>>
    <<set $lapass = passage()>>
    

    If it's not a bother, could you explain it to me? I'd love to understand it. It may come in handy in the future.
  • Jajajewels wrote: »
    Also, I got it to work, but I don't understand exactly what you did in the first part of the code, with the $lappass:
    <<if $lapass != passage()>>
        <<set $talk = "Hi, how are you?">>
    <</if>>
    <<set $lapass = passage()>>
    

    If it's not a bother, could you explain it to me? I'd love to understand it. It may come in handy in the future.

    That's just to make sure that your dialogue or whatever you want the div to contain doesn't keep resetting to its initial state.

    If you just write:
    <<set $talk = "Hi, how are you?">>
    

    And then follow it up with the rest of the code, pressing any of the buttons would just set $talk back to "Hi, How are you?" and nothing would ever happen. With the <<if>> you make sure that $talk is only set to "Hi, How are you?" the very first time you use <<replace>>.
    Also after thinking about it, it probably should be:
    <<if $lapass != passage()>>
    	<<set $lapass = passage()>>
    	<<set $talk = "Hi, how are you?">>
    <</if>>
    

    Instead of what I wrote initially. Both work basically the same way, but this is probably a little more efficient.
  • Oh, I get it. Makes sense.
    In the meanwhile I've been trying this out and it's working perfectly. I have to combine both options of code you suggested, in order to create strings of conversations with choice making for the player, but it's looking good! thanks again!
  • Follow up....
    Is there a way to customize the appearance of the buttons in css? maybe as an element contained in the dialog area... thanks
  • You customize buttons using the css stylesheet. For example:
    button {
      background-color: black;
      color: orange;
      border: solid;
      border-color: orange;
      text-align: center;
      text-decoration: none;
    }
    
    button:hover {
      background-color: orange;
      color: black;
      border-color: orange;
    }
    
  • @idling Cool! thanks for the quick response :smiley:
Sign In or Register to comment.