scrollToEnd in ShowMenu

Hi everyone!

I have learnt so much reading the responses posted in this forum but this is my first time actually asking a question. I'm hoping someone someone can help me with a text scrolling issue. I know I'm probably just being picky but it's quite frustrating in terms of formatting!

I've been using K.V.'s scrollToEnd( ) fix found here https://textadventures.co.uk/forum/quest/topic/mxvleq26puqyf3xfxbgwoq/scrolltoend.

I want my game to always scroll to the end unless that's more than a page and then it should scroll to the top of the most recent section of text. I only clear the screen between rooms and I don't want to either remove all the previous text or have the player needing to scroll back up to the top of the section.

This override works perfectly most of the time but doesn't seem to work when the message output has come from a ShowMenu case. I have tried putting scrollToEnd( ) everywhere inside and after the menu and it just refuses to scroll. I want it to scroll so the output from the menu is at the top of the screen. I think this is happening because the menu choice/output isn't considered a new turn so it doesn't affect the current turn scroll position or maybe because the menus are non-blocking?

This issue is particularly annoying as my conversations between the player and NPCs happen through menus where the player can select a topic to talk about. So none of my conversations will scroll properly. At least they're not scrolling all the way to the bottom though!

Many thanks to anyone who can help me out!


The position it scrolls to is equal to the height when markScrollPosition() is called. This is triggered by sendCommand before the UI sends a command to the backend.

I note that this could also lead to weird behavior if triggering a command while textfx (typewrite etc) is still running.

For menus, the simplest thing to do would be putting

JS.markScrollPosition()

right at the top of your menu response. However, this will likely scroll too far, because it may set the position to scroll to as the height of previous output before the menu options have finished hiding.


To make menus work neatly, you'd probably want to add a line to one of the core functions, ClearMenu:

    JS.eval("markScrollPosition(); $('." + game.menuoutputsection + "').each(function() {beginningOfCurrentTurnScrollPosition -= $(this).height();});")
    HideOutputSection(game.menuoutputsection)
    game.menuoutputsection = null
    game.menuoptions = null
    game.menucallback = null

This will automatically mark the scroll position, subtracting the height of the menu.

(If you do this, you wouldn't need to do anything in the menu response itself)

If you're on the web editor and can't modify the core functions, I've got two possible workarounds:

  1. The simple. Call JS.markScrollPosition() immediately before calling ShowMenu.
  2. If you output any text below the menu, option 1 will scroll it to the top after clicking an option. To avoid this, copy the blue line from the modified function above, and put it after all the output. So you would be doing something like:
ShowMenu ("What… is your favourite colour?", Split("red;green;blue;ivory"), true) {
  // some code here to handle the response
}
msg ("Remember to choose carefully!")
JS.eval("markScrollPosition(); $('." + game.menuoutputsection + "').each(function() {beginningOfCurrentTurnScrollPosition -= $(this).height();});")

Thank you so much for your ideas! I'm on the desktop editor so I have tried both editing the ClearMenu function and also inserting those lines before and after the menu but I'm not seeing any difference in the scrolling behaviour.


I think I might have figured it out! In the ShowMenuResponse function I have put your mark scroll position as well as scroll to end. So it now looks like this:

JS.markScrollPosition()
if (game.menucallback = null) {
  error ("Unexpected menu response")
}
else {
  parameters = NewStringDictionary()
  dictionary add (parameters, "result", UnescapeQuotes(option))
  script = game.menucallback
  ClearMenu
  // Added by KV to handle the new FinishTurn setup in 580
  if (not GetBoolean(game, "disambiguating")) {
    game.runturnscripts = true
  }
  game.disambiguating = false
  invoke (script, parameters)
  FinishTurn
}
JS.scrollToEnd ()

I'll have a play around with it like this and see if it keeps working or has any unintended side effects!


Ok so for anyone else looking for a solution to this problem (don't know if anyone will be cause it's pretty niche!), here's what I've ended up with...

In the game UI initialisation script I now have two JS functions:

JS.eval (" function scrollToEnd() {    var scrollOffset = -100; if (beginningOfCurrentTurnScrollPosition > 0) { var scrollTo = _animateScroll ? beginningOfCurrentTurnScrollPosition - 50 - $(\"#gamePanelSpacer\").height() - scrollOffset: $(document).height()+ scrollOffset;    var currentScrollTop = Math.max($(\"body\").scrollTop(), $(\"html\").scrollTop());    if (scrollTo > currentScrollTop) {        var maxScrollTop = $(document).height() - $(window).height();        if (scrollTo > maxScrollTop) scrollTo = maxScrollTop;        var distance = scrollTo - currentScrollTop;        var duration = _animateScroll ? distance / 0.4 : 1;        if (duration>2000) duration=2000;        $(\"body,html\").stop().animate({ scrollTop: scrollTo }, duration, \"easeInOutCubic\");   } }    $(\"#txtCommand\").focus();};")

JS.eval (" function scrollToEndMenu() {    var scrollOffset = 0; var scrollTo = _animateScroll ? beginningOfCurrentTurnScrollPosition - 50 - $(\"#gamePanelSpacer\").height() - scrollOffset: $(document).height()+ scrollOffset;    var currentScrollTop = Math.max($(\"body\").scrollTop(), $(\"html\").scrollTop());    if (scrollTo > currentScrollTop) {        var maxScrollTop = $(document).height() - $(window).height();        if (scrollTo > maxScrollTop) scrollTo = maxScrollTop;        var distance = scrollTo - currentScrollTop;        var duration = _animateScroll ? distance / 0.4 : 1;        if (duration>2000) duration=2000;        $(\"body,html\").stop().animate({ scrollTop: scrollTo }, duration, \"easeInOutCubic\");    }    $(\"#txtCommand\").focus();};")

The first one makes the scrollToEnd() work as I want it to almost everywhere. I need the scrollOffset of -100 in there for some reason otherwise it doesn't quite scroll far enough. The first if statement in there stops it from scrolling down that extra offset amount at the start of the game or upon entering a room (cause that looked weird).

The second one is for scrolling after menu choices and to make it work I have put JS.markScrollPosition () at the end of the ClearMenu function and JS.scrollToEndMenu () at the end of the ShowMenuResponse function.

I feel like it's all a bit cobbled together as this game is really my first time coding anything but it's working :)


Log in to post a reply.

Support

Forums