# GameData version4

## GameData wtih Custom Unity Events:

This version of GameData has 2 custom UnityEvents included:

The code snippet below shows that the events are declared as type UnityEvent, they will be used in PlayerStats classes so that changes in playerData: score or health, or changes in the will be updated

```csharp
    public UnityEvent onPlayerDataUpdate;
```

The code below shows that when TakeDamage is executed, there is a call to the InvokePlayerDataUpdate( ) method.  The InvokePlayerDataUpdate( ) method checks to see if there are any subscribed 'listeners', such that the event is not null, then it Invokes the event which executes all methods that have been added as listeners.

```csharp
//updated TakeDamage: 
    public void TakeDamage(int value)
    {
        health -= value;
        if (health < 0) health = 0;  //makes sure health !< 0
        Debug.Log("Health is updated " + health);
        InvokePlayerDataUpdate();
    }

    //Execute custom event if there are listeners
    public void InvokePlayerDataUpdate()
    {
        if (onPlayerDataUpdate != null)
        {
            onPlayerDataUpdate.Invoke();
        }
    }
```

```csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

//11/9/2020 Version 4 - custom

//Singleton - one and only 1 ever in existance
//global variable to allow easy access
public class GameData : MonoBehaviour
{

    public UnityEvent onPlayerDataUpdate;
    public UnityEvent onStateUpdate;
    
    /// static means it belongs to the Class, and not to an object instance of the class
    public static GameData instanceRef;  ///Global static variable 

    private Dictionary<string, string> choiceData = new Dictionary<string, string>();

    private int score;
    private int health;

    /// <summary>
    /// Properties - provide read/write access to variables
    /// Properties - Support Encapsulation - protect inner workings of our class
    /// </summary>
    public int Score //some versions use TotalScore
    {
        get { return score; }   //read only access
    }

    public int Health
    {
        get { return health; }   //read only access
    }

    //Initialize Singleton
    private void Awake()
    {
        health = 100; //initialize
        score = 50;
        InitializeChoiceStatevalues();  //initialize dictionary with state values

        if (instanceRef == null)
        {
            instanceRef = this; //point to itself
            DontDestroyOnLoad(this.gameObject);  //this will never be destroyed
        }
        else
        {
            Destroy(this.gameObject);
            Debug.Log("Duplicate GameData is Destroyed");
        }
    }

    //Initialize with default state values
    void InitializeChoiceStatevalues()
    {
        SaveChoice("LucyState", "deficiency");
        SaveChoice("ZombieState", "hungry");
        SaveChoice("RobotState", "agent");
        SaveChoice("CatState", "missing");
        SaveChoice("MonsterState", "angry");

    }

    /// <summary>
    /// Add the specified value.
    /// Overloaded method
    /// takes the PickUp item's value as input parameter
    /// </summary>
    /// <param name="value">Value.</param>
    public void Add(int value)
    {
        score += value;
        Debug.Log("Score is updated " + score);
        InvokePlayerDataUpdate();
    }

    public void Buy(int value)
    {
        score -= value;
        Debug.Log("Buy: score reduced " + score);
        InvokePlayerDataUpdate();
    }

    public void BoostHealth(int value)
    {
        health += value;
        health = Mathf.Min(health, 100);
        Debug.Log("boosting health, new health " + health);
        InvokePlayerDataUpdate();
    }

    //updated TakeDamage: 
    public void TakeDamage(int value)
    {
        health -= value;
        if (health < 0) health = 0;  //makes sure health !< 0
        Debug.Log("Health is updated " + health);
        InvokePlayerDataUpdate();
    }

    //Execute custom event if there are listeners
    public void InvokePlayerDataUpdate()
    {
        if (onPlayerDataUpdate != null)
        {
            onPlayerDataUpdate.Invoke();
        }
    }

    //execute custom event to indicate gameState-Dictionary values have changed
    public void InvokeStateUpdate()
    {
        if( onStateUpdate != null)
        {
           onStateUpdate.Invoke();
        }
    }

    //save any <string, string > key-value pair in choiceData dictionary
    public void SaveChoice(string choiceKey, string choiceValue)
    {
        if (choiceData.ContainsKey(choiceKey))
        {
            choiceData[choiceKey] = choiceValue; //change stored value
            Debug.Log("Choice Changed" + choiceKey + " : " + choiceValue);
        }
        else
        {
            choiceData.Add(choiceKey, choiceValue); //adds key,value pair
            Debug.Log("Choice Data Created" + choiceKey + " : " + choiceValue);
        }
        InvokeStateUpdate(); //notify all listeners that some choiceData value has changed
    }

    //given key, read any < string, string > key-value pair 
    public string GetChoice(string choiceKey)
    {
        string choiceValue = "None";
        choiceData.TryGetValue(choiceKey, out choiceValue);
        Debug.Log("Choice Data Accessed" + choiceKey + " : " + choiceValue);
        InvokeStateUpdate();
        return choiceValue;
    }

    //removes item from dictionary if key exists
    public void RemoveChoice( string choiceKey)
    {
        if(choiceData.ContainsKey(choiceKey))
        {
            choiceData.Remove(choiceKey);
            InvokeStateUpdate();
        }
    }

    //to restart entire game
    public void ResetGameData()
    {
        health = 100; //initialize
        score = 0;
    }

} //end class
```
