Skip to content

Commit 508af6f

Browse files
committed
sfx API
1 parent 72f87e8 commit 508af6f

File tree

7 files changed

+289
-3
lines changed

7 files changed

+289
-3
lines changed

ClickerCompat.cs

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ internal static void SetClickerWeaponDefaults(Item item)
6767
ClickerClass?.Call("SetClickerWeaponDefaults", versionString, item);
6868
}
6969

70+
/// <summary>
71+
/// Call in <see cref="ModItem.SetDefaults"/> to set important default fields for a "sfx button". Set fields:
72+
/// maxStack.
73+
/// Only change them afterwards if you know what you are doing!
74+
/// </summary>
75+
/// <param name="item">The <see cref="Item"/> to set the defaults for</param>
76+
internal static void SetSFXButtonDefaults(Item item)
77+
{
78+
ClickerClass?.Call("SetSFXButtonDefaults", versionString, item);
79+
}
80+
7081
/// <summary>
7182
/// Call in <see cref="ModProjectile.SetDefaults"/> to set important default fields for a clicker projectile. Set fields:
7283
/// DamageType.
@@ -108,7 +119,7 @@ internal static void RegisterClickerItem(ModItem modItem)
108119
}
109120

110121
/// <summary>
111-
/// Call this in <see cref="ModType.SetStaticDefaults"/> to register this weapon into the "clicker class" category as a "clicker".
122+
/// Call this in <see cref="ModType.SetStaticDefaults"/> to register this weapon into the "clicker class" category as a "clicker".<br/>
112123
/// Do not call <see cref="RegisterClickerItem"/> with it as this method does this already by itself
113124
/// </summary>
114125
/// <param name="modItem">The <see cref="ModItem"/> that is to be registered</param>
@@ -118,6 +129,18 @@ internal static void RegisterClickerWeapon(ModItem modItem, string borderTexture
118129
ClickerClass?.Call("RegisterClickerWeapon", versionString, modItem, borderTexture);
119130
}
120131

132+
/// <summary>
133+
/// Call this in <see cref="ModType.SetStaticDefaults"/> to register this item into the "sfx button" category.<br/>
134+
/// It will automatically contribute to the active "sfx buttons" when in the inventory<br/>
135+
/// Do not call <see cref="RegisterClickerItem"/> with it as this method does this already by itself
136+
/// </summary>
137+
/// <param name="modItem">The <see cref="ModItem"/> that is to be registered</param>
138+
/// <param name="playSoundAction">The method that runs that will play the sound</param>
139+
internal static void RegisterSFXButton(ModItem modItem, Action<int> playSoundAction)
140+
{
141+
ClickerClass?.Call("RegisterSFXButton", versionString, modItem, playSoundAction);
142+
}
143+
121144
/// <summary>
122145
/// Call this in <see cref="Mod.PostSetupContent"/> or <see cref="ModType.SetStaticDefaults"/> to register this click effect
123146
/// </summary>
@@ -263,6 +286,46 @@ internal static bool IsClickerItem(Item item)
263286
return ClickerClass?.Call("IsClickerItem", versionString, item) as bool? ?? false;
264287
}
265288

