URL: https://wiki.studiominus.nl/tutorials/tutorialCustomAttachment.html
Title: People Playground Modding - Creating a custom weapon attachment
==================================================

Creating a custom weapon attachment
by Aspa102
Weapon attachments are created similarly to syringes.

Contents1. Creating an attachment spawnable2. Creating an unique attachment3. Creating an attachment variant4. Summary
1. Creating an attachment spawnable
using UnityEngine;

namespace Mod
{
    public class Mod
    {
        public static void Main()
        {
            // registering a custom item
            ModAPI.Register(
                new Modification()
                {
                    OriginalItem = ModAPI.FindSpawnable("Scope Attachment"), // derive from an attachment
                    NameOverride = "Bike Horn [mod name]",
                    DescriptionOverride = "A bike horn that goes on the top of a gun. Does what you think it does.",
                    CategoryOverride = ModAPI.FindCategory("Firearms"),
                    ThumbnailOverride = ModAPI.LoadSprite("horn view.png"),
                    AfterSpawn = (Instance) =>
                    {
                        // give the attachment a new sprite
                        Instance.GetComponent<SpriteRenderer>().sprite = ModAPI.LoadSprite("bikehorn.png");
                        Instance.FixColliders();

                        // while you can use a new sound for the connection sound, you can do this to keep the current sound
                        // each attachment can have a unique connection sound
                        AudioClip attach = Instance.GetComponent<ScopeAttachmentBehaviour>().ConnectClip;

                        // destroy the existing attachment behaviour
                        UnityEngine.Object.Destroy(Instance.GetComponent<ScopeAttachmentBehaviour>());

                        // add the new attachment behaviour (unless it already exists)
                        var attachment = Instance.GetOrAddComponent<BikeHornAttachmentBehaviour>();

                        // set the connection sound
                        attachment.ConnectClip = attach;

                        // here is some other stuff you can change
                        attachment.AttachmentType = FirearmAttachmentType.AttachmentType.Scope; // whether the attachment will connect to the top or bottom of the gun
                        attachment.AttachmentOffset = Vector2.zero; // the offset from the attachment point (generally only used if you want the sprite to be within the gun and stuf
                    }
                }
            );
        }
    }

    // define the attachment behaviour
    public class BikeHornAttachmentBehaviour : FirearmAttachmentBehaviour
    {
        // method that is called on connection
        public override void OnConnect() { }

        // method that is called on disconnection
        public override void OnDisconnect() { }

        // method that is called when the gun is fired
        public override void OnFire() { }

        // method that is called when a bullet hits an object
        public override void OnHit(BallisticsEmitter.CallbackParams args)
        {
            // args contains the position of the bullet, direction of the bullet, object that was hit, and the surface normal the bullet hit.
        }
    }
}


Most weapon attachments have a unique behaviour associated with them, exactly like how syringes do.
While this isn't strictly necessary, like how you can use the scope behaviour for any scopes, it allows for the creation of really unique and cool attachments.
2. Creating an unique attachment
The attachment we created in the above section doesn't actually do anything, so let's change that.
Instead of having the attachment do literally nothing, let's make it play a noise when the gun is fired.
public class BikeHornAttachmentBehaviour : FirearmAttachmentBehaviour
{
    public AudioClip HornNoise; // The audio clip that will play on fire

    public override void OnConnect() { }

    public override void OnDisconnect() { }

    public override void OnFire()
    {
        // on fire, get the physical behaviour and run the PlayClipOnce method
        // note that you don't need to have the 'clip:' parts in the method's parameters, it makes it easier to tell what the parameters you're setting.
        Phys.PlayClipOnce(clip: HornNoise, volume: 1.5f);
    }

    public override void OnHit(BallisticsEmitter.CallbackParams args) { }
}


Then we change the spawnable definition.
ModAPI.Register(
    new Modification()
    {
        OriginalItem = ModAPI.FindSpawnable("Scope Attachment"),
        NameOverride = "Bike Horn [mod name]",
        DescriptionOverride = "A bike horn that goes on the top of a gun. Does what you think it does.",
        CategoryOverride = ModAPI.FindCategory("Firearms"),
        ThumbnailOverride = ModAPI.LoadSprite("horn view.png"),
        AfterSpawn = (Instance) =>
        {
            Instance.GetComponent<SpriteRenderer>().sprite = ModAPI.LoadSprite("bikehorn.png");
            Instance.FixColliders();

            AudioClip attach = Instance.GetComponent<ScopeAttachmentBehaviour>().ConnectClip;

            UnityEngine.Object.Destroy(Instance.GetComponent<ScopeAttachmentBehaviour>());

            var attachment = Instance.GetOrAddComponent<BikeHornAttachmentBehaviour>();

            attachment.ConnectClip = attach;
            attachment.AttachmentType = FirearmAttachmentType.AttachmentType.Scope;
            attachment.AttachmentOffset = Vector2.zero;

            // setting the new audio clip
            attachment.HornNoise = ModAPI.LoadSound("bikehorn.wav");
        }
    }
);

Here is the final result:

    

3. Creating an attachment variant
The attachment above is completely unique and comes with their own functionality, but what if you want to make a variant of the scope attachment?
In order to do that, all you need to do is change the sprite and change some variables if you feel like it.
ModAPI.Register(
    new Modification()
    {
        OriginalItem = ModAPI.FindSpawnable("Scope Attachment"), // derive from an attachment
        NameOverride = "Hotdog Sight [mod name]",
        DescriptionOverride = "A hotdog with a hole drilled down the middle. Improves accuracy by 100%.",
        CategoryOverride = ModAPI.FindCategory("Firearms"),
        ThumbnailOverride = ModAPI.LoadSprite("hog view.png"),
        AfterSpawn = (Instance) =>
        {
            // give the attachment a new sprite
            Instance.GetComponent<SpriteRenderer>().sprite = ModAPI.LoadSprite("hog.png");
            Instance.FixColliders();

            // we're changing the accuracy percentage of the attachment
            // this should make the scope increase accuracy by 100%
            Instance.GetComponent<ScopeAttachmentBehaviour>().AccuracyPercent = 100;

            // change the connection sound if you feel like it
            Instance.GetComponent<ScopeAttachmentBehaviour>().ConnectClip = ModAPI.LoadSound("hotdog.wav");
        }
    }
);

4. Summary
In summary, this guide has shown how to:

Create a new unique attachment
Create an attachment variant

A mod has been created with these items within it here, and has been open sourced here.