Extra functionalities for banker and shopkeeper

Hi everyone. I was wondering if there is anyway we can add these two functions to my banker (I didn’t want to put this question under the banker so the thread over there doesn’t get overwhelmed/mixed up with stuff non-relevant to the banker, since I’m seeking help for my shopper as well), and my shopkeeper:

  1. If my player gets suddenly attacked, or the player presses around the map when his bank is open, immediately shut the bank (or shop) UI down and let him focus on his fight/walk away
  2. when we click on the banker (or shop trader), can we get our player to move towards the banker/shop trader, before having the NPC rotate towards the player and opening our bank/shop? (I implemented something similar for my ‘PlayerConversant.cs’ before, but it relied on the Dialogue functions. I’m just not sure how to call on the banker, or the shopkeeper, or in which script to code a simple function for that). If it helps in anyway, there’s more than one of these NPCs in the game scene

I was hoping to be able to implement these for my shopkeeper and my banker (I tried adjusting the ‘Shopper.cs’ script for my second one, but it didn’t work well :slight_smile: )

The first part is easy for the Shop, make the Shopper an IAction.
Cancel() in this case should simply call SetActiveShop(null)
SetActiveShop should tell ActionScheduler to StartAction(this) when we call activeShop.SetShopper(this).

        public void SetActiveShop(Shop shop)
        {
            if (activeShop != null)
            {
                activeShop.SetShopper(null);
            }
            activeShop = shop;
            if (activeShop != null)
            {
                GetComponent<ActionScheduler>().StartAction(this);
                activeShop.SetShopper(this);
            }
            if (activeShopChange != null)
            {
                activeShopChange();
            }
        }

        public void Cancel()
        {
            SetActiveShop(null);
        }

This requires a bit of extra prep. Again, we’ll start with the Shopper, as it’s the easiest. We’ll need to add the same logic we use in Fighter to the Shopper, and instead of calling SetActiveShop, we’ll call StartShopAction. We’ll start by taking the line we just added to SetActiveShop OUT of SetActiveShop, we’ll be doing that in a different method.

We’ll need a target

Shop target;

We’ll need a method for the Shop to call

        public void StartShopAction(Shop targetShop)
        {
            if (targetShop == null)
            {
                Cancel();
                return;
            }
            GetComponent<ActionScheduler>().StartAction(this);
            this.target = targetShop;
        }

And we’ll need some Update logic

        void Update()
        {
            if (!target) return;
            if (Vector3.Distance(transform.position, target.transform.position) > 3) //Make this a variable?
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1);
            }
            else
            {
                StartShopAction(target);
                target = null;
            }
        }

Now one important thing… currently, Cancel only clears the active shop… we also need to add

target==null;

Now for the Banker… This is going to require a slightly different solution, because we’re simply turning on a UI when we want to open a bank (much like the Inventory itself). So we’re going to have to create a new class to add to the player.

public class BankAction : MonoBehaviour, IAction

Of course, it’s an IAction, so we’ll need a Cancel() method. Also, like the other walk to classes, we’re going to need a target. For this one, though, we’re simply going to have a Transform as the target.

Transform target;

public void Cancel()
{
    target=null;
}

This takes care of the cancelling, but only the moving to part of the cancelling. It doesn’t take into account that the windows might be open. To facilitate this, we’re going to create a static method in ShowHideUI that actually closes ALL the windows.

        public static void CloseAllWindows()
        {
            foreach (ShowHideUI hideUI in FindObjectsOfType<ShowHideUI>())
            {
                hideUI.uiContainer.SetActive(false);
                if(hideUI.otherInventoryUI!=null) hideUI.otherInventoryContainer.SetActive(false);
            }
        }

Now our Cancel method can call

public void Cancel()
{
    target=null;
    ShowHideUI.CloseAllWindows();
}

Now that that’s out of the way, we can create our action to initiate the BankAction. We’re going to use a callback technique to initiate our action when we’ve reached our destination.

System.Action callback;

        public void StartBankAction(Transform bankTarget, System.Action callback)
        {
            if (bankTarget == null) return;
            this.callback = callback;
            target = bankTarget;
            GetComponent<ActionScheduler>().StartAction(this);
        }

