# Puzzles

### Adding New Puzzles

{% hint style="info" %}
You can create two types of puzzles: complex puzzles that change the camera and derive from **PuzzleBase**, or simple puzzles that only disable interaction and derive from **PuzzleBaseSimple**.
{% endhint %}

1. Write a new script and derive it from **PuzzleBase** or **PuzzleBaseSimple** based on your specific requirements.

<div><figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2FbZmJhV20RylU2H4Ah3o1%2FScreenshot_4.png?alt=media&#x26;token=1e007eae-c4ed-4c67-b1b0-fa9a850a1387" alt=""><figcaption><p>Complex Puzzle</p></figcaption></figure> <figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2FsuTXiLwVvXkQux4KOnMW%2FScreenshot_5.png?alt=media&#x26;token=72e56839-cd2c-4c50-9fa7-cb11b901b13c" alt=""><figcaption><p>Simple Puzzle</p></figcaption></figure></div>

2. When deriving from Puzzle Base, the script inspector may look messy. To tidy it up, you can write a basic editor script and place it in the Editor folder. For instance, you can name the script <mark style="background-color:red;">**Test**</mark><mark style="background-color:green;">**PuzzleEditor**</mark>.

{% tabs %}
{% tab title="TestPuzzle" %}

```csharp
using UHFPS.Runtime;

// derive from PuzzleBase or PuzzleBaseSimple
public class TestPuzzle : PuzzleBase
{
    public string TestString;
    public float TestFloat;
}
```

{% endtab %}

{% tab title="TestPuzzleEditor" %}

```csharp
using UnityEngine;
using UnityEditor;
using ThunderWire.Editors;

namespace UHFPS.Editors
{
    [CustomEditor(typeof(TestPuzzle))]
    // derive from PuzzleEditor<T> or PuzzleSimpleEditor<T>
    public class TestPuzzleEditor : PuzzleEditor<TestPuzzle>
    {
        public override void OnEnable()
        {
            // when overriding OnEnable(), do not remove the base.OnEnable()
            base.OnEnable();
        }

        public override void OnInspectorGUI()
        {
            EditorDrawing.DrawInspectorHeader(new GUIContent("Test Puzzle"), Target);
            EditorGUILayout.Space();

            serializedObject.Update();
            {
                base.OnInspectorGUI(); // this will draw settings dropdown
                EditorGUILayout.Space();

                Properties.Draw("TestString");
                Properties.Draw("TestFloat");
            }
            serializedObject.ApplyModifiedProperties();
        }
    }
}
```

{% endtab %}
{% endtabs %}

<figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2FC8EgJ0udIevIVXrXaw2z%2FScreenshot_6.png?alt=media&#x26;token=4baa6f81-8df6-4b60-9fa4-a13252544244" alt=""><figcaption><p>Test Puzzle script with Custom Editor</p></figcaption></figure>

{% hint style="info" %}
To draw script properties, you can follow the same process as when creating an editor script for the Player Item script.
{% endhint %}

3. Create a new **Cinemachine Virtual Camera** by selecting **GameObject -> Cinemachine -> Virtual Camera** and add it to the puzzle object. Then assign it to the **Puzzle Camera** field in the **Puzzle Base Settings**.

<figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2FhY4kpj5rgAD6JtwfkNgs%2FScreenshot_7.png?alt=media&#x26;token=a5a11ecb-c656-4f2d-88c5-c082f7b5f82c" alt=""><figcaption></figcaption></figure>

4. Within the **Cinemachine Virtual Camera** component, set **Body** to **Do nothing** and **Aim** to **Do nothing**. Then, disable the object.

{% hint style="danger" %}
Be sure to disable the **Virtual Camera** object, as Cinemachine will automatically switch to the active virtual camera object.
{% endhint %}

{% hint style="info" %}
**PuzzleBase** or **PuzzleBaseSimple** contain the base functions and properties for puzzles, so it's worth examining what's included in these classes to ensure proper usage. The functions are commented, so it should be easy to determine what you can use in your script. Remember to include the <mark style="color:red;">**base.**</mark> call when overriding the methods.
{% endhint %}

5. Assign the controls for your puzzle that will be displayed on the puzzle screen to the **Controls Format** field. The controls should follow this format: **\[action] Action Title**.

{% hint style="info" %}
To create new controls, you can refer to the instructions on the [Localization ](https://docs.twgamesdev.com/uhfps/guides/broken-reference)page or select the magnifying glass icon and assign existing controls.
{% endhint %}

<figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2Fh614Y1DVCTMgTHcK29Ty%2FScreenshot_1.png?alt=media&#x26;token=58fe5d5b-cb2c-4b49-8ab5-5953a7837c94" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
After completing the previous steps, when you interact with the object, the camera should switch to a puzzle camera with a pointer. The puzzle pointer uses the **IInteractStart** interface to interact with the puzzle object. To enable puzzle colliders, simply specify **Colliders Enable** or **Colliders Disable**. So, when you interact with a puzzle, you should enable puzzle colliders so that you can only interact with puzzle objects when you are on the puzzle screen.
{% endhint %}

### Lockpick Puzzle

1. To use lockpick puzzle, add the **Lockpick Interact** component to the puzzle object.
2. Assign a **Lockpick Model** that includes the **Lockpick Component** script. You can choose from **Lockpick\_Chest** or **Lockpick\_Door**.

<figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2F00HOaq9JnMHH915Q16ak%2FScreenshot_4.png?alt=media&#x26;token=6ef9cfed-81cc-4b43-941e-f1f2ad6eba34" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
If you want to display a lockpick screen when interacting with a locked door, simply enable the **Is Dynamic Unlock Component** toggle. This will disable the **On Unlock** event and instead it will unlock the dynamic door. Then simply assign the **Unlock Script** with **Lockpick Interact**.
{% endhint %}

<figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2FiwNex808ClxHyVg6DBw3%2FScreenshot_7.png?alt=media&#x26;token=506a65c8-08d3-4bc6-90f3-d033a223895c" alt=""><figcaption></figcaption></figure>

3. Select the **Bobby Pin Item**, by clicking the circular button located to the right of the **Item Guid** field.

<figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2FquqHnXedUvcsjOyAnsNS%2FScreenshot_5.png?alt=media&#x26;token=79bf9e3f-412a-4bf5-9142-2127ef5db971" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Now you should be able to interact with the puzzle object that displays the lockpicking screen.
{% endhint %}

<figure><img src="https://2665493337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh8bp6Jx5qkS4c0NEaWR1%2Fuploads%2FpPdliiWPPlxbdLZ18TIp%2FScreenshot_8.png?alt=media&#x26;token=32bc819a-0448-46ac-a76b-41b896db9052" alt=""><figcaption></figcaption></figure>