289+
/// <summary>
290+
/// Call this to check if an item is an "sfx button"
291+
/// </summary>
292+
/// <param name="item">The item to be checked</param>
293+
/// <returns><see langword="true"/> if an "sfx button"</returns>
294+
internal static bool IsSFXButton(Item item)
295+
{
296+
return ClickerClass?.Call("IsSFXButton", versionString, item) as bool? ?? false;
297+
}
298+
299+
/// <summary>
300+
/// Call this to check if an item type is an "sfx button"
301+
/// </summary>
302+
/// <param name="type">The item type to be checked</param>
303+
/// <returns><see langword="true"/> if an "sfx button"</returns>
304+
internal static bool IsSFXButton(int type)
305+
{
306+
return ClickerClass?.Call("IsSFXButton", versionString, type) as bool? ?? false;
307+
}
308+
309+
/// <summary>
310+
/// Call this to get the sound playing method of an "sfx button"
311+
/// </summary>
312+
/// <param name="item">The item to be checked</param>
313+
/// <returns><see langword="null"/> if not "sfx button"</returns>
314+
internal static Action<int> GetSFXButton(Item item)
315+
{
316+
return ClickerClass?.Call("GetSFXButton", versionString, item) as Action<int> ?? null;
317+
}
318+
319+
/// <summary>
320+
/// Call this to get the sound playing method of an "sfx button"
321+
/// </summary>
322+
/// <param name="type">The item type to be checked</param>
323+
/// <returns><see langword="null"/> if not "sfx button"</returns>
324+
internal static Action<int> GetSFXButton(int type)
325+
{
326+
return ClickerClass?.Call("GetSFXButton", versionString, type) as Action<int> ?? null;
327+
}
328+
266329
/// <summary>
267330
/// Call this to check if an item type is a "clicker"
268331
/// </summary>
@@ -546,6 +609,40 @@ internal static bool HasClickEffect(Player player, string effect)
546609
return ClickerClass?.Call("HasClickEffect", versionString, player, effect) as bool? ?? false;
547610
}
548611

