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");
}
}