recursal/Fanatic-Fandom huggingface dataset:
Placing speech audio from addressables

UPDATE: This script is now deprecated, since AC now supports the Addressables system natively.

Unity's addressable system provides a performant way of retrieving asset files at runtime, and this variant of the "Dialogue: Play speech" Action allows you to use them for speech audio.

To use it:

1. In the Speech Manager, set the Reference speech files field to By Naming Convention.
2. Create a folder and place in it a new C# script named ActionSpeechAddressable.cs.
3. In the Speech Manager, define this folder as a custom Actions directory to install this as a new "Dialogue: Play speech (addressables)" Action, which you should use instead of the default.
4. When lines are gathered, they will each have an expected filename.  Add each associated audio file to your addressables package, and give it the same name.

ActionSpeechAddressable.cs:

```
using UnityEngine;

using UnityEngine.ResourceManagement.AsyncOperations;

using UnityEngine.AddressableAssets;

using System.Collections.Generic;

namespace AC

{

	public class ActionSpeechAddressable : ActionSpeech

	{

		protected AudioClip addressableAudioClip;

		protected bool isAwaitingAddressible = false;

		public ActionSpeechAddressable ()

		{

			this.isDisplayed = true;

			category = ActionCategory.Dialogue;

			title = "Play speech (addressables)";

			lineID = -1;

		}

		public override void AssignValues (List<ActionParameter> parameters)

		{

			addressableAudioClip = null;

			isAwaitingAddressible = false;

			base.AssignValues (parameters);

		}

		private void OnCompleteLoad (AsyncOperationHandle<AudioClip> obj)

		{

			isAwaitingAddressible = false;

			StartSpeech (obj.Result);

		}

		public override float Run ()

		{

			if (!isRunning)

			{

				SpeechLine speechLine = KickStarter.speechManager.GetLine (lineID);

				string filename = speechLine.GetFilename ();

				Addressables.LoadAssetAsync<AudioClip> (filename).Completed += OnCompleteLoad;

				isAwaitingAddressible = true;

				isRunning = true;

				return defaultPauseTime;

			}

			if (isAwaitingAddressible)

			{

				return defaultPauseTime;

			}

			if (isBackground)

			{

				isRunning = false;

				return 0f;

			}

			return base.Run ();

		}

	}

}

```
Dynamic split-screen interactivity

When using AC's "Camera: Split-screen" Action, the screen is split into two camera views - with only one being interactive with the cursor. This script allows both views to be interactive, so that the mouse can be used in both.

To use it, create a new C# file named DynamicSplitScreen.cs, and attach to a GameObject in the scene. The "Camera: Split-screen" Action can be used as normal.

DynamicSplitScreen.cs:

```
using UnityEngine;
using AC;

public class DynamicSplitScreen : MonoBehaviour
{

 private Rect otherCameraRect;
 private bool isInSplitScreen;

 private void OnEnable ()
 {
 EventManager.OnCameraSplitScreenStart += OnCameraSplitScreenStart;
 EventManager.OnCameraSplitScreenStop += OnCameraSplitScreenStop;
 }

 private void OnDisable ()
 {
 EventManager.OnCameraSplitScreenStart += OnCameraSplitScreenStart;
 EventManager.OnCameraSplitScreenStop += OnCameraSplitScreenStop;
 }

 private void Update ()
 {
 if (isInSplitScreen)
 {
 Vector2 mousePosition = KickStarter.playerInput.GetMousePosition ();
 Vector2 mousePositionScreen = new Vector2 (mousePosition.x / ACScreen.width, mousePosition.y / ACScreen.height);

 if (otherCameraRect.Contains (mousePositionScreen))
 {
 KickStarter.mainCamera.SwapSplitScreenMainCamera ();
 }
 }
 }

 private void OnCameraSplitScreenStart (\_Camera \_splitCamera, CameraSplitOrientation \_splitOrientation, float \_splitAmountMain, float \_splitAmountOther, bool \_isTopLeftSplit)
 {
 if (\_splitOrientation == CameraSplitOrientation.Overlay)
 {
 return;
 }

 isInSplitScreen = true;
 otherCameraRect = KickStarter.mainCamera.GetSplitScreenRect (false);
 }

 private void OnCameraSplitScreenStop (\_Camera camera)
 {
 isInSplitScreen = false;
 }

}

```
Override inventory clicks

The behaviour of inventory menus can be altered by hooking into the OnMenuElementClick event, which is run whenever the user clicks inside a menu.

This script demonstrates how to build custom inventory behaviour through script. It shows how the standard behaviour of left-clicking to select/combine, right-click to examine, can be moved to a custom script.

To use it:

1. Set your InventoryBox element's "Inventory box type" property to "Custom Script"
2. Paste the code below into a C# file named OverrideInventory.cs
3. Attach the new Override Inventory component to a GameObject in the scene

OverrideInventory.cs:

```
using UnityEngine;
using AC;

public class OverrideInventory : MonoBehaviour
{

 private void OnEnable ()
 {
 EventManager.OnMenuElementClick += ElementClick;
 }

 private void OnDisable ()
 {
 EventManager.OnMenuElementClick -= ElementClick;
 }

 private void ElementClick (Menu menu, MenuElement element, int slot, int buttonPressed)
 {
 MenuInventoryBox menuInventoryBox = (MenuInventoryBox) element;
 if (menuInventoryBox != null && menuInventoryBox.inventoryBoxType == AC\_InventoryBoxType.CustomScript)
 {
 // Clicked inside a custom InventoryBox element

 InvInstance clickedInstance = menuInventoryBox.GetInstance (slot);
 if (InvInstance.IsValid (clickedInstance))
 {
 // Clicked on a valid item slot

 if (buttonPressed == 1)
 {
 // Left click
 InvInstance currentSelectedInstance = KickStarter.runtimeInventory.SelectedInstance;
 if (InvInstance.IsValid (currentSelectedInstance))
 {
 // Combine item with selected
 clickedInstance.Combine (currentSelectedInstance);
 }
 else
 {
 // Select item
 clickedInstance.Select ();
 }
 }
 else if (buttonPressed == 2)
 {
 // Right click examine
 clickedInstance.Examine ();
 }
 }
 }
 }

}

```
Fade 3D objects

