I am getting an error about a lambda expression using func

So I am still following this tutorial on making a pokemon game and I ran into this error
Assets\Scripts\Data\ConditionsDB.cs(123,49): error CS1643: Not all code paths return a value in lambda expression of type ‘Func<Pokemon, bool>’
Its from this script on line 119

public class ConditionsDB
{
    public static void Init()
    {
        foreach(var kvp in Conditions)
        {
            var conditionId = kvp.Key;
            var condition = kvp.Value;

            condition.Id = conditionId;
        }
    }

    public static Dictionary<ConditionID, Condition> Conditions { get; set; } = new Dictionary<ConditionID, Condition>()
    {
        {
            ConditionID.psn, new Condition()
            {
                Name = "Poison",
                StartMessage = "has been poisoned",
                OnAfterTurn = (Pokemon pokemon) =>
                {
                    pokemon.UpdateHP(pokemon.MaxHp / 8);
                    pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} was hurt by poison");
                }
            }
        },
        {
            ConditionID.brn, new Condition()
            {
                Name = "Burn",
                StartMessage = "has been burned",
                OnAfterTurn = (Pokemon pokemon) =>
                {
                    pokemon.UpdateHP(pokemon.MaxHp / 16);
                    pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} suffers from burn");
                }
            }
        },
        {
            ConditionID.par, new Condition()
            {
                Name = "Paralyzed",
                StartMessage = "has been Parzlyzed",
               OnBeforeMove = (Pokemon pokemon) =>
               {
                  if (Random.Range(1,5) == 1)
                   {
                       pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} is paralyzed and can't move");
                       return false;
                   }

                  return true;
                 
               }
            }
        },
         {
            ConditionID.frz, new Condition()
            {
                Name = "Frozen",
                StartMessage = "has been frozen",
               OnBeforeMove = (Pokemon pokemon) =>
               {
                  if (Random.Range(1, 5) == 1)
                   {
                       pokemon.CureStatus();
                       pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} is no longer frozen");
                       return true;
                   }

                  return false;

               }
            }
        },
        {
            ConditionID.slp, new Condition()
            {
                Name = "Sleep",
                StartMessage = "has fallen asleep",

                OnStart = (Pokemon pokemon) =>
                {
                    pokemon.StatusTime = Random.Range(1, 4);
                    Debug.Log($"Will be asleep for {pokemon.StatusTime} moves");
                },

               OnBeforeMove = (Pokemon pokemon) =>
               {
                   if (pokemon.StatusTime <= 0)
                   {
                       pokemon.CureStatus();
                       pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} woke up!");
                       return true;
                   }

                  pokemon.StatusTime--;
                  pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} is sleeping");
                  return false;

               }
            }
        },

        // VOlatile Status Conditions
        {
            ConditionID.confusion, new Condition()
            {
                Name = "confusion",
                StartMessage = "has become confussed",

                OnStart = (Pokemon pokemon) =>
                {
                    pokemon.VolatileStatusTime = Random.Range(1, 5);
                    Debug.Log($"Will be confused for {pokemon.VolatileStatusTime} moves");
                },

               OnBeforeMove = (Pokemon pokemon) =>
               {
                   if (pokemon.VolatileStatusTime <= 0)
                   {
                       pokemon.CureVolatileStatus();
                       pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} is no longer confused!");
                       return true;
                   }

                  pokemon.VolatileStatusTime--;
                  if (Random.Range(1, 3) == 1)
                       return true;

               }
            }
        }
    };

}

public enum ConditionID
{
    none, psn, brn, slp, par, frz,
    confusion

}

Thing is I did my best to copy the code to the letter and in the video the guy doesn’t get that error. Now you might notice that the confusion section is partially a copy of the sleep one that came before it. Both have the line OnBeforeMove = (Pokemon pokemon) => only in the confusion portion it gets the error. I was trying to do research and came up with a partial answer that the problem is because they both use (Pokemon pokemon) =>. So the repeat is the cause. Although the video did the same thing and no error. Plus I know I used the Func function in one of my scripts which should have been part of something public, but the search function revealed noting on any of the scripts I tried.
Any advice?

Consider the lambda body on L120-L132.

               {
                   if (pokemon.VolatileStatusTime <= 0)
                   {
                       pokemon.CureVolatileStatus();
                       pokemon.StatusChanges.Enqueue($"{pokemon.Base.Name} is no longer confused!");
                       return true;
                   }

                  pokemon.VolatileStatusTime--;
                  if (Random.Range(1, 3) == 1)
                       return true;

               }

Say VolatileStatusTime > 0. The first if statement isn’t entered. Then say Random.Range returns 2. Then the second if statement isn’t entered. Now you’re at the end. What should happen in this case? What should be returned?

That’s where the problem is. You have some code paths that return a value but one that doesn’t. You need to deal with that by returning an appropriate value.

For fun, you could link the tutorial in question so people can see whether you actually did copy things exactly.

Also, this doesn’t seem particularly Unity-related. Even if in the context of a Unity game, I don’t see anything that’s particularly dependent on Unity. If anything, this seems to belong in the Scripting subforum.

2 Likes

Would like to note that this part:

public static void Init()
    {
        foreach(var kvp in Conditions)
        {
            var conditionId = kvp.Key;
            var condition = kvp.Value;
            condition.Id = conditionId;
        }
    }

Can just be a static constructor and avoid the need to call it manually:

static ConditionsDB()
{
    foreach(var kvp in Conditions)
    {
        var conditionId = kvp.Key;
        var condition = kvp.Value;

        condition.Id = conditionId;
    }
}

I do wonder if this ‘database’ is even necessary. A simple base class with derived classes is probably better (as in, proper OOP), allowing conditions to be just be new()'ed as necessary.

public abstract class Condition
{
    public abstract string Name { get; }
   
    public abstract void Apply(Pokemon pokemon);
}

public sealed class BurnCondition : Condition
{
    public override string Name => "Burn";
   
    public override void Apply(Pokemon pokemon)
    {
        // etc etc
    }
}

You could still give them an ID, probably just an enum value, for use with comparisons.