From adac70b9a576a52cb9559b4c5352d5860ece367e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Sat, 6 Apr 2024 00:57:29 +0200 Subject: [PATCH] =?UTF-8?q?Happiness=20is=20not=20a=20destination,=20it's?= =?UTF-8?q?=20a=20way=20of=20life=20=E2=98=80=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3d Prototyp/Assets/Scripts/Developer.cs | 156 +++++++++++++++--- 3d Prototyp/Assets/Scripts/DeveloperNeeds.cs | 3 +- 3d Prototyp/Assets/Scripts/GameManager.cs | 4 +- .../Assets/Scripts/Utility/Difficulty.cs | 2 + 4 files changed, 141 insertions(+), 24 deletions(-) diff --git a/3d Prototyp/Assets/Scripts/Developer.cs b/3d Prototyp/Assets/Scripts/Developer.cs index 33a1006d..580ca1a0 100644 --- a/3d Prototyp/Assets/Scripts/Developer.cs +++ b/3d Prototyp/Assets/Scripts/Developer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; using Utility; +using Random = UnityEngine.Random; [Serializable] public struct DeveloperStats @@ -13,18 +14,26 @@ public struct DeveloperStats public double CaffeineDrainFactor; public double HungerDrainFactor; - [FormerlySerializedAs("UrgeToUrinateFillFactor")] public double UrinationDrainFactor; + public double UrinationDrainFactor; + public double HappinessDrainFactor; - public DeveloperStats(double baseEfficiency, int fingers, double caffeineDrainFactor, double hungerDrainFactor, double urinationDrainFactor) + // TODO: Not yet used + public double CoffeePreference; + public double MatePreference; + + public DeveloperStats(double baseEfficiency, int fingers, double caffeineDrainFactor, double hungerDrainFactor, double urinationDrainFactor, double happinessDrainFactor, double coffeePreference, double matePreference) { BaseEfficiency = baseEfficiency; Fingers = fingers; CaffeineDrainFactor = caffeineDrainFactor; HungerDrainFactor = hungerDrainFactor; UrinationDrainFactor = urinationDrainFactor; + HappinessDrainFactor = happinessDrainFactor; + CoffeePreference = coffeePreference; + MatePreference = matePreference; } - public static readonly DeveloperStats Default = new DeveloperStats(1.0, 10, 1, 1, 1); + public static readonly DeveloperStats Default = new DeveloperStats(1.0, 10, 1, 1, 1, 1, 0.5, 0.5); } public class Developer : MonoBehaviour @@ -49,6 +58,9 @@ public class Developer : MonoBehaviour [SerializeField] private double _urgeToUrinateLevel = 1.0; + [SerializeField] + private double _happiness = 0.75; + [SerializeField, ShowOnly] private bool _isSleeping = false; @@ -78,10 +90,27 @@ public class Developer : MonoBehaviour public string Name => _name; + [Serializable, Flags] + public enum WantedConsumable + { + None, + Food = 0x01, + Drink = 0x02, + Coffee = Drink | 0x04, + Mate = Drink | 0x08, + Pizza = Food | 0x10 + } + [SerializeField] private GameObject _caffeineNeed; + + [SerializeField] private WantedConsumable _wantedDrink; + [SerializeField] private GameObject _hungerNeed; + + [SerializeField] private WantedConsumable _wantedFood; + [SerializeField] private GameObject _toiletNeed; @@ -92,63 +121,121 @@ public class Developer : MonoBehaviour _fingersLeft = _baseStats.Fingers; } - [ContextMenu("Give Drink")] - private void TestDrink() + [ContextMenu("Give Coffee")] + private void TestCoffee() { - GiveDrink(0.25); + GiveDrink(0.3, WantedConsumable.Coffee); + } + + [ContextMenu("Give Mate")] + private void TestMate() + { + GiveDrink(0.3, WantedConsumable.Mate); } [ContextMenu("Give Food")] private void TestFood() { - GiveFood(0.25); + GiveFood(0.3, WantedConsumable.Pizza); } [ContextMenu("Drain Bladder")] private void TestPee() { - Pee(0.25); + Pee(0.3, true); } - public void GiveDrink(double caffeineAmount) + public void GiveDrink(double caffeineAmount, WantedConsumable drinkType) { - _caffeineLevel += caffeineAmount; + if (!drinkType.HasFlag(WantedConsumable.Drink)) + throw new ArgumentException(nameof(drinkType), + $"{nameof(drinkType)} must be a value with the \"{WantedConsumable.Drink}\" flag"); + + _caffeineLevel = Math.Min(_caffeineLevel + caffeineAmount, 2.0); if (_caffeineNeed != null && _caffeineLevel > GameManager.Instance.NeedNotificationThreshold) { NeedFullfilled(_caffeineNeed); + _caffeineNeed = null; } + + if (_wantedDrink != WantedConsumable.None) + { + // TODO: Wie wäre es damit, das nicht fest zu coden? + if (drinkType == _wantedDrink) + _happiness += 0.2; + else + _happiness -= 0.2; + } + else + { + _happiness += 0.2; + } + + _wantedDrink = WantedConsumable.None; } - public void GiveFood(double foodAmount) + public void GiveFood(double foodAmount, WantedConsumable foodType) { - _hungerLevel += foodAmount; + if (!foodType.HasFlag(WantedConsumable.Food)) + throw new ArgumentException(nameof(foodType), + $"{nameof(foodType)} must be a value with the \"{WantedConsumable.Food}\" flag"); + + _hungerLevel = Math.Min(_hungerLevel + foodAmount, 1.0); if (_hungerNeed != null && _hungerLevel > GameManager.Instance.NeedNotificationThreshold) { NeedFullfilled(_hungerNeed); + _hungerNeed = null; } + + if (_wantedFood != WantedConsumable.None) + { + if (foodType == _wantedFood) + _happiness += 0.2; + else + _happiness -= 0.2; + } + else + { + _happiness += 0.2; + } + + _wantedFood = WantedConsumable.None; } - public void Pee(double peeAmount) + /// + /// Der Entwickler Pinkelt die angegebene Menge aus. + /// + /// Die Menge die ausgepinkelt wird. + /// Wenn true, dann pinkelt der Entwickler auf einer Toilette. Wenn false, dann pinkelt er auf den Boden (was schlecht ist) + public void Pee(double peeAmount, bool onToilet) { - _urgeToUrinateLevel += peeAmount; + _urgeToUrinateLevel = Math.Min(_urgeToUrinateLevel += peeAmount, 1.0); if (_toiletNeed != null && _urgeToUrinateLevel > GameManager.Instance.NeedNotificationThreshold) { NeedFullfilled(_toiletNeed); + _toiletNeed = null; } + + if (onToilet) + _happiness += 0.2; + else + _happiness -= 0.2; } - public void UpdateStats(double caffeineDrain, double hungerDrain, double urinationDrain) + public void UpdateStats(double caffeineDrain, double hungerDrain, double urinationDrain, double happinessDrain) { _caffeineLevel -= caffeineDrain * _baseStats.CaffeineDrainFactor; _hungerLevel -= hungerDrain * _baseStats.HungerDrainFactor; _urgeToUrinateLevel -= urinationDrain * _baseStats.UrinationDrainFactor; + _happiness -= happinessDrain * _baseStats.UrinationDrainFactor; - _caffeineLevel = Math.Clamp(_caffeineLevel, 0.0, 2.0); - _hungerLevel = Math.Clamp(_hungerLevel, 0.0, 1.0); - _urgeToUrinateLevel = Math.Clamp(_urgeToUrinateLevel, 0.0, 1.0); + _caffeineLevel = Math.Max(_caffeineLevel, 0.0); + _hungerLevel = Math.Max(_hungerLevel, 0.0); + _urgeToUrinateLevel = Math.Max(_urgeToUrinateLevel, 0.0); + _happiness = Math.Max(_happiness, 0.0); _isHyperactive = _caffeineLevel > 1.0; _isOvercaffeinated = _caffeineLevel > 1.5; @@ -156,12 +243,24 @@ public class Developer : MonoBehaviour if (_caffeineLevel < GameManager.Instance.NeedNotificationThreshold && _caffeineNeed == null) { - _caffeineNeed = _developerNeeds.SpawnCaffeineNeed(); + // TODO: Wir können hier anhand von Präferenz gewichten. + + if (Random.Range(0.0f, 1.0f) > 0.5f) + { + _caffeineNeed = _developerNeeds.SpawnMateNeed(); + _wantedDrink = WantedConsumable.Mate; + } + else + { + _caffeineNeed = _developerNeeds.SpawnCoffeeNeed(); + _wantedDrink = WantedConsumable.Coffee; + } } if (_hungerLevel < GameManager.Instance.NeedNotificationThreshold && _hungerNeed == null) { _hungerNeed = _developerNeeds.SpawnHungerNeed(); + _wantedFood = WantedConsumable.Pizza; } if (_urgeToUrinateLevel < GameManager.Instance.NeedNotificationThreshold && _toiletNeed == null) @@ -187,11 +286,12 @@ public class Developer : MonoBehaviour public void UpdateEfficiency() { - _currentEfficiency = _baseStats.BaseEfficiency * (_fingersLeft / 10.0) * CalculateCaffeineEfficiency() * CalculateHungerEfficiency() * CalculateUrinationEfficiency(); + _currentEfficiency = _baseStats.BaseEfficiency * (_fingersLeft / 10.0) * CalculateCaffeineEfficiency() * CalculateHungerEfficiency() * CalculateUrinationEfficiency() * CalculateHappinessEfficiency(); } // TODO: Es könnte sich als schwierig erweisen, die Effizienz hoch zu halten. - // Man könnte ggf. die Funktionen so anpassen, dass sie eine ganze Weile 100% Effizienz geben. + // Man könnte ggf. die Funktionen so anpassen, dass sie eine ganze Weile 100% Effizienz geben. + // TODO: Das auch nur ansatzweise zu balancieren wird wiztig 🤯 private double CalculateCaffeineEfficiency() { @@ -211,16 +311,28 @@ public class Developer : MonoBehaviour private double CalculateHungerEfficiency() { + if (_hungerLevel > 1.0) + return 1.0; + // https://easings.net/#easeOutCirc - return Math.Sqrt(1.0 - Math.Pow(_caffeineLevel - 1.0, 2.0)); + return Math.Sqrt(1.0 - Math.Pow(_hungerLevel - 1.0, 2.0)); } private double CalculateUrinationEfficiency() { + if (_urgeToUrinateLevel > 1.0) + return 1.0; + // https://easings.net/#easeOutExpo return Math.Abs(_urgeToUrinateLevel - 1.0) < 0.0001f ? 1.0 : 1.0 - Math.Pow(2, -10 * _urgeToUrinateLevel); } + private double CalculateHappinessEfficiency() + { + // 50% bei 0 Happiness, 100% bei 0.75 Happiness, 125% bei 1 Happiness + return 0.5 + _happiness * 2.0 / 3.0; + } + /// /// Der Entwickler wird verletzt und der Idiot bricht sich ausgerechnet einen Finger... /// diff --git a/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs b/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs index a4fb8c6e..7b4705b6 100644 --- a/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs +++ b/3d Prototyp/Assets/Scripts/DeveloperNeeds.cs @@ -25,7 +25,8 @@ public class DeveloperNeeds : MonoBehaviour // TODO: Enums statt strings verwenden // TODO: Multiple Needs möglich übereinander anzeigen? - public GameObject SpawnCaffeineNeed() => spawnNeed(Random.Range(0.0f, 1.0f) < 0.5f ? "coffee" : "mate"); + public GameObject SpawnCoffeeNeed() => spawnNeed("coffee"); + public GameObject SpawnMateNeed() => spawnNeed("mate"); public GameObject SpawnToiletNeed() => spawnNeed("toilet"); public GameObject SpawnHungerNeed() => spawnNeed("hunger"); public GameObject SpawnMoneyNeed() => spawnNeed("money"); diff --git a/3d Prototyp/Assets/Scripts/GameManager.cs b/3d Prototyp/Assets/Scripts/GameManager.cs index 07fa0257..d5f56050 100644 --- a/3d Prototyp/Assets/Scripts/GameManager.cs +++ b/3d Prototyp/Assets/Scripts/GameManager.cs @@ -147,13 +147,15 @@ public partial class GameManager : MonoBehaviourSingleton { double developerEfficiency = 0.0f; + // TODO: Und eine weitere absolut nicht handle-bare variable... double caffeineDrain = _generalNeedDrainScaling * Math.Pow(2, _difficultySettings.CaffeineDrainScaling * GameProgress); double hungerDrain = _generalNeedDrainScaling * Math.Pow(2, _difficultySettings.HungerDrainScaling * GameProgress); double urinationDrain = _generalNeedDrainScaling * Math.Pow(2, _difficultySettings.UrinationDrainScaling * GameProgress); + double happinessDrain = _generalNeedDrainScaling * Math.Pow(2, _difficultySettings.HappinessDrainScaling * GameProgress); foreach (Developer developer in _developers) { - developer.UpdateStats(caffeineDrain, hungerDrain, urinationDrain); + developer.UpdateStats(caffeineDrain, hungerDrain, urinationDrain, happinessDrain); developer.UpdateEfficiency(); developerEfficiency += developer.CurrentEfficiency; } diff --git a/3d Prototyp/Assets/Scripts/Utility/Difficulty.cs b/3d Prototyp/Assets/Scripts/Utility/Difficulty.cs index 5d3f47d8..19423308 100644 --- a/3d Prototyp/Assets/Scripts/Utility/Difficulty.cs +++ b/3d Prototyp/Assets/Scripts/Utility/Difficulty.cs @@ -22,6 +22,7 @@ namespace Utility public double CaffeineDrainScaling { get; protected set; } public double HungerDrainScaling { get; protected set; } public double UrinationDrainScaling { get; protected set; } + public double HappinessDrainScaling { get; protected set; } } public class EasyDifficulty : DifficultySettings @@ -42,6 +43,7 @@ namespace Utility CaffeineDrainScaling = 1.5; HungerDrainScaling = 1.5; UrinationDrainScaling = 1.5; + HappinessDrainScaling = 1.5; } }