This script allows 3D objects to be faded in and out.

The script is intended to work with the Standard shader in Unity's default render pipeline - it will need to be adapted to work with othe pipelines or shaders.

To use it:

1. Set the material's Shader to **Standard**, and set the **Rendering Mode** to **Fade**.
2. Copy/paste the code below into a C# script named **SetMaterialAlpha**.
3. Attach the new Set Material Alpha component to the object to fade.
4. Use either the **Object: Send message** or **Object: Call event** Actions to call the component's **TurnOff** and **TurnOn** functions to hide / show the object respectively.

SetMaterialAlpha.cs:

```
using UnityEngine;

public class SetMaterialAlpha : MonoBehaviour
{

 public float speed = 5f;
 private float targetAlpha = 1f;

 public void TurnOn ()
 {
 targetAlpha = 1f;
 }

 public void TurnOff ()
 {
 targetAlpha = 0f;
 }

 void Update ()
 {
 Color color = GetComponent<Renderer> ().material.color;
 float alpha = color.a;
 alpha = Mathf.MoveTowards (alpha, targetAlpha, Time.deltaTime \* speed);
 color.a = alpha;
 GetComponent<Renderer> ().material.color = color;
 }
}

```
Frame-flipping for Sprites Unity Complex characters

This script is used to automate the flipping of characters animated with the **Sprites Unity Complex** engine when facing a particular direction.

This is similar to the "Frame flipping" option when using the **Sprites Unity** engine, where left-facing animations can be flipped when facing right (and vice-versa).

To use:

1. Setup your character using the Sprites Unity Complex engine as normal
2. Update your Animator so that he plays the left-facing equivalent of any right-facing animation (or vice-versa) when appropriate.
3. Place the code below in a C# script named **SUC\_FrameFlip**
4. Place the script on the character and assign the fields - setting the charater's **Sprite child** as the Transform To Flip.
5. Tweak the Top Angle Freedom value to control how wide an angle a character can have when facing up or down before the script takes effect.

```

using UnityEngine;
using System.Collections;
using AC;
public class SUC_FrameFlip : MonoBehaviour
{
    [SerializeField] private AC.Char character;
    [SerializeField] private Transform transformToFlip;
    [SerializeField] private AC_2DFrameFlipping frameFlipping;
    [SerializeField] private float topAngleFreedom = 0f;
    private void Update ()
    {
        {
            return;
        }
        bool doFlip = false;
        float spriteAngle = character.GetSpriteAngle ();
        switch (frameFlipping)
        {
        	case AC_2DFrameFlipping.LeftMirrorsRight:
				doFlip = (spriteAngle >= 0f && spriteAngle < 180f);
        		break;
        	case AC_2DFrameFlipping.RightMirrorsLeft:
				doFlip = (spriteAngle > 180f && spriteAngle <= 360f);
        		break;
        	default:
        		return;
        }
        {
        	return;
        }
        if ((doFlip && transformToFlip.localScale.x > 0f) || (!doFlip && transformToFlip.localScale.x < 0f))
        {
            transformToFlip.localScale = new Vector3 (-transformToFlip.localScale.x, transformToFlip.localScale.y, transformToFlip.localScale.z);
        }
    }

}

```
Allow skipping of old Conversation options

This script causes a Conversation's previously-chosen dialog options to become skippable.

For it to work, you must rely on separate DialogOption ActionLists for each option, as opposed to checking **Override options?** in the **Dialogue: Start conversation** Action.

To use it, paste the code below into a C# file named **DynamicSkipConv**, and attach it to a GameObject in your scene.

```
using UnityEngine;
using System.Collections;
using AC;

public class DynamicSkipConv : MonoBehaviour
{

    private void OnEnable ()
    {
        EventManager.OnStartConversation += OnStartConversation;
    }

    private void OnDisable ()
    {
        EventManager.OnStartConversation -= OnStartConversation;
    }

    private void OnStartConversation (Conversation conversation)
    {
        foreach (ButtonDialog option in conversation.options)
        {
            if (option.assetFile != null)
            {
                option.assetFile.isSkippable = option.hasBeenChosen;
            }
            else if (option.dialogueOption != null)
            {
                option.dialogueOption.isSkippable = option.hasBeenChosen;
            }
        }
    }

}

```
Use items on an AC Character

Note: This tip will not be of use if the item you want to used has an Actionlist Asset attached to it (because such items react instantly/are used instantly-, so no dragging is available for them). If you need to trigger some other actions when you drop the item over the player you need to do it through the actionlist in the hotspot (not the item). (alverik)

The process to accomplish this is as follows:

* Place the Player on the default layer
* If 3D, make sure there is a Capsule Collider that serves as the Hotspot's "bounding box". If 2D, attach a Box Collider 2D to the sprite child. Make sure "Is Trigger" is checked.
* Add a Hotspot script to the same object as the collider and change the "Interaction source" to "Asset File"
* Create your Inventory interaction within an ActionList asset, and link it to the Hotspot as normal

The need for "ActionList assets" is so that the interaction works regardless of which scene you're in.

It's also to note that you could probably change the Actionlist asset on the fly during gameplay using scripting (Code pending). -Alverik.

-Tip provided by ChrisIceBox-
Using PlayMaker to control the Player

This is a simple (unoptimised) example script that shows how a PlayMaker FSM can be used to control an AC Player during gameplay. It works by enabling the attached FSM, and disabling AC's automatic Motion Control, during gameplay - and the reverse during cutscenes.

To use, place in a script named **PlayMakerControlPlayer**, attach to a Player object that also has a PlayMakerFSM component that is used to control the player's movement.

