Momo-Space-Diner-Code-Repo / FoodQuest.cs
FoodQuest.cs
Raw
using ML.SDK;
using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class FoodQuest : MonoBehaviour
{
    public List<string> EasyFoods = new List<string> { "Steak", "Tomato Soup", "Hamburger" };
    public List<string> Ingredients = new List<string> { "Steak", "Chicken", "Tomato", "Potato", "Green Bellpepper", "Red BellPepper", "Yellow BellPepper", "Burger Patty", "Lettuce", "Shrimp", "Salmon", "Mushrooms" };

    [SerializeField] private TextMeshPro DishNameText;
    [SerializeField] public TextMeshPro IngredientsText;
    public Slider ProgressBar;
    public float TimerDuration = 60f;
    private float timer;
    public GameObject DestroyFX;
    public GameObject InstantiateSpot;

    public bool IsExpired => timer <= 0;

    EventToken SpawnFoodQuest;
    const string EVENT_ID_Spawn_FOODQUEST = "OnNetworkSpawnFoodQuest";

    EventToken DestroyFoodQuest;
    const string EVENT_ID_Destroy_FOODQUEST = "OnNetworkDestroyFoodQuest";

    EventToken SetRandomInitState;
    const string EVENT_ID_Random_INIT = "OnNetworkSetInitState";

    private string truename;
    private static FoodQuest lastCreatedFoodQuest;
    private bool initialized = false;

    private int syncSeed;
    private string uniqueID = Guid.NewGuid().ToString();

    public OverCookedGameManager GameManagerReference;

    public int PointsForCompletion = 10; // Points awarded for completing the quest

    public plateScript plateScriptReference;

   private List<string> selectedIngredients = new List<string>();
    //TODO: Make / fix turn in system. This is busted.


    //With the soup spoon system there seems to be a problem with accepting the food on the soup plates.
    /*
     * Whenever a quest gets accepted, 
     *  this is the format :
     * 
            [23:08:32], Log: Plate script found
        -


        [23:08:32], Log: FoodQuest ingredients: Tomato, Zucchini, Mushroom
        -


        [23:08:32], Log: FOODQUEST : Found food with truename: Tomato
        -


        [23:08:32], Log: FOODQUEST : Found food with truename: Mushroom
        -


        [23:08:32], Log: FOODQUEST : Found food with truename: Zucchini
        -


        [23:08:32], Log: All quest ingredients are present on the plate! Quest completed.
        -


        [23:08:32], Log: New Score : 10


        Whenever a soup spoon object gets turned in :

        [23:09:25], Log: Plate script found
        -


        [23:09:25], Log: FoodQuest ingredients: Tomato, Mushroom
        -


        [23:09:25], Log: FOODQUEST : Found food with truename: Tomato, Mushroom
        -


        [23:09:25], Warning: Not all quest ingredients are present on the plate.
        -

        It seems that because there is only ONE food piece, it is parsing that as ONE item rather than evaluating it holisticly.
        Interestingly enough-- the other clients seem to turn in this quest where the master client doesn't. Weird. Because of this system
        I may need to redesign the soup spoon system to either produce equal amounts of food items depending on how many objects were
        added to the soup, or re-orient this function to also cover for this case.

     */
    private void OnTriggerEnter(Collider other)
    {
        //Debug.Log("Trigger entered from FoodCut object!");

        // Explicitly get the plateScript from the GameObject
        plateScript plateScriptReference = (plateScript)other.gameObject.GetComponent(typeof(plateScript));
        if (plateScriptReference == null)
        {
            Debug.LogWarning($"No plateScript found on the triggering object: {other.gameObject.name}");
            return;
        }

        // Ensure foodOnPlate list is initialized and not empty
        if (plateScriptReference.foodOnPlate == null || plateScriptReference.foodOnPlate.Count == 0)
        {
            Debug.LogError($"The foodOnPlate list is null or empty on the plateScript of {other.gameObject.name}");
            return;
        }

        Debug.Log("Plate script found");
        List<GameObject> foodOnPlate = plateScriptReference.foodOnPlate;

        // Get the FoodQuest component from the collided object
       // FoodQuest foodQuest = other.gameObject.GetComponent<FoodQuest>();


        if (selectedIngredients == null || selectedIngredients.Count == 0)
        {
            Debug.LogError($"The selectedIngredients list in FoodQuest is null or empty.");
            return;
        }

        Debug.Log($"FoodQuest ingredients: {string.Join(", ", selectedIngredients)}");

        // Check the plate ingredients against the FoodQuest ingredients
        List<string> plateIngredients = new List<string>();
        foreach (GameObject foodObject in foodOnPlate)
        {
            if (foodObject == null)
            {
                Debug.LogWarning("A null food item was found on the plate.");
                continue;
            }

            // Get the FoodCut component and truename
            FoodCut foodCutComponent = (FoodCut)foodObject.GetComponent(typeof(FoodCut));
            if (foodCutComponent == null)
            {
                Debug.LogWarning($"The GameObject {foodObject.name} does not have a FoodCut component.");
                continue;
            }

            string truename = foodCutComponent.TrueFoodName;
            Debug.Log($"FOODQUEST : Found food with truename: {truename}");


            /*New system from 12 / 2 / 2024
             * 
             */
            if(foodCutComponent != null)
            {
                if(foodCutComponent.isMeat == true)
                {
                    Debug.Log($" Meat item found! checking to see if meat has been cooked");
                    if(foodCutComponent.hasBeenCooked && !foodCutComponent.BurntVersion.activeInHierarchy)
                    {
                        Debug.Log(" Meat item has been cooked properly! Regiestering");
                        plateIngredients.Add(truename);
                    }
                    else if(foodCutComponent.BurntVersion.activeInHierarchy)
                    {
                        Debug.Log(" Meat item has been burnt!");
                        continue;
                    }
                    else if (!foodCutComponent.hasBeenCooked)
                    {
                        Debug.LogWarning(" Meat item is raw! Skipping");
                        continue;
                    }
                }
                else if(foodCutComponent.isMeat == false)
                {
                    plateIngredients.Add(truename);
                }
            }

           // plateIngredients.Add(truename);
        }

        // Compare the plate ingredients with the selectedIngredients
        bool allIngredientsMatch = selectedIngredients.All(ingredient => plateIngredients.Contains(ingredient));
        if (allIngredientsMatch)
        {
            Debug.Log("All quest ingredients are present on the plate! Quest completed.");
            AwardPoints();

            if(plateScriptReference.grabComponent.CurrentUser != null)
            {
                plateScriptReference.grabComponent.ForceRelease();

               // Object.Destroy(other);
            }

         
        }
        else
        {
            Debug.LogWarning("Not all quest ingredients are present on the plate.");
        }
    }




    private void AwardPoints()
    {
        if (GameManagerReference != null)
        {
            GameManagerReference.AddScore(PointsForCompletion);
            Debug.Log($"Awarded {PointsForCompletion} points for completing quest: {name}");
        }
    }

    private void CompleteQuest()
    {
        // Optionally: Add logic to visually update the quest or remove it from the UI
        Debug.Log($"Quest {name} completed!");
        Destroy(gameObject); // Remove the quest from the game world
    }

    private void Start()
    {
        SpawnFoodQuest = this.AddEventHandler(EVENT_ID_Spawn_FOODQUEST, OnNetworkSpawnFoodQuest);
        DestroyFoodQuest = this.AddEventHandler(EVENT_ID_Destroy_FOODQUEST, OnNetworkDestroyFoodQuest);
        SetRandomInitState = this.AddEventHandler(EVENT_ID_Random_INIT, OnNetworkSetInitState);
        Debug.Log($"Unique ID : {uniqueID}");


        if (MassiveLoopClient.IsMasterClient)
        {

            syncSeed = (int)DateTime.Now.Ticks; // Generate seed
            Debug.Log($" Master client attempting to set initstate : generated this seet {syncSeed} ");
            this.InvokeNetwork(EVENT_ID_Random_INIT, EventTarget.All, null, syncSeed, uniqueID);



        }
        else
        {
                this.DishNameText.text = GetRandomDish();
                this.IngredientsText.text = GetRandomIngredients(this.DishNameText.text);
                this.initialized = true;
            
        }


        // if (MassiveLoopClient.IsMasterClient)
        //  {
        //syncSeed = (int)DateTime.Now.Ticks; // Generate seed
        //Debug.Log($"[MasterClient] Generated seed: {syncSeed}");
        //    this.InvokeNetwork(EVENT_ID_Spawn_FOODQUEST, EventTarget.All, null, this.gameObject.GetInstanceID(), gameObject.name);
        //   }

        timer = TimerDuration;
        lastCreatedFoodQuest = this;
      //  Debug.Log($"[Start] Initialized FoodQuest object: {gameObject.name}, set as last created FoodQuest.");
    }

    private void Update()
    {
        if (timer > 0)
        {
            timer -= Time.deltaTime;
            ProgressBar.value = Mathf.Clamp01(timer / TimerDuration);

            float timePercentage = timer / TimerDuration;
            ProgressBar.fillRect.GetComponentInChildren<Image>().color = timePercentage > 0.5f ? Color.green :
                                                                        timePercentage > 0.3f ? Color.yellow : Color.red;
        }
        else
        {
            this.InvokeNetwork(EVENT_ID_Destroy_FOODQUEST, EventTarget.All, null, gameObject.GetInstanceID());
        }

      //  if(GameManagerReference.isGameRunning  == false)
      //  {
     //       this.InvokeNetwork(EVENT_ID_Destroy_FOODQUEST, EventTarget.All, null, gameObject.GetInstanceID());
      //  }
    }


    private void OnNetworkSetInitState(object[] args)
    {
        //TODO : Make all clients essentially use the same Random.initstate seed. If they all are using the same seed, they will see the same randomly generated
        // ingredients / dishes they need to cook.
        // syncSeed = (int)DateTime.Now.Ticks; // Generate seed

        if (this == null || gameObject == null || gameObject.name == null)
        {
            return;
        }

        int syncSeed_PassedIn = (int)args[0];
        string uniquePassedID = (string)args[1];

        if (!MassiveLoopClient.IsMasterClient)
        {
            this.uniqueID = uniquePassedID;
        }

        Debug.Log($"[OnNetworkSetInitState] Received seed: {(int)syncSeed_PassedIn}. Recieved Unique ID : {uniquePassedID}. Comparing to this objects unique ID : {this.uniqueID}");
        UnityEngine.Random.InitState((int)syncSeed_PassedIn);



        truename = GenerateRandomName();
        this.gameObject.name = truename;
        if (uniquePassedID == this.uniqueID && initialized == false)
        {
            this.DishNameText.text = GetRandomDish();
            this.IngredientsText.text = GetRandomIngredients(this.DishNameText.text);
            this.initialized = true;
        }

       // Debug.Log($"[OnNetworkSetInitState] Generated name : {truename}. ");

       // this.InvokeNetwork(EVENT_ID_Spawn_FOODQUEST, EventTarget.Others, null, this.gameObject.GetInstanceID(), GetRandomDish(), GetRandomIngredients(), gameObject.name, uniqueID);

    }

    //Gets the individual food quest to find the game manager reference.
    //We can call functions from this, which means we can properly clean the array when a food quest gets deleted!
    public void SetText(string text1, GameObject text2)
    {
        Debug.Log($" Set Text invoked from game manager, testing to see if I can pass in a game object are here {text2.name} ");
        GameManagerReference = (OverCookedGameManager)text2.GetComponent(typeof(OverCookedGameManager));

    }
    private void OnNetworkSpawnFoodQuest(object[] args)
    {
        if (this == null || gameObject == null || gameObject.name == null || args[0] == null)
        {
            return;
        }

      

        int instanceId = (int)args[0];
        string DishNameText_PassedIn = (string)args[1];
        string Ingredients_PassedIn = (string)args[2];
        string FoodNameText_PassedIn = (string)args[3];
        string uniquePassedID = (string)args[4];
        // syncSeed = (int)args[1]; // Set the syncSeed

       // if (uniqueID != instanceId) return; // Exit if the event is not for this instance


        //   Debug.Log($"[OnNetworkSpawnFoodQuest] Received seed: {syncSeed}. Initializing with synchronized seed.");
        Debug.Log($"[OnNetworkSpawnFoodQuest] Received gameobject name : {FoodNameText_PassedIn}. Comparing to this object : {this.gameObject.name}");
        //    Debug.Log($"[OnNetworkSpawnFoodQuest] Received gameobject instance ID : {instanceId}. Comparing to this object : {gameObject.GetInstanceID()}");
        Debug.Log($"[OnNetworkSpawnFoodQuest] Received Dishname : {DishNameText_PassedIn}. Ingredients Passed in : {Ingredients_PassedIn} . Food name : {FoodNameText_PassedIn}");

        Debug.Log($"Comparing Passed in unique ID {uniquePassedID} to this game object's ID {this.uniqueID}");

        if (uniquePassedID == this.uniqueID)
        {

            this.DishNameText.text = DishNameText_PassedIn;
            this.IngredientsText.text = Ingredients_PassedIn;
            ProgressBar.value = 1;
        }
    }

    private void OnNetworkDestroyFoodQuest(object[] args)
    {
        if (this == null || gameObject == null || gameObject.name == null || args[0] == null)
        {
            return;
        }


        int instanceId = (int)args[0];
        if (gameObject.GetInstanceID() == instanceId)
        {
            if(MassiveLoopClient.IsMasterClient)
            {
                GameManagerReference.RetrieveInfo();
                GameManagerReference.RemoveGameObjectFromList(this.gameObject);
            }


            GameObject desFX = UnityEngine.Object.Instantiate(DestroyFX, InstantiateSpot.transform.position, Quaternion.identity);
            UnityEngine.Object.Destroy(desFX, 5f);
            DishNameText.text = "";
            IngredientsText.text = "";
            UnityEngine.Object.Destroy(gameObject);
        }
    }

    private string GetRandomDish()
    {
        string dish = EasyFoods[UnityEngine.Random.Range(0, EasyFoods.Count)];
        Debug.Log($"[GetRandomDish] Selected dish: {dish}");
        return dish;
    }

    private string GetRandomIngredients(string dish)
    {
        // Define ingredient weights based on the selected dish
        Dictionary<string, Dictionary<string, float>> dishIngredientWeights = new Dictionary<string, Dictionary<string, float>>
    {
        {
            "Steak", new Dictionary<string, float>
            {
                { "Steak", 15 },
                { "Potato", 3 },
                { "Mushroom", 2 },
                { "Green Beans", 1 }
            }
        },
        {
            "Tomato Soup", new Dictionary<string, float>
            {
                { "Tomato", 15 },
                { "Carrot", 2 },
                { "Onion", 2 },
                {"Mushroom", 2 },
                {"Zucchini", 2 },
                { "Garlic", 1 }
            }
        },
        {
            "Hamburger", new Dictionary<string, float>
            {
                { "Burger Patty", 15 },
                { "Lettuce", 3 },
                { "Tomato", 3 },
                { "Cheese", 2 }
            }
        },
        {
            "Salmon", new Dictionary<string, float>
            {
                { "Salmon", 15 },
                { "Lemon", 3 },
                { "Zucchini", 2 }
            }
        }
    };

        // Get ingredient weights for the selected dish
        if (!dishIngredientWeights.ContainsKey(dish))
        {
            Debug.LogWarning($"No ingredients defined for dish: {dish}. Using fallback ingredients.");
            return "No Ingredients";
        }

        Dictionary<string, float> ingredientWeights = new Dictionary<string, float>(dishIngredientWeights[dish]);
        

        int ingredientCount = UnityEngine.Random.Range(2, 4);

        for (int i = 0; i < ingredientCount; i++)
        {
            if (ingredientWeights.Values.All(w => w <= 0))
            {
                Debug.LogWarning("All ingredient weights are zero or less. Stopping selection.");
                break;
            }

            // Calculate total weight for remaining ingredients
            float totalWeight = ingredientWeights.Values.Sum();
            if (totalWeight <= 0)
            {
                Debug.LogWarning("Total weight is zero. No ingredients can be selected.");
                break;
            }

            // Pick a weighted random ingredient
            float randomValue = UnityEngine.Random.Range(0, totalWeight);
            float cumulativeWeight = 0;
            string selectedIngredient = null;

            foreach (var ingredient in ingredientWeights)
            {
                if (ingredient.Value <= 0) continue; // Skip ingredients with zero weight

                cumulativeWeight += ingredient.Value;

                if (randomValue <= cumulativeWeight)
                {
                    selectedIngredient = ingredient.Key;
                    break;
                }
            }

            if (!string.IsNullOrEmpty(selectedIngredient))
            {
                Debug.Log($"Selected Ingredient: {selectedIngredient}");
                selectedIngredients.Add(selectedIngredient);
                ingredientWeights[selectedIngredient] = 0; // Set weight to 0 instead of removing
            }
            else
            {
                Debug.LogWarning("Failed to select an ingredient. Skipping.");
            }
        }

        return string.Join(", ", selectedIngredients);
    }


    // Helper method to get a weighted random ingredient
    private string GetWeightedRandomIngredient(Dictionary<string, float> ingredientWeights)
    {
        float totalWeight = ingredientWeights.Values.Sum();
        if (totalWeight <= 0)
        {
            Debug.LogWarning("Total weight is zero or less. No ingredients can be selected.");
            return null;
        }

        float randomValue = UnityEngine.Random.Range(0, totalWeight);
        float cumulativeWeight = 0;

        foreach (var ingredient in ingredientWeights)
        {
            Debug.LogWarning($"Ingredient : {ingredient}");
            if (ingredient.Value <= 0) continue; // Skip ingredients with zero weight
            cumulativeWeight += ingredient.Value;

            if (randomValue <= cumulativeWeight)
            {
                return ingredient.Key;
            }
        }

        Debug.LogWarning("Failed to select an ingredient. Returning null.");
        return null;
    }


    private string GenerateRandomName()
    {
        string[] possibleNames = { "Apple", "Banana", "Carrot", "Steak", "Burger", "Fish" };
        int randomIndex = UnityEngine.Random.Range(0, possibleNames.Length);
        int randomNumber = UnityEngine.Random.Range(0, 100000);
        return possibleNames[randomIndex] + "_" + randomNumber.ToString("D5");
    }
}