612+
/// <summary>
613+
/// Returns all currently active "sfx button" stacks.<br/>
614+
/// Use with <see cref="GetSFXButton"/> to get the sound
615+
/// </summary>
616+
/// <param name="player">The player</param>
617+
/// <returns>Dictionary mapping item type to stack</returns>
618+
internal static IReadOnlyDictionary<int, int> GetAllSFXButtonStacks(Player player)
619+
{
620+
return ClickerClass?.Call("GetAllSFXButtonStacks", versionString, player) as IReadOnlyDictionary<int, int> ?? null;
621+
}
622+
623+
/// <summary>
624+
/// Counts the stack of the given <paramref name="item"/> up by its stack<br/>
625+
/// </summary>
626+
/// <param name="player">The player</param>
627+
/// <param name="item">The item</param>
628+
/// <returns><see langword="true"/> it reached 5</returns>
629+
internal static bool AddSFXButtonStack(Player player, Item item)
630+
{
631+
return ClickerClass?.Call("AddSFXButtonStack", versionString, player, item) as bool? ?? false;
632+
}
633+
634+
/// <summary>
635+
/// Counts the stack of the given item type up by <paramref name="stack"/><br/>
636+
/// </summary>
637+
/// <param name="player">The player</param>
638+
/// <param name="type">The item type</param>
639+
/// <param name="stack">The stack to add</param>
640+
/// <returns><see langword="true"/> if it reached 5</returns>
641+
internal static bool AddSFXButtonStack(Player player, int type, int stack)
642+
{
643+
return ClickerClass?.Call("AddSFXButtonStack", versionString, player, type, stack) as bool? ?? false;
644+
}
645+
549646
/// <summary>
550647
/// Sets an auto-reuse effect to be applied to the player. Will apply the fastest one onto the player (if there are multiple active ones)
551648
/// </summary>
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Terraria;
5+
using Terraria.Audio;
6+
using Terraria.ID;
7+
using Terraria.Localization;
8+
using Terraria.ModLoader;
9+
10+
namespace ClickerClassExampleMod.Items.Misc
11+
{
12+
//A more advanced example using API methods to use other sfx buttons' sounds
13+
//Basic comments are removed here in favor of showcasing advanced behavior
14+
public class ExampleAdvancedSFXButtonSystem : ModSystem
15+
{
16+
public static Dictionary<int, Action<int>> SFXButtonToPlaySound { get; private set; }
17+
public static bool PlayedSoundThisTick { get; set; } = false;
18+
19+
public override void OnModLoad()
20+
{
21+
SFXButtonToPlaySound = new Dictionary<int, Action<int>>();
22+
}
23+
24+
public override void PostSetupContent()
25+
{
26+
//Get all modded sfx buttons and add them to a dictionary
27+
foreach (var modItem in ModContent.GetContent<ModItem>().Where(m => ClickerCompat.IsSFXButton(m.Type)))
28+
{
29+
SFXButtonToPlaySound[modItem.Type] = ClickerCompat.GetSFXButton(modItem.Type);
30+
}
31+
}
32+
33+
public override void PostUpdatePlayers()
34+
{
35+
PlayedSoundThisTick = false;
36+
}
37+
38+
public override void OnModUnload()
39+
{
40+
SFXButtonToPlaySound = null;
41+
PlayedSoundThisTick = false;
42+
}
43+
}
44+
45+
public class ExampleAdvancedSFXButton : ModItem
46+
{
47+
public override bool IsLoadingEnabled(Mod mod)
48+
{
49+
return ClickerCompat.ClickerClass != null;
50+
}
51+
52+
public override LocalizedText Tooltip => base.Tooltip.WithFormatArgs(Item.maxStack);
53+
54+
public static void PlaySound(int stack)
55+
{
56+
//Recursion checks (if another mod does the same thing: calling other sfx buttons's sound method).
57+
//This may cause a sound to not play at all but prevents the game from crashing
58+
if (ExampleAdvancedSFXButtonSystem.PlayedSoundThisTick)
59+
{
60+
return;
61+
}
62+
ExampleAdvancedSFXButtonSystem.PlayedSoundThisTick = true;
63+
64+
//Avoid recursion with self
65+
var list = ExampleAdvancedSFXButtonSystem.SFXButtonToPlaySound
66+
.Where(pair => pair.Key != ModContent.ItemType<ExampleAdvancedSFXButton>())
67+
.Select(pair => pair.Value)
68+
.ToList();
69+
70+
var playSound = Main.rand.Next(list);
71+
playSound.Invoke(stack);
72+
}
73+
74+
public override void SetStaticDefaults()
75+
{
76+
ClickerCompat.RegisterSFXButton(this, (Action<int>)PlaySound); //The cast is necessary here to avoid a warning
77+
}
78+
79+
public override void SetDefaults()
80+
{
81+
ClickerCompat.SetSFXButtonDefaults(Item);
82+
83+
Item.width = 20;
84+
Item.height = 20;
85+
Item.value = Item.buyPrice(0, 1, 0, 0);
86+
Item.rare = ItemRarityID.Orange;
87+
}
88+
89+
public override void AddRecipes()
90+
{
91+
CreateRecipe(1).AddIngredient(ItemID.Wood, 20).AddTile(TileID.WorkBenches).Register();
92+
}
93+
}
94+
}
501 Bytes
Loading

