BITFALL/Assets/Plugins/Loot Table/Script/LootDrop.cs

389 lines
17 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using TinyScript;
#if UNITY_EDITOR
using UnityEditorInternal;
#endif
namespace TinyScript {
[CreateAssetMenu(fileName = "Loot Table", menuName = "Tiny Slime Studio/Loot Table SO")]
public class LootDrop : ScriptableObject
{
public DropChangeItem[] GuaranteedLootTable = new DropChangeItem[0];
public DropChangeItem[] OneItemFromList = new DropChangeItem[1];
public float WeightToNoDrop = 100;
// Return List of Guaranteed Drop
public List<GameObject> GetGuaranteeedLoot()
{
List<GameObject> lootList = new List<GameObject>();
for (int i = 0; i < GuaranteedLootTable.Length; i++)
{
// Adds the drawn number of items to drop
int count = Random.Range(GuaranteedLootTable[i].MinCountItem, GuaranteedLootTable[i].MaxCountItem);
for (int j = 0; j < count; j++)
{
lootList.Add(GuaranteedLootTable[i].Drop);
}
}
return lootList;
}
// Return List of Optional Drop
public List<GameObject> GetRandomLoot(int ChangeCount)
{
List<GameObject> lootList = new List<GameObject>();
float totalWeight = WeightToNoDrop;
// Executes a function a specified number of times
for (int j = 0; j < ChangeCount; j++)
{
// They add up the entire weight of the items
for (int i = 0; i < OneItemFromList.Length; i++)
{
totalWeight += OneItemFromList[i].Weight;
}
float value = Random.Range(0, totalWeight);
float timed_value = 0;
for (int i = 0; i < OneItemFromList.Length; i++)
{
// If timed_value is greater than value, it means this item has been drawn
timed_value += OneItemFromList[i].Weight;
if (timed_value > value)
{
int count = Random.Range(OneItemFromList[i].MinCountItem, OneItemFromList[i].MaxCountItem + 1);
for (int c = 0; c < count; c++)
{
lootList.Add(OneItemFromList[i].Drop);
}
break;
}
}
}
return lootList;
}
public void SpawnDrop(Transform _position, int _count, float _range)
{
List<GameObject> guaranteed = GetGuaranteeedLoot();
List<GameObject> randomLoot = GetRandomLoot(_count);
for (int i = 0; i < guaranteed.Count; i++)
{
Instantiate(guaranteed[i], new Vector3(_position.position.x + Random.Range(-_range, _range), _position.position.y, _position.position.z + Random.Range(-_range, _range)), Quaternion.identity);
}
for (int i = 0; i < randomLoot.Count; i++)
{
Instantiate(randomLoot[i], new Vector3(_position.position.x + Random.Range(-_range, _range), _position.position.y, _position.position.z + Random.Range(-_range, _range)), Quaternion.identity);
}
}
}
/* --------------------- */
// Drop Item Change Class
/* --------------------- */
[System.Serializable]
public class DropChangeItem
{
public float Weight;
public GameObject Drop;
public int MinCountItem;
public int MaxCountItem;
}
}
/* --------------------- */
// Custom Editor & Property Draw (look)
/* --------------------- */
#if UNITY_EDITOR
/* --------------------- */
// Custom Editor
/* --------------------- */
[CustomEditor(typeof(LootDrop))]
public class LootDropEditor : Editor
{
// Guaranteed
SerializedProperty guaranteedList;
ReorderableList reorderableGuaranteed;
// Change
SerializedProperty changeToGetList;
ReorderableList reorderableChange;
LootDrop ld;
private void OnEnable()
{
/* GUARANTEED */
guaranteedList = serializedObject.FindProperty("GuaranteedLootTable");
reorderableGuaranteed = new ReorderableList(serializedObject, guaranteedList, true, true, true, true);
// Functions
reorderableGuaranteed.drawElementCallback = DrawGuaranteedListItems;
reorderableGuaranteed.drawHeaderCallback = DrawHeaderGuaranteed;
/* Change */
changeToGetList = serializedObject.FindProperty("OneItemFromList");
reorderableChange = new ReorderableList(serializedObject, changeToGetList, true, true, true, true);
// Functions
reorderableChange.drawElementCallback += DrawChangeListItems;
reorderableChange.drawHeaderCallback += DrawHeaderChange;
ld = target as LootDrop;
}
void DrawHeaderGuaranteed(Rect rect) { EditorGUI.LabelField(rect, "Guaranteed Loot Table"); }
void DrawHeaderChange(Rect rect) { EditorGUI.LabelField(rect, "Change To Get Loot Table"); }
void DrawGuaranteedListItems(Rect rect, int index, bool isActive, bool isFocused)
{
LootDrop loot = (LootDrop)target;
reorderableGuaranteed.elementHeight = 42;
SerializedProperty element = reorderableGuaranteed.serializedProperty.GetArrayElementAtIndex(index);
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, rect.height), element, GUIContent.none);
//LootDrop loot = (LootDrop)target;
}
void DrawChangeListItems(Rect rect, int index, bool isActive, bool isFocused)
{
reorderableChange.elementHeight = 42;
SerializedProperty element = reorderableChange.serializedProperty.GetArrayElementAtIndex(index);
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, rect.height), element, GUIContent.none);
}
public override void OnInspectorGUI()
{
EditorUtility.SetDirty(target);
LootDrop loot = (LootDrop)target;
EditorGUILayout.BeginVertical("box");
EditorGUI.indentLevel = 0;
// Loot Name
GUIStyle myStyle = new GUIStyle();
myStyle.normal.textColor = GUI.color;
myStyle.alignment = TextAnchor.UpperCenter;
myStyle.fontStyle = FontStyle.Bold;
int _ti = myStyle.fontSize;
EditorGUILayout.LabelField($"Loot Table", myStyle);
myStyle.fontStyle = FontStyle.Italic;
myStyle.fontSize = 20;
EditorGUILayout.LabelField($",,{loot.name}''", myStyle);
EditorGUILayout.Space(10);
EditorGUI.BeginChangeCheck();
/* Fixed by D9Construct */
serializedObject.Update();
ValidateGuaranteedList(loot);
reorderableGuaranteed.DoLayoutList();
ValidateOneItemFromList(loot);
reorderableChange.DoLayoutList();
serializedObject.ApplyModifiedProperties();
if (EditorGUI.EndChangeCheck())
{
for (int index = 0; index < loot.OneItemFromList.Length; index++)
{
SerializedProperty OIFElement = reorderableChange.serializedProperty.GetArrayElementAtIndex(index);
loot.OneItemFromList[index].Weight = OIFElement.FindPropertyRelative("Weight").floatValue;
loot.OneItemFromList[index].Drop = (GameObject)OIFElement.FindPropertyRelative("Drop").objectReferenceValue;
loot.OneItemFromList[index].MinCountItem = OIFElement.FindPropertyRelative("MinCountItem").intValue;
loot.OneItemFromList[index].MaxCountItem = OIFElement.FindPropertyRelative("MaxCountItem").intValue;
}
for (int index = 0; index < loot.GuaranteedLootTable.Length; index++)
{
SerializedProperty GuaranteedElement = reorderableGuaranteed.serializedProperty.GetArrayElementAtIndex(index);
loot.GuaranteedLootTable[index].Weight = GuaranteedElement.FindPropertyRelative("Weight").floatValue;
loot.GuaranteedLootTable[index].Drop = (GameObject)GuaranteedElement.FindPropertyRelative("Drop").objectReferenceValue;
loot.GuaranteedLootTable[index].MinCountItem = GuaranteedElement.FindPropertyRelative("MinCountItem").intValue;
loot.GuaranteedLootTable[index].MaxCountItem = GuaranteedElement.FindPropertyRelative("MaxCountItem").intValue;
}
}
/* Fixed by D9Construct */
// Nothing Weight
loot.WeightToNoDrop = EditorGUILayout.FloatField("No Drop Weight", loot.WeightToNoDrop);
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
Rect r = EditorGUILayout.BeginVertical("box");
myStyle.fontStyle = FontStyle.Bold;
myStyle.fontSize = 20;
EditorGUILayout.Space(5);
EditorGUILayout.LabelField($"Drop Change", myStyle);
float totalWeight = loot.WeightToNoDrop;
float guaranteedHeight = 0;
if (loot.OneItemFromList != null)
{
for (int j = 0; j < loot.OneItemFromList.Length; j++)
{
totalWeight += loot.OneItemFromList[j].Weight;
}
}
var _oldColor = GUI.backgroundColor;
if (0 < loot.GuaranteedLootTable.Length) { guaranteedHeight += 10; }
/* Guaranteed */
GUI.backgroundColor = Color.green;
for (int i = 0; i < loot.GuaranteedLootTable.Length; i++)
{
string _tmpString = "";
guaranteedHeight += 25;
if (loot.GuaranteedLootTable[i].Drop == null) { _tmpString = " --- No Drop Object --- "; } else { _tmpString = loot.GuaranteedLootTable[i].Drop.name; }
EditorGUI.ProgressBar(new Rect(r.x + 5, r.y + 40 + (25 * i), r.width - 10, 20), 1, $"{_tmpString} [{loot.GuaranteedLootTable[i].MinCountItem}-{loot.GuaranteedLootTable[i].MaxCountItem}] - Guaranteed");
}
GUI.backgroundColor = _oldColor;
/* Not Guaranteed */
for (int i = 0; i < loot.OneItemFromList.Length; i++)
{
string _tmpString = "";
if (loot.OneItemFromList[i].Drop == null) { _tmpString = "!!! No Drop Object Attackhment !!!"; } else { _tmpString = loot.OneItemFromList[i].Drop.name; }
if (loot.OneItemFromList[i].Weight / totalWeight < 0) {
GUI.backgroundColor = Color.red;
EditorGUI.ProgressBar(new Rect(r.x + 5, r.y + 40 + (25 * i) + guaranteedHeight, r.width - 10, 20), 1, "Error");
} else {
EditorGUI.ProgressBar(new Rect(r.x + 5, r.y + 40 + (25 * i) + guaranteedHeight, r.width - 10, 20), loot.OneItemFromList[i].Weight / totalWeight, $"{_tmpString} [{loot.OneItemFromList[i].MinCountItem}-{loot.OneItemFromList[i].MaxCountItem}] - {(loot.OneItemFromList[i].Weight / totalWeight * 100).ToString("f2")}%");
}
GUI.backgroundColor = _oldColor;
}
GUI.backgroundColor = Color.gray;
EditorGUI.ProgressBar(new Rect(r.x + 5, r.y + 40 + (25 * loot.OneItemFromList.Length + 10) + guaranteedHeight, r.width - 10, 20), loot.WeightToNoDrop / totalWeight, $"Nothing Additional - {(loot.WeightToNoDrop / totalWeight * 100).ToString("f2")}%");
GUI.backgroundColor = _oldColor;
EditorGUILayout.Space(25 * loot.OneItemFromList.Length + 45 + guaranteedHeight);
EditorGUILayout.EndVertical();
}
void ValidateOneItemFromList(LootDrop loot)
{
bool _countError = false;
bool _prefabError = false;
bool _weightError = false;
for (int index = 0; index < loot.OneItemFromList.Length; index++)
{
if (loot.OneItemFromList[index].Drop == null) { _prefabError = true; }
if (loot.OneItemFromList[index].MinCountItem <= 0) { _countError = true; }
if (loot.OneItemFromList[index].MinCountItem > loot.OneItemFromList[index].MaxCountItem) { _countError = true; }
if (loot.OneItemFromList[index].Weight < 0) { _weightError = true; }
}
if (_prefabError == true) { EditorGUILayout.HelpBox("One of the List Items does not have ''Item To Drop'' assigned, which will cause an error if it is drawn", MessageType.Error, true); }
if (_countError == true) { EditorGUILayout.HelpBox("One of the List Items has an incorrect number of items, which will result in items not appearing when drawn", MessageType.Warning, true); }
if (_weightError == true) { EditorGUILayout.HelpBox("One of the List Items has an incorrect Weight, this will cause erroneous data readings or the whole system will crash", MessageType.Error, true); }
}
void ValidateGuaranteedList(LootDrop loot)
{
bool _countError = false;
bool _prefabError = false;
bool _weightError = false;
for (int index = 0; index < loot.GuaranteedLootTable.Length; index++)
{
if (loot.GuaranteedLootTable[index].Drop == null) { _prefabError = true; }
if (loot.GuaranteedLootTable[index].MinCountItem <= 0) { _countError = true; }
if (loot.GuaranteedLootTable[index].MinCountItem > loot.GuaranteedLootTable[index].MaxCountItem) { _countError = true; }
if (loot.GuaranteedLootTable[index].Weight < 0) { _weightError = true; }
}
if (_prefabError == true) { EditorGUILayout.HelpBox("One of the List Items does not have ''Item To Drop'' assigned, which will cause an error if it is drawn", MessageType.Error, true); }
if (_countError == true) { EditorGUILayout.HelpBox("One of the List Items has an incorrect number of items, which will result in items not appearing when drawn", MessageType.Warning, true); }
if (_weightError == true) { EditorGUILayout.HelpBox("One of the List Items has an incorrect Weight, this will cause erroneous data readings or the whole system will crash", MessageType.Error, true); }
}
}
/* --------------------- */
// Custom Property Draw
/* --------------------- */
[CustomPropertyDrawer(typeof(DropChangeItem))]
public class DropChangeItemDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var _oldColor = GUI.backgroundColor;
EditorGUI.BeginProperty(position, label, property);
//GUI.backgroundColor = Color.red;
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
var weightRectLabel = new Rect(position.x, position.y, 55, 18);
var weightRect = new Rect(position.x, position.y + 20, 55, 18);
EditorGUI.LabelField(weightRectLabel, "Weight");
if(property.FindPropertyRelative("Weight").floatValue < 0) { GUI.backgroundColor = Color.red; }
EditorGUI.PropertyField(weightRect, property.FindPropertyRelative("Weight"), GUIContent.none);
GUI.backgroundColor = _oldColor;
var ItemRectLabel = new Rect(position.x + 60, position.y, position.width - 60, 18);
var ItemRect = new Rect(position.x + 60, position.y + 20, position.width - 60 - 75, 18);
EditorGUI.LabelField(ItemRectLabel, "Item To Drop");
if(property.FindPropertyRelative("Drop").objectReferenceValue == null) { GUI.backgroundColor = Color.red; }
EditorGUI.PropertyField(ItemRect, property.FindPropertyRelative("Drop"), GUIContent.none);
GUI.backgroundColor = _oldColor;
var MinMaxRectLabel = new Rect(position.x + position.width - 70, position.y, 70, 18);
var MinRect = new Rect(position.x + position.width - 70, position.y + 20, 30, 18);
var MinMaxRect = new Rect(position.x + position.width - 39, position.y + 20, 9, 18);
var MaxRect = new Rect(position.x + position.width - 30, position.y + 20, 30, 18);
if(property.FindPropertyRelative("MinCountItem").intValue < 0) { GUI.backgroundColor = Color.red; }
if (property.FindPropertyRelative("MaxCountItem").intValue < property.FindPropertyRelative("MinCountItem").intValue) { GUI.backgroundColor = Color.red; }
EditorGUI.LabelField(MinMaxRectLabel, "Min - Max");
EditorGUI.PropertyField(MinRect, property.FindPropertyRelative("MinCountItem"), GUIContent.none);
EditorGUI.LabelField(MinMaxRect, "-");
EditorGUI.PropertyField(MaxRect, property.FindPropertyRelative("MaxCountItem"), GUIContent.none);
GUI.backgroundColor = _oldColor;
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return 40;
}
}
#endif