#Identify the color of the SCP-330 candy used by a player.

1 messages · Page 1 of 1 (latest)

clever vault
#

When a player eats candy, it can be detected through PlayerUsedItemEventArgs, but it seems that the specific color of the candy eaten cannot be directly identified. Is there any way to determine which color of candy the player consumed?

mortal token
clever vault
dim compass
clever vault
silent ravine
#

@clever vault

  private void PlayerEvents_UsingItem(PlayerUsingItemEventArgs ev)
  {
      if(ev.UsableItem.Base is Scp330Bag bag)
      {
          bag.Candies.TryGet(bag.SelectedCandyId, out CandyKindID candy);
          if(candy == CandyKindID.Rainbow)
          {
              // Do stuff
          }
      }
  }

Something like this might work?

#

(Havent tested it)

dim compass
#

it's just about casting

clever vault
#

To anyone reading this later:
It seems that SCP-330 candy is only considered actually consumed after approximately 2 seconds of the consumption animation (this is an assumption). As a result, the timing of using and used events does not seem to align well with the actual moment of consumption.

This situation might require using Harmony, or perhaps another solution you can think of that works better.

The following approach should also work, though it is somewhat rudimentary. It can serve as a reference for a more refined solution:

internal static void UsingItem(PlayerUsingItemEventArgs e)
{
if (e.UsableItem.Type == ItemType.SCP330)
Timing.RunCoroutine(UseCandy(e.Player, e.UsableItem));
}

internal static IEnumerator<float> UseCandy(Player player, UsableItem usableItem)
{
if (player is null || !(usableItem.Base is Scp330Bag scp330Bag))
yield break;

CandyKindID candyKindID = CandyKindID.None;

List<CandyKindID> originalCandies = new List<CandyKindID>(scp330Bag.Candies);

if (originalCandies is null || originalCandies.Count == 0)
    yield break;

if (originalCandies.Count is 1)
{
    candyKindID = originalCandies[0];
    yield return Timing.WaitForSeconds(2);
    goto UseCandy;
}

yield return Timing.WaitForSeconds(2);
if (player is null || !player.IsAlive || !(player.Items.FirstOrDefault(item => item.Type == ItemType.SCP330)?.Base is Scp330Bag scp330BagB)) yield break;

List<CandyKindID> currentCandies = new List<CandyKindID>(scp330BagB.Candies);

if (originalCandies.Count != currentCandies.Count + 1)
    yield break;

foreach(var candy in currentCandies)
{
    originalCandies.Remove(candy);
}

if (originalCandies.Count != 1)
    yield break;

candyKindID = originalCandies.FirstOrDefault();

UseCandy:;

/*do something (candyKindID)*/

}

lapis fern
#

patching it

#
[HarmonyPatch(typeof(Scp330Bag), nameof(Scp330Bag.ServerOnUsingCompleted))]
    public static class EatingCandyEvent
    {
        public class AteCandyEventArgs(Player player, CandyKindID candy) : EventArgs
        {
            public Player Player { get; } = player;

            public CandyKindID Candy { get; } = candy;
        }

        public static event LabEventHandler<AteCandyEventArgs>? AteCandy;

        private static void Postfix(Scp330Bag __instance)
        {
            if (!__instance.IsCandySelected)
                return;

            if (!Scp330Candies.CandiesById.TryGetValue(__instance.Candies[__instance.SelectedCandyId], out ICandy candy))
                return;

            AteCandy?.Invoke(new AteCandyEventArgs(Player.Get(__instance.Owner), candy.Kind);
        }
    }

and then:

EatingCandyEvent.AteCandy += ev =>
            {
                if (ev.Candy == CandyKindID.Yellow)
                    ev.Player.Kill();
            };

FOR REFERENCE: This is not functional and needs to be a prefix not postfix and you need to handle it differently
Patch also according to @fathom comet is not required (read down)

fathom comet
lapis fern
fathom comet
#

The ICandy is an unnecessary lookup for some purposes

#

But if you want the ServerApplyEffects logic and the SpawnChanceWeight then you can do it

fathom comet
#

Thank's for the shoutout homeslice @lapis fern