```
using System.Collections;

using System.Collections.Generic;

using UnityEngine;

using HutongGames.PlayMaker;

using AC;

public class PlayMakerControlPlayer : MonoBehaviour

{

	void Update ()

	{

		if (KickStarter.stateHandler && KickStarter.stateHandler.gameState == GameState.Cutscene)

		{

			// Disable custom movement

			GetComponent <PlayMakerFSM>().enabled = false;

			GetComponent <Player>().motionControl = MotionControl.Automatic;

		}

		else

		{

			// Enable custom movement

			GetComponent <PlayMakerFSM>().enabled = true;

			GetComponent <Player>().motionControl = MotionControl.Manual;

		}

	}

}

```
Trigger interactions on mouse-up

When the **Interaction method** is set to **Choose Hotspot Then Interaction**, available interactions are presented in a Menu upon clicking a Hotspot.  Choosing an interaction is then a case of clicking the intended icon.

This script reduces this to a single-click: holding the mouse down brings up the Interaction menu, and releasing the mouse runs the Interaction that the mouse is over (and closes the Menu otherwise).

To use it:

1. Set your Settings Manager's **Close interactions with** field to **Via Script Only**.
2. Copy/paste the code below into a C# script named **ClickUpInteractions**.
3. Attach the new **Click Up Interactions** component to a GameObject in the scene.

ClickUpInteractions.cs:

```
using UnityEngine;
using AC;

public class ClickUpInteractions : MonoBehaviour
{

 void Update ()
 {
 if (Input.GetMouseButtonUp (0) && KickStarter.playerMenus.IsInteractionMenuOn ())
 {
 MenuElement mouseOverElement = KickStarter.playerMenus.MouseOverMenuElement;
 if (mouseOverElement && mouseOverElement is MenuInteraction)
 {
 MenuInteraction menuInteraction = (MenuInteraction) mouseOverElement;
 menuInteraction.ParentMenu.TargetHotspot.RunUseInteraction (menuInteraction.iconID);
 }
 KickStarter.playerMenus.CloseInteractionMenus ();
 }
 }

}

```
Pinch input events

This script allows you to run events when pinching or spreading two fingers on mobile devices beyond a set distance. When testing in the Editor, such input can be simulated by moving the mouse vertically while holding the middle-mouse button.

To use it:

1. Create a new C# file named PinchInput and paste in the code below.
2. Attach the new Pinch Input component to an object in the scene, and fill in its Inspector.
3. To have ActionLists run when the events fire, invoke their Interact functions.

PinchInput.cs:

```
#if (UNITY\_IOS || UNITY\_ANDROID) && !UNITY\_EDITOR
#define MOBILE\_INPUT
#endif
using UnityEngine;
using UnityEngine.Events;

namespace AC
{

 public class PinchInput : MonoBehaviour
 {

 [SerializeField] private float pinchThreshold = 0.6f;
 [SerializeField] private bool eventsOnRelease = true;
 [SerializeField] private GameState reactDuringGameState;
 [SerializeField] private UnityEvent onPinch;
 [SerializeField] private UnityEvent onSpread;
 public bool IsPinching { get; private set; }
 public float RelativePinchDistance { get; private set; }
 private float startPinchDistance;

 private void LateUpdate ()
 {
 if (KickStarter.stateHandler.gameState != reactDuringGameState)
 {
 IsPinching = false;
 return;
 }

 if (Input\_StartPinch)
 {
 IsPinching = true;
 startPinchDistance = Input\_PinchDistance;
 }

 if (IsPinching)
 {
 if (Input\_EndPinch)
 {
 IsPinching = false;
 }
 else
 {
 float pinchDistance = (Input\_PinchDistance - startPinchDistance) / Screen.dpi;
 RelativePinchDistance = pinchDistance / pinchThreshold;
 }

 if ((IsPinching && !eventsOnRelease) || (!IsPinching && eventsOnRelease))
 {
 if (RelativePinchDistance >= 1f)
 {
 // Spread
 onSpread.Invoke ();
 IsPinching = false;
 }
 else if (RelativePinchDistance <= -1f)
 {
 // Pinch
 onPinch.Invoke ();
 IsPinching = false;
 }
 }
 }
 }

 private float Input\_PinchDistance
 {
 get
 {
 #if MOBILE\_INPUT
 return (Input.GetTouch (0).position - Input.GetTouch (1).position).magnitude;
 #else
 return Input.mousePosition.y;
 #endif
 }
 }

 private bool Input\_StartPinch
 {
 get
 {
 if (IsPinching) return false;

 #if MOBILE\_INPUT
 return Input.touchCount == 2 && Input.GetTouch (1).phase == TouchPhase.Began;
 #else
 return Input.GetMouseButtonDown (2);
 #endif
 }
 }

 private bool Input\_EndPinch
 {
 get
 {
 if (!IsPinching) return false;

 #if MOBILE\_INPUT
 return (Input.touchCount != 2);
 #else
 return !Input.GetMouseButton (2);
 #endif
 }
 }

 }

}

```
Limiting the times an ActionList can run

This script lets you set the number of times a scene-based ActionList (i.e. a Cutscene / Interaction / Trigger) can be run. If the limit has been exceeded, an alternative ActionList can be run in its place.

To use it:

1. Create a new C# script named ActionListRepeater.cs, and paste in the code below
2. Attach the new "Action List Repeater" component to the scene-based ActionList you wish to limit
3. In its Inspector, set its "Repeatable Amount" value and (optionally) an "ActionList On Fail".

ActionListRepeater.cs:

```
using UnityEngine;

using AC;

public class ActionListRepeater : MonoBehaviour

{

	public int repeatableAmount = -1;

	public ActionList actionListOnFail;

	private int timesPlayed;

	private void OnEnable ()

	{

		EventManager.OnBeginActionList += OnBeginActionList;

	}

	private void OnDisable ()

	{

		EventManager.OnBeginActionList -= OnBeginActionList;

	}

	private void OnBeginActionList (ActionList actionList, ActionListAsset actionListAsset, int startingIndex, bool isSkipping)

	{

		if (repeatableAmount >= 0 && actionList == GetComponent <ActionList>())

		{

			if (timesPlayed > repeatableAmount)

			{

				actionList.Kill ();

				if (actionListOnFail) actionListOnFail.Interact ();

				return;

			}

			timesPlayed ++;

		}

	}

}

```
Saving Remember data globally

