update 1.2.0

This commit is contained in:
2025-07-20 10:05:55 +08:00
parent 2afbbf9be4
commit 5396d3e4b8
102 changed files with 93826 additions and 357 deletions
@@ -110,97 +110,9 @@ namespace EmeraldAI.Utility
EditorGUI.PropertyField(new Rect(rect.x, rect.y + 3f, rect.width, EditorGUIUtility.singleLineHeight), element, new GUIContent("Attack Transform " + (index + 1), AttackTransformTooltip));
};
//TODO: Make into function so it can be used with type 1 and type 2
//Type 1 Attacks
Type1Attacks = new ReorderableList(serializedObject, serializedObject.FindProperty("Type1Attacks").FindPropertyRelative("AttackDataList"), true, true, true, true);
Type1Attacks.drawHeaderCallback = rect => {
EditorGUI.LabelField(rect, "Type 1 Attacks", EditorStyles.boldLabel);
};
Type1Attacks.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) => {
var element = Type1Attacks.serializedProperty.GetArrayElementAtIndex(index);
Type1Attacks.elementHeight = EditorGUIUtility.singleLineHeight * 7.5f;
if (self.Type1Attacks.AttackDataList.Count > 0 && EmeraldAnimation.Type1AttackEnumAnimations != null)
{
CustomEditorProperties.CustomListPopup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), new GUIContent(), element.FindPropertyRelative("AttackAnimation"), "Attack Animation", EmeraldAnimation.Type1AttackEnumAnimations);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation", "The animation that will be used for this attack.\n\nNote: Animations are based off of your AI's Attack Animation List within its Animation Profile."));
}
else
{
EditorGUI.Popup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), 0, EmeraldAnimation.Type1AttackBlankOptions);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation"));
}
if (isActive)
{
CurrentAttackDistance = element.FindPropertyRelative("AttackDistance").floatValue;
CurrentTooCloseDistance = element.FindPropertyRelative("TooCloseDistance").floatValue;
DrawDistanceActive = true;
}
if (element.FindPropertyRelative("AttackDistance").floatValue == 0) element.FindPropertyRelative("AttackDistance").floatValue = 2;
if (element.FindPropertyRelative("TooCloseDistance").floatValue == 0) element.FindPropertyRelative("TooCloseDistance").floatValue = 0.5f;
EditorGUI.ObjectField(new Rect(rect.x, rect.y + 35, rect.width, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("AbilityObject"), new GUIContent("Ability Object", "The Ability Object that will be used for this attack."));
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 60, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Distance", "Controls the distance that this attack can happen within."), element.FindPropertyRelative("AttackDistance"), 0.5f, 75f);
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 85, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Too Close Distance", "Controls the distance for when an AI will backup. This is useful for AI keeping their distance from attackers."), element.FindPropertyRelative("TooCloseDistance"), 0f, 35f);
EditorGUI.BeginDisabledGroup(self.Type1Attacks.AttackPickType != AttackPickTypes.Odds);
CustomEditorProperties.CustomListIntSlider(new Rect(rect.x, rect.y + 110, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Odds", "The odds that this attack will be used (when using the Odds Pick type)."), element.FindPropertyRelative("AttackOdds"), 1, 100);
EditorGUI.EndDisabledGroup();
};
Type1Attacks.drawHeaderCallback = rect =>
{
EditorGUI.LabelField(rect, "Type 1 Attacks", EditorStyles.boldLabel);
};
//Type 2 Attacks
Type2Attacks = new ReorderableList(serializedObject, serializedObject.FindProperty("Type2Attacks").FindPropertyRelative("AttackDataList"), true, true, true, true);
Type2Attacks.drawHeaderCallback = rect => {
EditorGUI.LabelField(rect, "Type 2 Attacks", EditorStyles.boldLabel);
};
Type2Attacks.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) => {
var element = Type2Attacks.serializedProperty.GetArrayElementAtIndex(index);
Type2Attacks.elementHeight = EditorGUIUtility.singleLineHeight * 7.5f;
if (self.Type2Attacks.AttackDataList.Count > 0 && EmeraldAnimation.Type2AttackEnumAnimations != null)
{
CustomEditorProperties.CustomListPopup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), new GUIContent(), element.FindPropertyRelative("AttackAnimation"), "Attack Animation", EmeraldAnimation.Type2AttackEnumAnimations);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation", "The animation that will be used for this attack.\n\nNote: Animations are based off of your AI's Attack Animation List within its Animation Profile."));
}
else
{
EditorGUI.Popup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), 0, EmeraldAnimation.Type1AttackBlankOptions);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation"));
}
if (isActive)
{
CurrentAttackDistance = element.FindPropertyRelative("AttackDistance").floatValue;
CurrentTooCloseDistance = element.FindPropertyRelative("TooCloseDistance").floatValue;
DrawDistanceActive = true;
}
EditorGUI.ObjectField(new Rect(rect.x, rect.y + 35, rect.width, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("AbilityObject"), new GUIContent("Ability Object", "The Ability Object that will be used for this attack."));
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 60, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Distance", "Controls the distance that this attack can happen within"), element.FindPropertyRelative("AttackDistance"), 0.5f, 75f);
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 85, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Too Close Distance", "Controls the distance for when an AI will backup. This is useful for AI keeping their distance from attackers."), element.FindPropertyRelative("TooCloseDistance"), 0f, 35f);
EditorGUI.BeginDisabledGroup(self.Type2Attacks.AttackPickType != AttackPickTypes.Odds);
CustomEditorProperties.CustomListIntSlider(new Rect(rect.x, rect.y + 110, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Odds", "The odds that this attack will be used (when using the Odds Pick type)."), element.FindPropertyRelative("AttackOdds"), 1, 100);
EditorGUI.EndDisabledGroup();
};
Type2Attacks.drawHeaderCallback = rect =>
{
EditorGUI.LabelField(rect, "Type 2 Attacks", EditorStyles.boldLabel);
};
DrawType1Attacks(self);
DrawType2Attacks(self);
//Type 1 Action List
Type1ActionsList = new ReorderableList(serializedObject, serializedObject.FindProperty("Type1CombatActions"), true, true, true, true);
@@ -545,6 +457,139 @@ namespace EmeraldAI.Utility
DrawCombatRadii(self);
}
void DrawType1Attacks(EmeraldCombat self)
{
//Type 1 Attacks
Type1Attacks = new ReorderableList(serializedObject, serializedObject.FindProperty("Type1Attacks").FindPropertyRelative("AttackDataList"), true, true, true, true);
Type1Attacks.drawHeaderCallback = rect => {
EditorGUI.LabelField(rect, "Type 1 Attacks", EditorStyles.boldLabel);
};
Type1Attacks.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) => {
var element = Type1Attacks.serializedProperty.GetArrayElementAtIndex(index);
if (self.Type1Attacks.AttackDataList[index].AbilityObject != null && self.Type1Attacks.AttackDataList[index].AbilityObject.ConditionSettings.Enabled)
{
Rect helpBoxRect = new Rect(rect.x, rect.y + 133, rect.width, EditorGUIUtility.singleLineHeight * 1.5f);
GUIContent content = new GUIContent(" Condition Module Active (See tooltip)", EditorGUIUtility.IconContent("console.warnicon").image, "Abilities that use a Condition Module will need to have their condition met in order to be triggered. " +
"Conditions that are High Priorty will ignore an AI's Pick Type and be picked first, given the condition is met.\n\nNote: If the condition is not met, this ability will be skipped.");
EditorGUI.LabelField(helpBoxRect, content, EditorStyles.label);
}
if (self.Type1Attacks.AttackDataList.Count > 0 && EmeraldAnimation.Type1AttackEnumAnimations != null)
{
CustomEditorProperties.CustomListPopup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), new GUIContent(), element.FindPropertyRelative("AttackAnimation"), "Attack Animation", EmeraldAnimation.Type1AttackEnumAnimations);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation", "The animation that will be used for this attack.\n\nNote: Animations are based off of your AI's Attack Animation List within its Animation Profile."));
}
else
{
EditorGUI.Popup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), 0, EmeraldAnimation.Type1AttackBlankOptions);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation"));
}
if (isActive)
{
CurrentAttackDistance = element.FindPropertyRelative("AttackDistance").floatValue;
CurrentTooCloseDistance = element.FindPropertyRelative("TooCloseDistance").floatValue;
DrawDistanceActive = true;
}
if (element.FindPropertyRelative("AttackDistance").floatValue == 0) element.FindPropertyRelative("AttackDistance").floatValue = 2;
if (element.FindPropertyRelative("TooCloseDistance").floatValue == 0) element.FindPropertyRelative("TooCloseDistance").floatValue = 0.5f;
EditorGUI.ObjectField(new Rect(rect.x, rect.y + 35, rect.width, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("AbilityObject"), new GUIContent("Ability Object", "The Ability Object that will be used for this attack."));
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 60, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Distance", "Controls the distance that this attack can happen within."), element.FindPropertyRelative("AttackDistance"), 0.5f, 75f);
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 85, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Too Close Distance", "Controls the distance for when an AI will backup. This is useful for AI keeping their distance from attackers."), element.FindPropertyRelative("TooCloseDistance"), 0f, 35f);
EditorGUI.BeginDisabledGroup(self.Type1Attacks.AttackPickType != AttackPickTypes.Odds);
CustomEditorProperties.CustomListIntSlider(new Rect(rect.x, rect.y + 110, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Odds", "The odds that this attack will be used (when using the Odds Pick type)."), element.FindPropertyRelative("AttackOdds"), 1, 100);
EditorGUI.EndDisabledGroup();
};
//Modify the heights of each element to create a cleaner reorderable list. This allows the element with a condition module active to have room to display the icon and info.
Type1Attacks.elementHeightCallback = (int index) =>
{
SerializedProperty element = Type1Attacks.serializedProperty.GetArrayElementAtIndex(index);
float height = EditorGUIUtility.singleLineHeight * 7.5f;
if (self.Type1Attacks.AttackDataList[index].AbilityObject && self.Type1Attacks.AttackDataList[index].AbilityObject.ConditionSettings.Enabled)
height += 26f;
return height;
};
Type1Attacks.drawHeaderCallback = rect =>
{
EditorGUI.LabelField(rect, "Type 1 Attacks", EditorStyles.boldLabel);
};
}
void DrawType2Attacks(EmeraldCombat self)
{
//Type 2 Attacks
Type2Attacks = new ReorderableList(serializedObject, serializedObject.FindProperty("Type2Attacks").FindPropertyRelative("AttackDataList"), true, true, true, true);
Type2Attacks.drawHeaderCallback = rect => {
EditorGUI.LabelField(rect, "Type 2 Attacks", EditorStyles.boldLabel);
};
Type2Attacks.drawElementCallback =
(Rect rect, int index, bool isActive, bool isFocused) => {
var element = Type2Attacks.serializedProperty.GetArrayElementAtIndex(index);
if (self.Type2Attacks.AttackDataList[index].AbilityObject != null && self.Type2Attacks.AttackDataList[index].AbilityObject.ConditionSettings.Enabled)
{
Rect helpBoxRect = new Rect(rect.x, rect.y + 133, rect.width, EditorGUIUtility.singleLineHeight * 1.5f);
GUIContent content = new GUIContent(" Condition Module Active (See tooltip)", EditorGUIUtility.IconContent("console.warnicon").image, "Abilities that use a Condition Module will need to have their condition met in order to be triggered. " +
"Conditions that are High Priorty will ignore an AI's Pick Type and be picked first, given the condition is met.\n\nNote: If the condition is not met, this ability will be skipped.");
EditorGUI.LabelField(helpBoxRect, content, EditorStyles.label);
}
if (self.Type2Attacks.AttackDataList.Count > 0 && EmeraldAnimation.Type2AttackEnumAnimations != null)
{
CustomEditorProperties.CustomListPopup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), new GUIContent(), element.FindPropertyRelative("AttackAnimation"), "Attack Animation", EmeraldAnimation.Type2AttackEnumAnimations);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation", "The animation that will be used for this attack.\n\nNote: Animations are based off of your AI's Attack Animation List within its Animation Profile."));
}
else
{
EditorGUI.Popup(new Rect(rect.x + 125, rect.y + 10, rect.width - 125, EditorGUIUtility.singleLineHeight), 0, EmeraldAnimation.Type1AttackBlankOptions);
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 10, 125, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Animation"));
}
if (isActive)
{
CurrentAttackDistance = element.FindPropertyRelative("AttackDistance").floatValue;
CurrentTooCloseDistance = element.FindPropertyRelative("TooCloseDistance").floatValue;
DrawDistanceActive = true;
}
EditorGUI.ObjectField(new Rect(rect.x, rect.y + 35, rect.width, EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("AbilityObject"), new GUIContent("Ability Object", "The Ability Object that will be used for this attack."));
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 60, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Distance", "Controls the distance that this attack can happen within"), element.FindPropertyRelative("AttackDistance"), 0.5f, 75f);
CustomEditorProperties.CustomListFloatSlider(new Rect(rect.x, rect.y + 85, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Too Close Distance", "Controls the distance for when an AI will backup. This is useful for AI keeping their distance from attackers."), element.FindPropertyRelative("TooCloseDistance"), 0f, 35f);
EditorGUI.BeginDisabledGroup(self.Type2Attacks.AttackPickType != AttackPickTypes.Odds);
CustomEditorProperties.CustomListIntSlider(new Rect(rect.x, rect.y + 110, rect.width, EditorGUIUtility.singleLineHeight), new GUIContent("Attack Odds", "The odds that this attack will be used (when using the Odds Pick type)."), element.FindPropertyRelative("AttackOdds"), 1, 100);
EditorGUI.EndDisabledGroup();
};
//Modify the heights of each element to create a cleaner reorderable list. This allows the element with a condition module active to have room to display the icon and info.
Type2Attacks.elementHeightCallback = (int index) =>
{
SerializedProperty element = Type2Attacks.serializedProperty.GetArrayElementAtIndex(index);
float height = EditorGUIUtility.singleLineHeight * 7.5f;
if (self.Type2Attacks.AttackDataList[index].AbilityObject && self.Type2Attacks.AttackDataList[index].AbilityObject.ConditionSettings.Enabled)
height += 26f;
return height;
};
Type2Attacks.drawHeaderCallback = rect =>
{
EditorGUI.LabelField(rect, "Type 2 Attacks", EditorStyles.boldLabel);
};
}
void DrawCombatRadii (EmeraldCombat self)
{
if (DrawDistanceActive)