Forum rules - please read before posting.

Hotspot restrictions and game remaining playable during speeches

Hello there, two questions this time!

Question 1: Let's say a character locks themself in a cage in a room. They shouldn't be able to access any of the other hotspots in the room as long as they remain in the cage. It seems kind of troublesome to disable all the other hotspots one by one and then enable them again once they get out of the cage. As there can be tens of hotspots in a room, I want to ask if there's a simpler way to do this? I know you can do Player:Constrain to restrict character movement, but what about limiting access to hotspots (all but one)?

Question 2: When you look at an object in a classic PNC adventure game, in all of LucasArts games at least, the playable character comments and you can keep playing simultaneously, you still have all the controls – even when there are many lines of monologue to read/listen. In AC, this isn't the case, by default: you lose the controls until the monologue is over. Play in background can be used, but only with the last line, otherwise all the previous lines are skipped.

I guess I could try some weird Engine:Wait between every line with the Play in background in use, but that seems like a hack, not intuitive at all. This seems like such a basic feature that I feel like there should be a box to tick somewhere that says "Game remains playable during speeches" or something. If not, is there a more clever way to implement this?

Comments

  • I know you can do Player:Constrain to restrict character movement, but what about limiting access to hotspots (all but one)?

    You could rely on a custom script to enable/disable the Hotspots in bulk:

    using UnityEngine;
    using AC;
    
    public class BulkSetHotspots : MonoBehaviour
    {
    
        public Hotspot[] hotspots;
    
        public void EnableAll ()
        {
            foreach (Hotspot hotspot in hotspots) hotspot.TurnOn ();
        }
    
        public void DisableAll ()
        {
            foreach (Hotspot hotspot in hotspots) hotspot.TurnOn ();
        }
    
    }
    

    Alternatively, an Interactive boundary object can be assigned to a Hotspot to limit interactivity to only when the Player is within it. Though this is just an idea, you could try assigning all such Hotspots to one that - by default - covers the whole scene, and then teleport the boundary out of view once the Player is confined.

    This seems like such a basic feature that I feel like there should be a box to tick somewhere that says "Game remains playable during speeches" or something.

    In the ActionList's Inspector, set its When running property to Run In Background.

  • edited May 2021

    Thank you @ChrisIceBox ! Run in Background as such didn't actually suffice, because I still wasn't able to do anything else when any dialogue line was playing: a mouse click would only skip the current dialogue line. After many hours and some help, I found out that what was needed, in addition, was to untick "Subtitles during gameplay can also be skipped?" from the Speech manager. These two together would let me play normally as a dialogue line was playing.

    Nevertheless, one problem persists: let's say there are two objects in a room. You can examine both and object 1 produces a long 5-line monologue. Object 2 produces a short one line comment.

    If I look at object 1:
    the long babbling begins in background...
    I immediately look at object 2:
    the short comment punches in...
    after which the player character returns to the remainder of the object 1 babble.

    Obviously I don't want this to happen. So the new question is: what's the best way to stop a previous look at action (that's running in background) when a new one is activated?

  • edited May 2021

    (posted about another problem but solved it thereafter – but the problem above persists)

  • edited May 2021

    If the first object deals with multiple lines of dialogue, you can use the ActionList: Kill Action at the start of the second object's Interaction to kill the first, and prevent its lines from being fired.

    This could also be automated through script:

    using UnityEngine;
    using AC;
    
    public class CancelBackgroundInteractions : MonoBehaviour
    {
    
        private void OnEnable () { EventManager.OnBeginActionList += OnBeginActionList; }
        private void OnDisable () { EventManager.OnBeginActionList -= OnBeginActionList; }
    
        private void OnBeginActionList (ActionList actionList, ActionListAsset actionListAsset, int startingIndex, bool isSkipping)
        {
            if (actionList is Interaction)
            {
                // Kill all other gameplay Interaction ActionLists
                for (int i = 0; i < KickStarter.actionListManager.ActiveLists.Count; i++)
                {
                    ActiveList activeList = KickStarter.actionListManager.ActiveLists[i];
                    if (activeList.actionList && activeList.actionList != actionList && activeList.actionList.actionListType == ActionListType.RunInBackground)
                    {
                        KickStarter.actionListManager.EndList (activeList);
                    }
                }
            }
        }
    
    }
    
  • edited May 2021

    Thank you once again @ChrisIceBox and sorry for having been a bit unclear before. In my example, for clarity's sake, I mentioned two objects only, but we're actually talking about a room filled with objects = things to look at. And all the rooms in my game are like that. So if I wanted to use ActionList: Kill I would have to always list all the 20+ things in that room the player could've possibly looked at previously (that is, ActionLists the player could've set in motion).

    Your script fixes this. BUT if I understand correctly, it does so by killing ALL ActionLists. That's a problem, because I'll have background animations, NPCs doing things and probably other stuff going on in the scenes and I don't want those to be killed. I ONLY want the previous "look at" interaction to die. Is it possible to come up with a script that kills only the previous ActionList you've run just before the current one?

    I wondered if a simple Dialogue:Stop speech (by Player) would suffice, although that's clearly not the optimal solution, because it would require for all the monologues throughout the game to be kept in single ActionList action ("bubble"), lines separated with [commands], with all the possible actions stuffed in that same bubble as well. If it wasn't all in one bubble, Dialogue:Stop speech would only affect the current line/bubble and if there's an ActionList running in background with more lines/bubbles, then the next ones would just pop up... So I hope there's a more clever way to achieve this.

  • You can filter by the ActionList's type to only affect Hotspot Interactions:

    if (activeList.actionList && activeList.actionList != actionList && activeList.actionList is Interaction && activeList.actionList.actionListType == ActionListType.RunInBackground)
    

    If you wanted to try the method of killing the previously-run ActionList:

    using UnityEngine;
    using AC;
    
    public class CancelBackgroundInteractions : MonoBehaviour
    {
    
        private ActionList lastBackgroundActionList;
    
        private void OnEnable () { EventManager.OnBeginActionList += OnBeginActionList; }
        private void OnDisable () { EventManager.OnBeginActionList -= OnBeginActionList; }
    
        private void OnBeginActionList (ActionList actionList, ActionListAsset actionListAsset, int startingIndex, bool isSkipping)
        {
            if (actionList is Interaction)
            {
                KickStarter.actionListManager.EndList (lastBackgroundActionList);
            }
    
            if (actionList.actionListType == ActionListType.RunInBackground)
            {
                lastBackgroundActionList = actionList;
            }
        }
    
    }
    
  • edited May 2021

    @ChrisIceBox Brilliant, thanks! This code does exactly what I wanted.

    But since new problems always seem to arise when you fix something, there was still one thing I didn't foresee: this script doesn't let you look at any object twice in a row! Once you've chosen "look at apple", you have to look at something else before you can look at the apple again.

    Can an exception be added to the script which checks if there's an interaction ActionList currently running in background and only in that case that ActionList is cancelled? Or is there another workaround that would solve this bug?

  • Try this:

    using UnityEngine;
    using AC;
    
    public class CancelBackgroundInteractions : MonoBehaviour
    {
    
        private ActionList lastBackgroundActionList;
    
        private void OnEnable () { EventManager.OnBeginActionList += OnBeginActionList; }
        private void OnDisable () { EventManager.OnBeginActionList -= OnBeginActionList; }
    
        private void OnBeginActionList (ActionList actionList, ActionListAsset actionListAsset, int startingIndex, bool isSkipping)
        {
            if (actionList == lastBackgroundActionList) return;
    
            if (actionList is Interaction)
            {
                KickStarter.actionListManager.EndList (lastBackgroundActionList);
            }
    
            if (actionList.actionListType == ActionListType.RunInBackground)
            {
                lastBackgroundActionList = actionList;
            }
        }
    
    }
    
  • Perfect! That one added line solved it. I'm slightly ashamed but then again, I'm not a coder at all.

    P.S. I don't think I've ever had better service anywhere, you are simply pure gold. Is there a way to make a small donation to you / for AC development?

  • Asset reviews are always welcome.

Sign In or Register to comment.

Howdy, Stranger!

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

Welcome to the official forum for Adventure Creator.