Remember components are used to save data about objects in the scene, and are saved automatically when the game is saved or the scene is closed.

But if you have an object that's only in the scene for some of the time (i.e. spawned in temporarily and then removed), its Remember data will not be part of the save file. This script allows you to store such data in a Global variable when the object is disabled, and loaded in again when enabled.

To use it:

1. Create a new C# script named RememberToVariable.cs, and paste in the code below
2. Create a new Global Variable and set its Type to String
3. Attach the new Remember To Variable component to a prefab that gets spawned in and removed at runtime
4. In its Inspector, assign the Remember component you wish to save, as well as the ID of the variable to store its data in.

RememberToVariable.cs:

```
using UnityEngine;

namespace AC

{

	public class RememberToVariable : MonoBehaviour

	{

		[SerializeField] private int linkedVariableID = 0;

		[SerializeField] private Remember remember = null;

		private void OnEnable ()

		{

			GVar linkedVariable = GlobalVariables.GetVariable (linkedVariableID);

			if (linkedVariable != null && !string.IsNullOrEmpty (linkedVariable.TextValue) && remember)

			{

				remember.LoadData (linkedVariable.TextValue);

			}

		}

		private void OnDisable ()

		{

			GVar linkedVariable = GlobalVariables.GetVariable (linkedVariableID);

			if (linkedVariable != null && remember)

			{

				linkedVariable.TextValue = remember.SaveData ();

			}

		}

	}

}

```
Sync footstep sounds with collider materials

A character with the Footstep Sounds component will play walk and run sounds as they move around the scene. These sounds can be changed using the "Sound: Change footsteps" Action, placed in e.g. a Trigger. This script, however, allows you to change sounds automatically based on what surface the character is standing on.

To use:

1. For each floor collider that can be stood on, create and assign it a Unity "Physic Material" asset.
2. Create a new C# file named AutoSetFootstepSounds.cs, and paste in the code below.
3. Attach the new Auto Set Footstep Sounds component to your character.
4. Fill in the component's Inspector: assigning both the layer that the floor colliders are placed on, and create an entry for each created Physic Material in the "Footstep Materials" array, pairing the material with a set of footstep sounds.

AutoSetFootstepSounds.cs:

```
using UnityEngine;
using AC;

public class AutoSetFootstepSounds : MonoBehaviour
{

 [SerializeField] private LayerMask layerMask = new LayerMask ();
 [SerializeField] private float rayLength = 0.2f;
 [SerializeField] private FootstepMaterial[] footstepMaterials = new FootstepMaterial[0];

 private Char character;
 private FootstepSounds footstepSounds;
 private PhysicMaterial standingOnMaterial;

 private void Awake ()
 {
 character = GetComponent<Char> ();
 footstepSounds = GetComponentInChildren<FootstepSounds> ();
 }

 private void LateUpdate ()
 {
 Vector3 rayStart = transform.position + (0.5f \* rayLength \* Vector3.up);
 Debug.DrawRay (rayStart, Vector3.up \* -rayLength);
 RaycastHit hitInfo = new RaycastHit ();
 if (Physics.Raycast (rayStart, Vector3.down, out hitInfo, rayLength, layerMask))
 {
 if (hitInfo.collider.sharedMaterial && standingOnMaterial != hitInfo.collider.sharedMaterial)
 {
 standingOnMaterial = hitInfo.collider.sharedMaterial;
 OnStandMaterial (standingOnMaterial);
 }
 }
 }

 private void OnStandMaterial (PhysicMaterial material)
 {
 foreach (FootstepMaterial footstepMaterial in footstepMaterials)
 {
 if (footstepMaterial.Material == material)
 {
 footstepMaterial.Apply (footstepSounds);
 return;
 }
 }
 }

 [System.Serializable]
 private class FootstepMaterial
 {

 [SerializeField] private PhysicMaterial material = null;
 [SerializeField] private AudioClip[] walkSounds = new AudioClip[0];
 [SerializeField] private AudioClip[] runSounds = new AudioClip[0];

 public void Apply (FootstepSounds footstepSounds)
 {
 if (walkSounds.Length > 0)
 {
 footstepSounds.footstepSounds = walkSounds;
 }
 if (runSounds.Length > 0)
 {
 footstepSounds.runSounds = runSounds;
 }
 if (!footstepSounds.character.IsGrounded () && walkSounds.Length > 0)
 {
 footstepSounds.soundToPlayFrom.audioSource.clip = walkSounds[0];
 }
 }

 public PhysicMaterial Material { get { return material; } }

 }

}

```
Proximity-based Interaction menus

This script causes an Interaction menu to open automatically for the Hotspot closest to the Player.  Note that this requires AC v1.60.5 or newer.

First, set up your game to use proximity-based Hotspot detection (see this tutorial).

In your Settings Manager, set the following Interaction settings:

* Movement method -> Direct
* Interaction method -> Choose Hotspot Then Interaction
* Select Interactions by -> Clicking Menu
* See Interactions with -> Via Script Only
* Close Interactions With -> Via Script Only

Then create a new C# script named **InteractionOnNearest**:

```
using UnityEngine;
using AC;

public class InteractionOnNearest : MonoBehaviour
{

 public float minimumSqrDistance = 10f;

 private void Update ()
 {
 // Check if there is a player with a hotspot detector
 if (KickStarter.player && KickStarter.player.hotspotDetector)
 {
 // Read the nearest Hotspot to the detector
 Hotspot nearestHotspot = KickStarter.player.hotspotDetector.NearestHotspot;

 if (nearestHotspot && KickStarter.stateHandler.IsInGameplay () && (nearestHotspot.transform.position - KickStarter.player.hotspotDetector.transform.position).sqrMagnitude < minimumSqrDistance)
 {
 // If there is a Hotspot nearby, and it's during gameplay, show Interaction menus for that Hotspot
 KickStarter.playerMenus.EnableInteractionMenus (nearestHotspot);
 }
 else
 {
 // Otherwise, close Interaction menus
 KickStarter.playerMenus.CloseInteractionMenus ();
 }
 }

 }

}

```