Next up, we need to head to OtherInventory to modify IHandleRaycast.
In the section where the Mouse is down, rather than opening the window directly, we’re going to pass along an anonymous function to the StartBankAction method.

        public bool HandleRaycast(PlayerController callingController)
        {
            if (showHideUI == null) return false;
            if (Input.GetMouseButtonDown(0))
            {
                 callingController.GetComponent<BankAction>().StartBankAction(transform, () =>
                 {
                     showHideUI.ShowOtherInventory(gameObject);
                 });
            }
            return true;
        }

Finally, it’s time for our challenge!
We need an Update() method in BankAction that, if you have a target moves to the target, and when it is in range (say 3?), invokes the action.
Hints:

You can invoke the action with callback?.Invoke(); and it automatically null checks.
Since we passed a Transform as the target, you can use target.position instead of target.transform.position in the Distance calculation.

Good day Brian. The code works for shutting down the UI when we get engaged in a fight, but the code to make the player run towards the NPC he needs to interact with is not working as expected. Any alternatives?

Is this the Shop or the Banker?

It’s for the shop, I’m still going through the banker :slight_smile:

Oh, silly little thing, that.
In the Shop.IHandleRayCast, you need to change the call from SetActiveShop(this) to

StartShopAction(this);

And I made a tiny mistake in Update() (actually one tiny mistake and one big one).

        void Update()
        {
            if (!target) return;
            if (Vector3.Distance(transform.position, target.transform.position) > 3) //Make this a variable?
            {
                GetComponent<Mover>().MoveTo(target.transform.position, 1);
            }
            else
            {
                SetActiveShop(target);
                target = null;
                GetComponent<Mover>().Cancel();
            }
        }

Yup, that fixed it for the shopper. As for the banker, clicking on him now returns a null reference exception error. If it helps in anyway, here is my solution to the Update() function challenge that was provided in the end:

public void Update() {

        if (Vector3.Distance(transform.position, target.position) > acceptanceRadius) {

            callback?.Invoke();

        }

    }

Take a closer look at Shopper’s Update() method…
The Update in BankAction is going to be very very similar.

  • Ensure Target is not null
  • Check distance, if > 3 Move to the bank
  • else callback?.Invoke() (along with clearing the target and cancelling the Mover)

Well it was that, and the fact that I completely forgot to assign ‘BankAction.cs’ to my Player… Silly me :stuck_out_tongue_winking_eye:

It works perfectly fine though now, thanks again Brian :slight_smile:

1 Like

OK a bit of overflow, but since we’re on the topic anyway… Is automatically shutting down the Dialogue UI when we walk away from a conversation with an NPC any similar? I just noticed that, was hoping I can implement that too :sweat_smile:

Dialogues aren’t controlled by the ShowHideUI (unless you make a dummy one).

However, PlayerConversant.Quit() will close the window.

Well, can you please help me implement this too? I’m trying to think of a way that gets the computer to detect a raycast fired at a distance, whilst in conversation, and it picks that up and automatically plays the ‘Quit()’ function

That’s fairly unclear…
Outline what you’re looking to do… what’s the raycast represent? Does it have to be a Raycast (we’re already pumping one to two of those per frame, we don’t want to do more than that if we can help it).

Ok so the whole idea is to use the Raycasts that are being fired at any frame, to sense for mouse clicks by the player. If the player walks away from conversation (i.e: he clicks elsewhere), the Dialogue automatically shuts down, as he is no longer engaging in conversation.

We’re already doing that in PlayerController. The PlayerConversant just needs to be an IAction with a Cancel() that calls Quit and clears the target. I was under the impression that you’d already gotten that from the original post.

This is going to be very similar to Shopper… The AIConversant tells the PlayerConversant to StartDialogueAction() passing the AIConversant and Dialogue.
These are stored by StartDialogueAction, and ActionScheduler gets the StartAction call.
Update moves to within range of the AIConversant, and then calls StartDialogue()

All the building blocks for this are in this thread.

Ok so I just add ‘Quit()’ and clear my targetConversant in ‘PlayerConversant.IAction.Cancel()’ method, got it, and it works now. Thanks again Brian :slight_smile:

Ok I wanted to try this on my own before asking, but I am having a hard time with finding out what to cancel… My traits menu also needs the adjustment to be able to automatically shut down if we walk away or get suddenly attacked, or maybe even have another UI (like the bank) suddenly open up. Can we do this as one last request (hopefully) for this thread? After that we can try disabling the Shop and Dialogue UI when the pause menu is triggered, whenever you’re ready :sweat_smile:

Privacy & Terms