// Assets/_Project/Scripts/Editor/Gameplay/WaveGoldEntryDrawer.cs using UnityEditor; using UnityEngine; using TD.Gameplay; namespace TD.Editor.Gameplay { /// /// Custom property drawer for . Renders the standard fields /// followed by a read-only "Preview Total" line computed from the entry's values, so /// designers can see at a glance how much a single player could earn from a wave. /// /// /// The preview includes the kill-reward portion only when the entry's Wave /// reference is assigned (it's needed to count enemies in that wave). When unset, the /// preview shows just CompletionBonus + NoLeaksBonus and labels itself so the /// designer knows to drop a WaveDefinition in for a complete number. /// [CustomPropertyDrawer(typeof(WaveGoldEntry))] public class WaveGoldEntryDrawer : PropertyDrawer { private const float PreviewLineExtraHeight = 4f; public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { // Sum the children + one extra line for the preview label. We render children // ourselves rather than using EditorGUI.PropertyField default since we want a // foldout with our custom preview tacked onto the end. if (!property.isExpanded) return EditorGUIUtility.singleLineHeight; float h = EditorGUIUtility.singleLineHeight; // foldout h += SpacedLineHeight() * 4; // Wave + GoldPerEnemy + Completion + NoLeaks h += SpacedLineHeight() + PreviewLineExtraHeight; // preview label return h; } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Foldout header. Rect headerRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight); property.isExpanded = EditorGUI.Foldout(headerRect, property.isExpanded, label, toggleOnLabelClick: true); if (!property.isExpanded) return; float y = position.y + SpacedLineHeight(); float indent = 14f; Rect Row() { Rect r = new Rect(position.x + indent, y, position.width - indent, EditorGUIUtility.singleLineHeight); y += SpacedLineHeight(); return r; } // Standard property fields. var waveProp = property.FindPropertyRelative("Wave"); var perEnemyProp = property.FindPropertyRelative("GoldPerEnemy"); var completionProp = property.FindPropertyRelative("CompletionBonus"); var noLeaksProp = property.FindPropertyRelative("NoLeaksBonus"); EditorGUI.PropertyField(Row(), waveProp); EditorGUI.PropertyField(Row(), perEnemyProp); EditorGUI.PropertyField(Row(), completionProp); EditorGUI.PropertyField(Row(), noLeaksProp); // Compute the preview total. We instantiate the same logic as the runtime // property — read the serialized values, count enemies in the optional Wave, // sum it all up. Done inline (rather than calling WaveGoldEntry.PreviewTotalGold // directly) because SerializedProperty edits aren't applied to the target object // until ApplyModifiedProperties runs at the end of the frame, so reading the // backing class instance here would show stale data while the user is typing. int perEnemy = perEnemyProp.intValue; int completion = completionProp.intValue; int noLeaks = noLeaksProp.intValue; var waveAsset = waveProp.objectReferenceValue as WaveDefinition; int enemyCount = 0; if (waveAsset != null && waveAsset.Entries != null) { foreach (var e in waveAsset.Entries) { if (e.EnemyType != null && e.Count > 0) enemyCount += e.Count; } } int total = perEnemy * enemyCount + completion + noLeaks; // Preview line. Slightly dimmed style, italic, non-editable. Includes a // breakdown so the designer can see where the number came from. y += PreviewLineExtraHeight; Rect previewRect = new Rect(position.x + indent, y, position.width - indent, EditorGUIUtility.singleLineHeight); string breakdown = waveAsset != null ? $"Preview Total: {total} g ({perEnemy} × {enemyCount} enemies " + $"+ {completion} completion + {noLeaks} no-leak)" : $"Preview Total: {completion + noLeaks} g (bonuses only — assign Wave " + $"to include kill rewards)"; var prevStyle = new GUIStyle(EditorStyles.miniLabel) { fontStyle = FontStyle.Italic }; using (new EditorGUI.DisabledScope(true)) { EditorGUI.LabelField(previewRect, breakdown, prevStyle); } } private static float SpacedLineHeight() => EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; } }