Attach this either to an object in your scene, or to your Player prefab.  Interaction menus will now turn on automatically for the Hotspot within the detector that is nearest the player.
NavMesh Agent Wrap

A simple action to teleport NavMesh Agent to a position on scene.

```

```

```
☀/*

 *	Adventure Creator

 *	by Chris Burton, 2013-2016

 *	"ActionTemplate.cs"

 *	This is a blank action template.

 */

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

#if UNITY_EDITOR

using UnityEditor;

#endif

namespace AC

{

	[System.Serializable]

	public class ActionNavMeshWrap : Action

	{

        // Declare variables here

        public bool isPlayer;

        public UnityEngine.AI.NavMeshAgent Agent;

        public Transform WarpPosition;

        public ActionNavMeshWrap()

		{

			this.isDisplayed = true;

			category = ActionCategory.Custom;

			title = "Navmesh Wrap";

			description = "Wraps Navmesh position";

		}

        public override void AssignValues(List<ActionParameter> parameters)

        {

            base.AssignValues(parameters);

            if (isPlayer)

            {

                Agent = KickStarter.player.GetComponent<UnityEngine.AI.NavMeshAgent>();

            }

        }

        override public float Run ()

		{

            /*

			 * This function is called when the action is performed.

			 * The float to return is the time that the game

			 * should wait before moving on to the next action.

			 * Return 0f to make the action instantenous.

			 * For actions that take longer than one frame,

			 * you can return "defaultPauseTime" to make the game

			 * re-run this function a short time later. You can

			 * use the isRunning boolean to check if the action is

			 * being run for the first time, eg:

			 */

            if (Agent && WarpPosition)

            {

                Agent.Warp(WarpPosition.position);

            }

            return 0f;

        }

		#if UNITY_EDITOR

		override public void ShowGUI ()

		{

            // Action-specific Inspector GUI code here

            isPlayer = EditorGUILayout.Toggle("Is Player?", isPlayer);

            if (isPlayer)

            {

                if (Application.isPlaying)

                {

                    Agent = KickStarter.player.GetComponent<UnityEngine.AI.NavMeshAgent>();

                }

                else if (AdvGame.GetReferences().settingsManager)

                {

                    Agent = AdvGame.GetReferences().settingsManager.GetDefaultPlayer().GetComponent<UnityEngine.AI.NavMeshAgent>();

                }

            }

            else

                Agent = (UnityEngine.AI.NavMeshAgent)EditorGUILayout.ObjectField("Navmesh Agent:", Agent, typeof(UnityEngine.AI.NavMeshAgent), true);

            WarpPosition = (Transform)EditorGUILayout.ObjectField("Warp Position:", WarpPosition, typeof(Transform), true);

            AfterRunningOption ();

		}

		public override string SetLabel ()

		{

            // Return a string used to describe the specific action's job.

            if (isPlayer)

            {

                return " (Player)";

            }

            else if (Agent)

            {

                return (" (" + Agent.name + " - " + WarpPosition.ToString() + ")");

            }

            return "";

        }

		#endif

	}

}

```
Rogo Lipsync (No audio) 03 - Set Emotion Action

Note: This is an alternative integration for Rogo LipSync and is intended to allow emotions and mouth movement to be played independently from any audio. The integration consists of three AC actions. These will be posted in separate articles to avoid clutter.

Author's quote:

> Use this as a means to have emotions/mouth movement that plays with text (no audio) and limit the .asset files to just a handful - short speech, medium speech, long speech. I also use it for asset files that just sync gestures and emotions.
>
>

To use it replace the text in a .cs file named RogoLipSync\_SetEmotion with this text, or create a new blank text file, then paste the text and rename the file RogoLipSync\_SetEmotion.cs. Then drop the file into the folder named actions inside the Adventure creator folder. Then, just use the action in an action list.

The code for the Set Emotion action is as follows:

```
using UnityEngine;
using System.Collections;
using RogoDigital.Lipsync;

#if UNITY_EDITOR
using UnityEditor;
#endif

 namespace AC
 {
     [System.Serializable]
    public class RogoLipSync_SetEmotion : Action
     {
         public bool isPlayer;
        public LipSync lipSyncTarget;
        public string emotion;
        public float blendTime;

         public RogoLipSync_SetEmotion()
        {
             this.isDisplayed = true;
            category = ActionCategory.Custom;
            title = "Rogo LipSync - Set Emotion";
            description = "Blends a LipSync emotion on a LipSync component";
            isPlayer = true;

         }

         override public float Run()
        {
             if (isPlayer)
            {
                 lipSyncTarget = KickStarter.player.GetComponent<LipSync>();

                if (lipSyncTarget == null)
                {
                    Debug.LogWarning("RogoLipSync_Play: No LipSync component found on Player.");
                    return 0f;
                }
            }

             else if (lipSyncTarget == null)
            {
                 Debug.LogWarning("RogoLipSync_Play: No LipSync component defined.");
                return 0f;
            }

             lipSyncTarget.SetEmotion(emotion, blendTime);
            return 0f;
        }

         override public void Skip()
        {

         }

 #if UNITY_EDITOR
        override public void ShowGUI()
        {
             isPlayer = EditorGUILayout.Toggle("Is player?", isPlayer);

            if (!isPlayer)
            {
                 lipSyncTarget = (LipSync)EditorGUILayout.ObjectField("Character:", lipSyncTarget, typeof(LipSync), true);
            }

             emotion = EditorGUILayout.TextField("Emotion:", emotion);
            blendTime = EditorGUILayout.Slider("Blend Time:", blendTime, 0f, 5f);
            AfterRunningOption();
        }
 #endif
     }
 }

```

It's also important to note that this specific action (SetEmotion) may not play if there is a competing animation already playing at the time.

-Original code provided by user Larsos-
Global Timer