Items/Misc/ExampleSFXButton.cs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using Microsoft.Xna.Framework;
2+
using System;
3+
using Terraria;
4+
using Terraria.Audio;
5+
using Terraria.ID;
6+
using Terraria.Localization;
7+
using Terraria.ModLoader;
8+
9+
namespace ClickerClassExampleMod.Items.Misc
10+
{
11+
public class ExampleSFXButton : ModItem
12+
{
13+
//Optional, if you only want this item to exist only when Clicker Class is enabled
14+
public override bool IsLoadingEnabled(Mod mod)
15+
{
16+
return ClickerCompat.ClickerClass != null;
17+
}
18+
19+
//Optional, reuse a clicker class tooltip that all sfx buttons share. Remove if you want to specify your own
20+
public override LocalizedText Tooltip => Language.GetText("Mods.ClickerClass.Common.Tooltips.SFXButtonTip").WithFormatArgs(Item.maxStack);
21+
22+
/// <summary>
23+
/// The method used to play a sound
24+
/// </summary>
25+
/// <param name="stack">Usually used to control the volume by multiplying with 0.5f, ranges from 1 to 5</param>
26+
public static void PlaySound(int stack)
27+
{
28+
SoundStyle style = SoundID.Coins.WithVolumeScale(0.5f * stack) with
29+
{
30+
PitchVariance = 0.2f,
31+
};
32+
SoundEngine.PlaySound(style);
33+
}
34+
35+
public override void SetStaticDefaults()
36+
{
37+
//You NEED to call this in SetStaticDefaults to make it count as an sfx button and to register the sound playback
38+
//Doing so will automatically apply its functionality: While in the inventory (or opened Void Bag) it will apply its sound effect every click
39+
ClickerCompat.RegisterSFXButton(this, (Action<int>)PlaySound); //The cast is necessary here to avoid a warning
40+
}
41+
42+
public override void SetDefaults()
43+
{
44+
//This call is mandatory as it sets common stats like maxStack which is shared between all sfx buttons
45+
ClickerCompat.SetSFXButtonDefaults(Item);
46+
47+
Item.width = 20;
48+
Item.height = 20;
49+
Item.value = Item.buyPrice(0, 1, 0, 0);
50+
Item.rare = ItemRarityID.Green;
51+
}
52+
53+
//Optional: Showcase of some API methods
54+
public override void UpdateInventory(Player player)
55+
{
56+
//Let's make it so that this item also acts as the soundboard 25% of the time
57+
//DISCLAIMER: Calling this for your own item is not needed, it gets taken care of by RegisterSFXButton
58+
59+
if (!ModContent.TryFind<ModItem>("ClickerClass/SFXSoundboard", out var soundboard))
60+
{
61+
return;
62+
}
63+
64+
if (Main.rand.NextBool(4))
65+
{
66+
return;
67+
}
68+
69+
bool atMaxStacks = ClickerCompat.AddSFXButtonStack(player, soundboard.Type, Item.stack);
70+
71+
//We can also fetch currently active sfx button stacks (though this is not the correct timing, use a hook like ModPlayer.PostUpdate)
72+
var current = ClickerCompat.GetAllSFXButtonStacks(player);
73+
//Just for testing, we can verify that it works - it should spawn dust on the players head
74+
if (current.ContainsKey(soundboard.Type))
75+
{
76+
Dust.QuickDust(player.Top.ToTileCoordinates(), Color.White);
77+
}
78+
}
79+
80+
public override void AddRecipes()
81+
{
82+
CreateRecipe(1).AddIngredient(ItemID.Wood, 10).AddTile(TileID.WorkBenches).Register();
83+
}
84+
}
85+
}

Items/Misc/ExampleSFXButton.png

517 Bytes
Loading

Items/Weapons/Clickers/ExampleClicker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public override void SetDefaults()
2929
ClickerCompat.SetColor(Item, Color.White);
3030
ClickerCompat.SetDust(Item, 6);
3131

32-
//You can use Clicker Classes base effects (you can find them in the source code), or your own ones
32+
//You can use Clicker Classes' base effects (you can find them in the source code), or your own ones
3333
ClickerCompat.AddEffect(Item, "ClickerClass:DoubleClick");
3434

3535
Item.damage = 4;

Localization/en-US.hjson

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
Mods: {
32
ClickerClassExampleMod: {
43
Items: {
@@ -26,6 +25,17 @@ Mods: {
2625
DisplayName: Example Clicker With Effect
2726
Tooltip: "{$Mods.ClickerClass.Common.Tooltips.Clicker}"
2827
}
28+
29+
ExampleSFXButton.DisplayName: Example SFX Button
30+
31+
ExampleAdvancedSFXButton: {
32+
DisplayName: Example Advanced SFX Button
33+
Tooltip:
34+
'''
35+
Plays a random sound from existing SFX Buttons
36+
{$Mods.ClickerClass.Common.Tooltips.SFXButtonTip}
37+
'''
38+
}
2939
}
3040

3141
Projectiles.MiniClicker.DisplayName: Mini Clicker

0 commit comments

Comments
 (0)