The following script can be used to automatically reduce a Global Integer variable's value by 1 every second, and run an ActionList asset when it hits zero.

To use it, paste the following code into a C# script named VariableTimer.cs, and add the Variable Timer component to your scene. Configure its Inspector to create a new timer by assigning the ID number of the variable you wish to countdown.

To have the timer begin, either check "Run On Awake", or use either the "Object: Call event" or "Object: Send message" Actions to call the component's "Begin" function.

VariableTimer.cs:

```
using UnityEngine;
using AC;

public class VariableTimer : MonoBehaviour
{

 public int globalIntegerVariableID;
 public Cutscene cutsceneOnHitZero = null;
 public ActionListAsset actionListOnHitZero = null;
 public bool runOnAwake;

 private float ticker = 1f;
 private int i;
 private GVar variable;
 private bool doCountdown;

 private void Awake ()
 {
 doCountdown = runOnAwake;
 }

 public void Begin ()
 {
 doCountdown = true;
 }

 public void End ()
 {
 doCountdown = false;
 }

 private void Update ()
 {
 ticker -= Time.deltaTime;
 if (ticker <= 0f)
 {
 ticker = 1f;

 if (variable == null)
 {
 variable = GlobalVariables.GetVariable (globalIntegerVariableID);
 }
 if (variable == null)
 {
 Debug.LogWarning ("AC Global Variable with ID=" + globalIntegerVariableID + " not found!");
 }

 if (doCountdown && variable != null && variable.IntegerValue > 0)
 {
 variable.IntegerValue --;
 if (variable.IntegerValue == 0)
 {
 doCountdown = false;

 if (actionListOnHitZero)
 {
 actionListOnHitZero.Interact ();
 }
 if (cutsceneOnHitZero)
 {
 cutsceneOnHitZero.Interact ();
 }
 }
 }
 }
 }

}

```
Simple Global Timer

Note: this can be used to create a simple global timer for your game.

> You can create a Global integer Variable to store the number of e.g. seconds that have passed since your game begins.
>
>
>
>
>
>
>
>
> Create a new ActionList that's set to Run In Background, and have it run a Variable: Set Action to increase the integer's value by 1, then an Engine: Wait Action to wait 1 second, then loop back to the first Action.  If you then assign this as your ActionList on start game (in the Settings Manager), it'll track how many seconds have passed.
>
>

You can then use those seconds to calculate hours and minutes by putting an actionlist running in parallel (or generally at the same time). Just have two other Global variable to store the minutes and the hours, then do the following calculations (should be possible to do this in the Variable:set using tokens):

Minutes = Seconds / 60

Hours = minutes / 60

Then just finalize it with a Engine:Wait to hold for 1 second and loop back to the beginning of the actionlist to repeat. That should give you a basic timer for your game.

[Original tip was provided by ChrisIceBox, extended by Alerik]
Adjust 2d light intensity

Save this to your custom actions folder.

The action requires a **2d light** (this won't work with 3d lights). To learn more about Unity's new 2d lighting system, see here:

https://docs.unity3d.com/Packages/com.unity.render-pipelines.lightweight@6.7/manual/2DLightProperties.html

 You also must provide a float to set the intensity. You can set the intensity to 0 to turn the light off.

This script can probably be extended to cover adjusting all the options in a 2d light.

NOTE: When copying the script, it's essential you copy the following line:

using UnityEngine.Experimental.Rendering.Universal;

```
using UnityEngine;

using System;

using UnityEngine.Experimental.Rendering.Universal;

#if UNITY_EDITOR

using UnityEditor;

#endif
   /* By Meffy1122
   * Custom action to
* Change 2d light intensity.
*/

   namespace AC
   {

       [System.Serializable]
    public class ChangeLightIntensity: Action

    {

           // Declare variables here

        public float intensity;

        public Light2D light;
        public float intensityField;

        public ChangeLightIntensity()
        {
               this.isDisplayed = true;
            category = ActionCategory.Custom;
            title = "Change light intensity";
            description = "Changes light intensity";
        }

           override public float Run()
        {
               light.intensity = intensityField;
            return 0f;

        }

   #if UNITY_EDITOR

        public override void ShowGUI()
        {
             light = (Light2D)EditorGUILayout.ObjectField("Light to affect:", light, typeof(Light2D), true);

         intensityField = (float)EditorGUILayout.FloatField("New light intensity:", intensityField);

            AfterRunningOption();
        }
   #endif    //end the action
    }

   }

```
2.5D games with URP

AC's 2.5D camera mode involves rendering the background and characters with separate cameras, and ovelaying them together.

Unity's Universal Render Pipeline uses its own technique to overlay multiple cameras, so this script will make the necessary changes to a 2.5D scene to allow it to work with URP.

To use it, paste the script below into a C# file named URP\_25D.cs and attach it as a component to a GameObject in the scene:

```
using UnityEngine.Rendering.Universal;
using UnityEngine;
using AC;

public class URP\_25D: MonoBehaviour
{

 private void OnEnable () { EventManager.OnSwitchCamera += OnSwitchCamera; }
 private void OnDisable () { EventManager.OnSwitchCamera -= OnSwitchCamera; }

 private void Awake ()
 {
 Camera backgroundCamera = BackgroundCamera.Instance.GetComponent<Camera> ();
 var backgroundCameraData = backgroundCamera.GetUniversalAdditionalCameraData ();
 backgroundCameraData.renderType = CameraRenderType.Overlay;

 var mainCameraData = KickStarter.mainCamera.Camera.GetUniversalAdditionalCameraData ();
 if (!mainCameraData.cameraStack.Contains (backgroundCamera))
 {
 mainCameraData.cameraStack.Add (backgroundCamera);
 }
 }

 private void Start ()
 {
 GameCamera25D[] gameCamera25Ds = FindObjectsOfType<GameCamera25D> ();
 foreach (GameCamera25D gameCamera25D in gameCamera25Ds)
 {
 gameCamera25D.Camera.enabled = true;

 var cameraData = gameCamera25D.Camera.GetUniversalAdditionalCameraData ();
 cameraData.renderType = CameraRenderType.Overlay;
 }
 }

 private void OnSwitchCamera (\_Camera fromCamera, \_Camera toCamera, float transitionTime)
 {
 var mainCameraData = KickStarter.mainCamera.Camera.GetUniversalAdditionalCameraData ();
 if (fromCamera && mainCameraData.cameraStack.Contains (fromCamera.Camera))
 {
 mainCameraData.cameraStack.Remove (fromCamera.Camera);
 }

 if (!mainCameraData.cameraStack.Contains (toCamera.Camera))
 {
 var gameCameraData = toCamera.Camera.GetUniversalAdditionalCameraData ();
 gameCameraData.renderType = CameraRenderType.Overlay;
 mainCameraData.cameraStack.Add (toCamera.Camera);
 }
 }
}

```
Life Is Strange-style interactions

Life Is Strange gameplay involves moving the character with direct movement, and then having Hotspot labels appear for nearby interactive objects.  An Interaction menu turns on automatically for the closest Hotspot, and interactions within that Menu are run by pressing a dedicated input button:

Two scripts are necessary:

Simultaneous Hotspot labels

Proximity-based Interaction menus

In addition to the fields set in the above, set the following in your Settings Manager:

(Under Interaction settings)
Movement method -> Direct

(Under Hotspot settings)
Hotspot detection method -> Player Vicinity
Hotspots in vicinity -> Show All

Then in the Menu Manager, create a new Interaction menu (or modify the default) and give each Interaction icon an Alternative input button.  The name entered here must match with an input name listed in your Unity Input manager (Edit -> Project settings -> Input).
Sorting 3D characters in 2D scenes

3D characters are possible in 2D games and scenes.  However, since Follow Sorting Maps are only able to control the dislay order of sprite shaders, it's not possible to properly control their depth display (relative to other scene objects and characters) without relying on a custom shader.

This script offers an alternative approach - by having each object and character rendered by a separate camera, and then controlling the display order of each camera.

**(Note: This script requires AC v1.64.0 or later)**

To use this method:

1. Set up the scene's Sorting Map as normal, and place Follow Sorting Maps on your character(s).
2. Place each character, and mid-scene sprite (i.e. objects the characters can move in front of and behind) on separate, dedicated layers - e.g. place the Player on a layer named "Player", a chair object on "Chair" etc.
3. Create a new Camera for each new layer as a child of the MainCamera.  Set the Clear Flags to Depth only, and the Culling Mask to just one of these new layers each.
4. Attach the script below onto each new Camera.  For cameras that render characters, assign that character's Follow Sorting Map in the script's Inspector.
5. For cameras that render scene sprites, set the Camera's Depth value to match that sprite's Sorting Order value.
6. Remove these new layers from the MainCamera's Culling Mask field.

SortingDepthCam.cs:

```
using UnityEngine;

using System.Collections;

using AC;

public class SortingDepthCam : MonoBehaviour

{

	private Camera ownCamera;

	public FollowSortingMap followSortingMap;

	private void Start ()

	{

		ownCamera = GetComponent <Camera>();

	}

	private void LateUpdate ()

	{

		ownCamera.transform.position = Camera.main.transform.position;

		ownCamera.transform.rotation = Camera.main.transform.rotation;

		ownCamera.projectionMatrix = Camera.main.projectionMatrix;

		ownCamera.orthographicSize = Camera.main.orthographicSize;

		ownCamera.fieldOfView = Camera.main.fieldOfView;

		if (followSortingMap != null)

		{

			ownCamera.depth = followSortingMap.SortingOrder - ((float) followSortingMap.SharedDepth / 10f);

		}

	}

}

```
Change a menu's "Appear type" at runtime

This custom Action allows you to change a menu's "Appear type" property at runtime. To use it, place the code below in a C# script named ActionChangeMenuAppearType.cs, and place the file in your custom Actions folder. For more on custom Actions and such folders, see this tutorial.

ActionChangeMenuAppearType.cs

```
using UnityEngine;

using System.Collections;

#if UNITY_EDITOR

using UnityEditor;

#endif

namespace AC

{

	public class ActionChangeMenuAppearType : Action

	{

		public string menuName;

		public AppearType newAppearType;

		public ActionChangeMenuAppearType ()

		{

			this.isDisplayed = true;

			category = ActionCategory.Menu;

			title = "Change appear type";

		}

		override public float Run ()

		{

			Menu menu = AC.PlayerMenus.GetMenuWithName (menuName);

			if (menu != null)

			{

				menu.appearType = newAppearType;

			}

			return 0f;

		}

		#if UNITY_EDITOR

		override public void ShowGUI ()

		{

			menuName = EditorGUILayout.TextField ("Menu name:", menuName);

			newAppearType = (AppearType) EditorGUILayout.EnumPopup ("New appear type:", newAppearType);

			AfterRunningOption ();

		}

		#endif

	}

}

```
Custom Tokens Example

Note: this is a simple example regarding Custom Token usage.

There are two parts to the process of creating custom tokens. First you need to create them and give them a value. This can be done n the Start() or Awake() function or you can create a function a launch it specifically when you want it.

To create a token you use the following line:

```
KickStarter.runtimeVariables.SetCustomToken (IntId, stringToShow);

```

The code takes two parameters, the first is the Id you want the token to have. This can be set to whatever you need. The second parameter is the string to be stored in the token. Take note that whenever you run the above code the Token with that specific Id will be overwritten/updated.

The second step is to use the new token within AC. This is simple, just type **[token:0]** inside any AC Label or element which displays text. In the example 0 represents the IntId you assigned to the token.

An example of usage would be:

```
void CalculateTokens()
	{
		KickStarter.runtimeVariables.SetCustomToken (0, NumberToshow1.ToString("#.#"));
		KickStarter.runtimeVariables.SetCustomToken (1, NumberToshow2.ToString("#.#"));
		KickStarter.runtimeVariables.SetCustomToken (2, NumberToshow3.ToString("#.#"));
	}

```

With the above code you would have 3 new tokens at your disposal **[token:0],[token:1],[token:2]**.You would run this function every time a menu or menu element containing the token is opened, to make sure the token stays up to date. if you need the value to update continuously (like to show a score incrementing) you could create a loop to run until the user or scripts finishes running, or simply fire the function every time the score is updated (which would have the same effect in that case).

-Original tip provided by ChrisIceBox. Reformulated and expanded by Alverik-
Prerendered videos as backdrop during cutscenes or general gameplay

Note: this is useful if you want to have a prerendered videos play as a backdrop during cutscenes or during normal gameplay.

> There are a couple of ways to do this:
>
>

1. AC allows for the playback of movie files with the Engine: Play movie clip Action.  On desktop platforms, you have an additional option to play a movie file as a texture - meaning you can have a movie play on a square plane and position it in front of both the camera and the player.
2. If you imported each frame of the sequence as a separate image file into Unity, you could combine them into a single animated sprite within Unity (using Unity's built-in animation tools).  This might give way to larger file-sizes, but may be more flexible if you want to easily transition from one animation to another

[Original tip provided by ChrisIceBox]
Changing Cinemachine camera priority

UPDATE: A package that provides integration with Cinemachine can be found on AC's Downloads page. The original script is below.

This custom Action allows you to change the priority of a Cinemachine camera. It is provided by @shredingskin on the AC forum.

An alternative script can be found here.

```
using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using Cinemachine;

#if UNITY_EDITOR

using UnityEditor;

#endif

namespace AC

{

	[System.Serializable]

	public class ActionCinemachineCamera : Action

	{

		public CinemachineVirtualCameraBase CM_cam;

		public int cmCamConstantID = 0;

		public int cmCamParameterID = -1;

		private CinemachineVirtualCameraBase runtimeCMCam;

		public int Priority;

		public int priorityParameterID = -1;

		public ActionCinemachineCamera()

		{

			this.isDisplayed = true;

			category = ActionCategory.Camera;

			title = "CM Priority";

			description = "Changes CM priority";

		}

		public override void AssignValues (List<ActionParameter> parameters)

		{

			runtimeCMCam = AssignFile <CinemachineVirtualCameraBase> (parameters, cmCamParameterID, cmCamConstantID, CM_cam);

			Priority = AssignInteger (parameters, priorityParameterID, Priority);

		}

		override public float Run()

		{

			if (runtimeCMCam)

			{

				runtimeCMCam.enabled = true;

				runtimeCMCam.MoveToTopOfPrioritySubqueue();

				runtimeCMCam.Priority = Priority;

			}

			return 0f;

		}

		#if UNITY_EDITOR

		override public void ShowGUI (List<ActionParameter> parameters)

		{

			cmCamParameterID = Action.ChooseParameterGUI ("CM camera:", parameters, cmCamParameterID, ParameterType.GameObject);

			if (cmCamParameterID >= 0)

			{

				cmCamConstantID = 0;

				CM_cam = null;

			}

			else

			{

				CM_cam = (CinemachineVirtualCameraBase) EditorGUILayout.ObjectField ("CM Camera:", CM_cam, typeof(CinemachineVirtualCameraBase), true);

				cmCamConstantID = FieldToID <CinemachineVirtualCameraBase> (CM_cam, cmCamConstantID);

				CM_cam = IDToField <CinemachineVirtualCameraBase> (CM_cam, cmCamConstantID, true);

			}

			priorityParameterID = Action.ChooseParameterGUI ("Priority:", parameters, priorityParameterID, ParameterType.Integer);

			if (priorityParameterID < 0)

			{

				Priority = EditorGUILayout.IntField ("Priority:", Priority);

			}

			AfterRunningOption ();

		}

		#endif

	}

}

```
Control Blendshapes in speech text

The [expression:ID] token, when inserted into speech text, allows you to change a character's expression - provided you've set up Animation parameters or shapekeys.

However, it doesn't offer much control beside which expression to change to. The script below allows you to set shape key values with control over their intensity and transition time - through use of the token syntax:

**[shape:group\_key\_value\_transition]**

where:

* **shape** is the token key (don't change this)
* **group** is replaced by the group ID
* **key** is replaced by the label of the key within that group
* **value** is replaced by the new value
* **transition** is replaced by the transition time

When inserted into a character's speech text, this token will then be processed and used to update the character's Shapeable component, provided they have one.

To use it:

1. Create a new C# script named ShapeableTokens.cs and paste in the script below
2. Attach thew new Shapeable Tokens component to any character's root that you want to be able to use this.
3. Each such character must have a Shapeable component in their hierarchy, with their shapekeys defined in the Inspector
4. The [shape:X] token detailed above can then be inserted into their speech text.

ShapeableTokens.cs:

```
	using UnityEngine;

	using AC;

	public class ShapeableTokens : MonoBehaviour

	{

		private void OnEnable ()

		{

			KickStarter.dialog.SpeechEventTokenKeys = new string[1] { "shape" };

			EventManager.OnSpeechToken += OnSpeechToken;

		}

		private void OnDisable () { EventManager.OnSpeechToken -= OnSpeechToken; }

		private void OnSpeechToken (AC.Char speakingCharacter, int lineID, string tokenKey, string tokenValue)

		{

			if (speakingCharacter != GetComponent <AC.Char>()) return;

			if (tokenKey == "shape")

			{

				string[] valueArray = tokenValue.Split ("_"[0]);

				if (valueArray.Length == 4)

				{

					int groupID = 0;

					string keyName = valueArray[1];

					float value = 0f;

					float transition = 0f;

					if (int.TryParse (valueArray[0], out groupID) &&

						float.TryParse (valueArray[2], out value) &&

						float.TryParse (valueArray[3], out transition))

					{

						Shapeable shapeable = speakingCharacter.GetComponentInChildren <Shapeable>();

						shapeable.SetActiveKey (groupID, keyName, value, transition, MoveMethod.Smooth, null);

					}

				}

			}

		}

	}

```