using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System; using RPGCreationKit; using System.IO; using System.Reflection; using System.Linq; namespace RPGCreationKit { public class QuestWindow : EditorWindow { public bool isReady = false; public SerializedObject questObj; // Navigation public enum CurrentWindow { Quest, QuestStages, NPCs, Dialogues }; CurrentWindow m_Window; // Buttons scroll Vector2 buttonsScrollPos; Vector2 indexesScrollView; GUIStyle guiLayoutDarkColor = new GUIStyle(); GUIStyle guiLayoutLightColor = new GUIStyle(); // Quest Conditions Vector2 questConditionsScrollView = Vector2.zero; int selectedQuestConditionIndex = -1; // Quest Stage Conditions Vector2 questStageConditionsScrollView = Vector2.zero; int selectedQuestStageConditionIndex = -1; bool isCreatingNewStage = false; bool hasSelectedStage = false; int selectedStage = 0; MonoScript[] allQuestScripts; MonoScript[] allQuestStagesScripts; void Callback(object obj) { ScriptElementData questScriptData = (ScriptElementData)obj; questScriptData.property.stringValue = questScriptData.value; } public void Init(SerializedObject _quest) { // Windows is created from 'Configure' button of the Inspector of the Quest // Set Title Texture icon = AssetDatabase.LoadAssetAtPath(EditorIconsPath.QuestWindowIcon); GUIContent titleContent = new GUIContent("Quest Window", icon); this.titleContent = titleContent; // We copy the Item SerializedObject to not lose reference. SerializedObject itemcopy = new SerializedObject(_quest.targetObject); questObj = itemcopy; guiLayoutDarkColor.normal.background = MakeTex(600, 1, new Color(5.0f, 5.0f, 5.0f, .1f)); guiLayoutLightColor.normal.background = MakeTex(600, 1, new Color(37.0f, 79.0f, 133.0f, .4f)); allQuestScripts = NodesHelper.GetAllResultScripts(); allQuestStagesScripts = NodesHelper.GetAllResultScripts(); isReady = true; this.Show(); } private Texture2D MakeTex(int width, int height, Color col) { Color[] pix = new Color[width * height]; for (int i = 0; i < pix.Length; i++) pix[i] = col; Texture2D result = new Texture2D(width, height); result.SetPixels(pix); result.Apply(); return result; } public void OnGUI() { if (!questObj.targetObject) { Debug.LogWarning("ItemObj: NullReferenceException"); return; } GUIStyle ButtonStyle = new GUIStyle(GUI.skin.button) { alignment = TextAnchor.MiddleCenter }; ButtonStyle.border = new RectOffset(2,2,2,2); ButtonStyle.fontSize = 16; ButtonStyle.font = (Font)AssetDatabase.LoadAssetAtPath("Assets/RPG Creation Kit/Fonts/monofonto.ttf"); GUIStyle HeaderStyle = new GUIStyle(GUI.skin.label) { alignment = TextAnchor.MiddleLeft }; HeaderStyle.fontSize = 14; HeaderStyle.font = (Font)AssetDatabase.LoadAssetAtPath("Assets/RPG Creation Kit/Fonts/monofonto.ttf"); EditorGUILayout.BeginHorizontal("box"); EditorGUILayout.LabelField("Configuring: " + questObj.targetObject.name, EditorStyles.boldLabel); EditorGUILayout.EndHorizontal(); // Scroll View Of Buttons: buttonsScrollPos = EditorGUILayout.BeginScrollView(buttonsScrollPos, GUILayout.Width(position.width), GUILayout.Height(75)); GUILayout.BeginHorizontal(); GUILayout.Space(212); GUILayout.BeginHorizontal("box"); #region NavigationMenu // Buttons for navigation var defaultColor = GUI.color; if (m_Window == CurrentWindow.Quest) GUI.color = Color.green; else GUI.color = defaultColor; if (GUILayout.Button("Quests", GUILayout.Width(125), GUILayout.Height(20))) { m_Window = CurrentWindow.Quest; } if (m_Window == CurrentWindow.QuestStages) GUI.color = Color.green; else GUI.color = defaultColor; if (GUILayout.Button("Quest Stages", GUILayout.Width(125), GUILayout.Height(20))) { m_Window = CurrentWindow.QuestStages; } if (m_Window == CurrentWindow.NPCs) GUI.color = Color.green; else GUI.color = defaultColor; if (GUILayout.Button("NPCs", GUILayout.Width(125), GUILayout.Height(20))) { m_Window = CurrentWindow.NPCs; } if (m_Window == CurrentWindow.Dialogues) GUI.color = Color.green; else GUI.color = defaultColor; if (GUILayout.Button("Dialogues", GUILayout.Width(125), GUILayout.Height(20))) { m_Window = CurrentWindow.Dialogues; } GUILayout.EndHorizontal(); GUI.color = defaultColor; EditorGUILayout.EndScrollView(); GUILayout.EndHorizontal(); #endregion switch (m_Window) { case CurrentWindow.Quest: #region code EditorGUILayout.BeginVertical("Box"); EditorGUILayout.LabelField("QUEST SETTINGS:", HeaderStyle); EditorGUILayout.PropertyField(questObj.FindProperty("questName")); EditorGUILayout.PropertyField(questObj.FindProperty("questID")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(questObj.FindProperty("questDescription")); EditorGUILayout.Space(); EditorGUILayout.PropertyField(questObj.FindProperty("questPriority")); //EditorGUILayout.PropertyField(questObj.FindProperty("questScript")); // display the GenericMenu when pressing a button EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel("Quest Script:"); string menuDisplayValue = string.IsNullOrEmpty(questObj.FindProperty("questScript").stringValue) ? "-None-" : questObj.FindProperty("questScript").stringValue; if (GUILayout.Button(menuDisplayValue)) { // create the menu and add items to it GenericMenu menu = new GenericMenu(); menu.AddDisabledItem(new GUIContent("Quest Scripts")); menu.AddSeparator(""); menu.AddItem(new GUIContent("None"), false, Callback, new ScriptElementData(questObj.FindProperty("questScript"), "")); for (int i = 0; i < allQuestScripts.Length; i++) { menu.AddItem(new GUIContent(allQuestScripts[i].name), false, Callback, new ScriptElementData(questObj.FindProperty("questScript"), allQuestScripts[i].GetClass().Namespace+"."+allQuestScripts[i].name)); } menu.ShowAsContext(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.PropertyField(questObj.FindProperty("firstStageIsDefaultStage")); EditorGUILayout.PropertyField(questObj.FindProperty("allowRepeatedStages")); EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical("Box"); Event current = Event.current; EditorGUILayout.LabelField("QUEST CONDITIONS:", HeaderStyle); questConditionsScrollView = EditorGUILayout.BeginScrollView(questConditionsScrollView, true, true, GUILayout.Width(position.width), GUILayout.Height(360)); Rect questConditionRectArea = new Rect(questConditionsScrollView.x, questConditionsScrollView.y, position.width, 360); for (int i = 0; i < questObj.FindProperty("questConditions").arraySize; i++) { Rect currentConditionArea = EditorGUILayout.BeginHorizontal((selectedQuestConditionIndex == i) ? guiLayoutLightColor : guiLayoutDarkColor); EditorGUILayout.PropertyField(questObj.FindProperty("questConditions").GetArrayElementAtIndex(i), GUILayout.Width(1500)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); if (currentConditionArea.Contains(current.mousePosition) && Event.current.type == EventType.MouseDown && Event.current.button == 0) { selectedQuestConditionIndex = i; Repaint(); } } // DROPDOWN TO CREATE NEW CONDITIONS if (questConditionRectArea.Contains(current.mousePosition) && current.type == EventType.ContextClick) { GenericMenu menu = new GenericMenu(); menu.AddDisabledItem(new GUIContent("Quests Conditions")); menu.AddItem(new GUIContent("New"), false, CreateNewQuestCondition); menu.AddItem(new GUIContent("Delete Selected"), false, DeleteSelectedQuestCondition); menu.ShowAsContext(); current.Use(); } void CreateNewQuestCondition() { questObj.FindProperty("questConditions").InsertArrayElementAtIndex(questObj.FindProperty("questConditions").arraySize); selectedQuestConditionIndex = questObj.FindProperty("questConditions").arraySize - 1; Repaint(); } void DeleteSelectedQuestCondition() { if (selectedQuestConditionIndex != -1) { questObj.FindProperty("questConditions").DeleteArrayElementAtIndex(selectedQuestConditionIndex); selectedQuestConditionIndex = -1; Repaint(); } } EditorGUILayout.EndScrollView(); EditorGUILayout.BeginHorizontal("box", GUILayout.MaxWidth(150)); GUI.enabled = (selectedQuestConditionIndex != -1) ? true : false; GUI.enabled = (selectedQuestConditionIndex != -1 && selectedQuestConditionIndex != 0); if(GUILayout.Button("↑")) { GUI.FocusControl(null); questObj.FindProperty("questConditions").MoveArrayElement(selectedQuestConditionIndex, selectedQuestConditionIndex - 1); selectedQuestConditionIndex = selectedQuestConditionIndex - 1; Repaint(); } GUI.enabled = (selectedQuestConditionIndex != -1 && selectedQuestConditionIndex != questObj.FindProperty("questConditions").arraySize - 1); if (GUILayout.Button("↓")) { GUI.FocusControl(null); questObj.FindProperty("questConditions").MoveArrayElement(selectedQuestConditionIndex, selectedQuestConditionIndex + 1); selectedQuestConditionIndex = selectedQuestConditionIndex + 1; Repaint(); } GUI.enabled = true; EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); GUILayout.FlexibleSpace(); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("SAVE", ButtonStyle)) { questObj.ApplyModifiedProperties(); // Refresh database var AllQuestDatabaseFiles = GetAllInstances(); foreach (QuestsDatabaseFile file in AllQuestDatabaseFiles) file.fill(); this.Close(); } if (GUILayout.Button("CANCEL", ButtonStyle)) { this.Close(); } EditorGUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); #endregion break; case CurrentWindow.QuestStages: #region code EditorGUILayout.LabelField(" [QUEST STAGES]", HeaderStyle, GUILayout.MaxWidth(200.0f)); EditorGUILayout.BeginHorizontal(); // --- LEFT PANEL indexesScrollView = EditorGUILayout.BeginScrollView(indexesScrollView, GUILayout.Width(210.0f), GUILayout.Height(550.0f)); Rect clickArea = EditorGUILayout.BeginVertical(guiLayoutDarkColor, GUILayout.Width(200.0f), GUILayout.Height(550.0f)); current = Event.current; GUI.enabled = !isCreatingNewStage; // Display all current quest stages EditorGUILayout.BeginVertical(); for (int i = 0; i < questObj.FindProperty("questStages").arraySize; i++) { if (selectedStage == i && hasSelectedStage) GUI.color = Color.green; GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Stage " + questObj.FindProperty("questStages").GetArrayElementAtIndex(i).FindPropertyRelative("index").intValue.ToString(), GUILayout.Width(150.0f))) { GUI.FocusControl(null); selectedStage = i; selectedQuestStageConditionIndex = -1; hasSelectedStage = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUI.color = defaultColor; } GUI.enabled = true; if (!isCreatingNewStage) { // DROPDOWN TO CREATE NEW STAGES if (clickArea.Contains(current.mousePosition) && current.type == EventType.ContextClick) { GenericMenu menu = new GenericMenu(); menu.AddDisabledItem(new GUIContent("Quest Stages")); menu.AddSeparator(""); menu.AddItem(new GUIContent("New"), false, CreateNew); menu.AddItem(new GUIContent("Delete Selected"), false, DeleteSelected); menu.ShowAsContext(); current.Use(); } } else { int newStageIndex = 0; EditorGUI.BeginChangeCheck(); GUI.SetNextControlName("NewStageField"); newStageIndex = EditorGUILayout.DelayedIntField(newStageIndex); GUI.FocusControl("NewStageField"); Event e = Event.current; switch (e.type) { case EventType.KeyDown: if (current.keyCode == KeyCode.Escape) { isCreatingNewStage = false; Repaint(); } break; } // IF CREATE NEW ELEMENT if (EditorGUI.EndChangeCheck()) { //check if the selected stage index doesn't already exist bool newStageAlreadyExist = false; for(int i = 0; i < questObj.FindProperty("questStages").arraySize; i++) { if (questObj.FindProperty("questStages").GetArrayElementAtIndex(i).FindPropertyRelative("index").intValue == newStageIndex) { newStageAlreadyExist = true; break; } } // If the new stage already exist set it to a non-used stage (the last one +1) if (newStageAlreadyExist) newStageIndex = questObj.FindProperty("questStages").GetArrayElementAtIndex(questObj.FindProperty("questStages").arraySize - 1).FindPropertyRelative("index").intValue +1; questObj.FindProperty("questStages").InsertArrayElementAtIndex(questObj.FindProperty("questStages").arraySize); questObj.FindProperty("questStages").GetArrayElementAtIndex(questObj.FindProperty("questStages").arraySize - 1).FindPropertyRelative("index").intValue = newStageIndex; // Order Array bool triggered = false; // for selecting the corrent stage for(int i = 0; i < questObj.FindProperty("questStages").arraySize; i++) { if(questObj.FindProperty("questStages").GetArrayElementAtIndex(questObj.FindProperty("questStages").arraySize - 1).FindPropertyRelative("index").intValue < questObj.FindProperty("questStages").GetArrayElementAtIndex(i).FindPropertyRelative("index").intValue) { questObj.FindProperty("questStages").MoveArrayElement(questObj.FindProperty("questStages").arraySize - 1, i); selectedStage = i; triggered = true; } else if(!triggered) selectedStage = questObj.FindProperty("questStages").arraySize - 1; } isCreatingNewStage = false; } } void CreateNew() { isCreatingNewStage = true; selectedQuestStageConditionIndex = -1; } void DeleteSelected() { if (hasSelectedStage) { questObj.FindProperty("questStages").DeleteArrayElementAtIndex(selectedStage); hasSelectedStage = false; } } EditorGUILayout.EndScrollView(); EditorGUILayout.EndVertical(); EditorGUILayout.EndVertical(); EditorGUILayout.BeginHorizontal(); if (hasSelectedStage) { EditorGUILayout.BeginVertical("box", GUILayout.MaxHeight(360)); EditorGUILayout.BeginVertical(guiLayoutDarkColor); EditorGUILayout.LabelField("[QUEST STAGE : " + questObj.FindProperty("questStages").GetArrayElementAtIndex(selectedStage).FindPropertyRelative("index").intValue + "]", HeaderStyle, GUILayout.MaxWidth(400.0f)); EditorGUILayout.PropertyField(questObj.FindProperty("questStages").GetArrayElementAtIndex(selectedStage).FindPropertyRelative("description")); EditorGUILayout.BeginHorizontal(); EditorGUIUtility.labelWidth = 100; EditorGUILayout.PropertyField(questObj.FindProperty("questStages").GetArrayElementAtIndex(selectedStage).FindPropertyRelative("completeQuest")); EditorGUIUtility.labelWidth = 60; EditorGUILayout.PropertyField(questObj.FindProperty("questStages").GetArrayElementAtIndex(selectedStage).FindPropertyRelative("failQuest")); EditorGUIUtility.labelWidth = 110; EditorGUILayout.PropertyField(questObj.FindProperty("questStages").GetArrayElementAtIndex(selectedStage).FindPropertyRelative("displayLogEntry")); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); GUILayout.Space(15); var curResultScript = questObj.FindProperty("questStages").GetArrayElementAtIndex(selectedStage).FindPropertyRelative("resultScript"); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel("Stage Script:"); string resultScriptMenuValue = string.IsNullOrEmpty(curResultScript.stringValue) ? "-None-" : curResultScript.stringValue; if (GUILayout.Button(resultScriptMenuValue)) { // create the menu and add items to it GenericMenu menu = new GenericMenu(); menu.AddDisabledItem(new GUIContent("Quest Stages Scripts")); menu.AddSeparator(""); menu.AddItem(new GUIContent("None"), false, Callback, new ScriptElementData(curResultScript, "")); for (int i = 0; i < allQuestStagesScripts.Length; i++) { menu.AddItem(new GUIContent(allQuestStagesScripts[i].name), false, Callback, new ScriptElementData(curResultScript, allQuestStagesScripts[i].GetClass().Namespace + "." + allQuestStagesScripts[i].name)); } menu.ShowAsContext(); } EditorGUILayout.EndHorizontal(); GUILayout.Space(15); EditorGUILayout.BeginVertical(guiLayoutDarkColor); current = Event.current; EditorGUILayout.LabelField("QUEST STAGE CONDITIONS:", HeaderStyle); questStageConditionsScrollView = EditorGUILayout.BeginScrollView(questStageConditionsScrollView, true, true, GUILayout.Width(position.width - 230), GUILayout.Height(360)); Rect questStageConditionRectArea = new Rect(questStageConditionsScrollView.x, questStageConditionsScrollView.y, position.width, 400); var questStages = questObj.FindProperty("questStages").GetArrayElementAtIndex(selectedStage); for (int i = 0; i < questStages.FindPropertyRelative("stageConditions").arraySize; i++) { Rect currentConditionArea = EditorGUILayout.BeginHorizontal((selectedQuestStageConditionIndex == i) ? guiLayoutLightColor : guiLayoutDarkColor); EditorGUILayout.PropertyField(questStages.FindPropertyRelative("stageConditions").GetArrayElementAtIndex(i), GUILayout.Width(1500)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(10); if (currentConditionArea.Contains(current.mousePosition) && Event.current.type == EventType.MouseDown && Event.current.button == 0) { selectedQuestStageConditionIndex = i; Repaint(); } } // DROPDOWN TO CREATE NEW CONDITIONS if (questStageConditionRectArea.Contains(current.mousePosition) && current.type == EventType.ContextClick) { GenericMenu menu = new GenericMenu(); menu.AddDisabledItem(new GUIContent("Quest Stage Conditions")); menu.AddItem(new GUIContent("New"), false, CreateNewQuestStageCondition); menu.AddItem(new GUIContent("Delete Selected"), false, DeleteSelectedQuestStageCondition); menu.ShowAsContext(); current.Use(); } void CreateNewQuestStageCondition() { questStages.FindPropertyRelative("stageConditions").InsertArrayElementAtIndex(questStages.FindPropertyRelative("stageConditions").arraySize); selectedQuestStageConditionIndex = questStages.FindPropertyRelative("stageConditions").arraySize - 1; Repaint(); } void DeleteSelectedQuestStageCondition() { if (selectedQuestStageConditionIndex != -1) { questStages.FindPropertyRelative("stageConditions").DeleteArrayElementAtIndex(selectedQuestStageConditionIndex); selectedQuestStageConditionIndex = -1; Repaint(); } } EditorGUILayout.EndScrollView(); EditorGUILayout.BeginHorizontal("box", GUILayout.MaxWidth(150)); GUI.enabled = (selectedQuestStageConditionIndex != -1) ? true : false; GUI.enabled = (selectedQuestStageConditionIndex != -1 && selectedQuestStageConditionIndex != 0); if (GUILayout.Button("↑")) { GUI.FocusControl(null); questStages.FindPropertyRelative("stageConditions").MoveArrayElement(selectedQuestStageConditionIndex, selectedQuestStageConditionIndex - 1); selectedQuestStageConditionIndex = selectedQuestStageConditionIndex - 1; Repaint(); } GUI.enabled = (selectedQuestStageConditionIndex != -1 && selectedQuestStageConditionIndex != questStages.FindPropertyRelative("stageConditions").arraySize - 1); if (GUILayout.Button("↓")) { GUI.FocusControl(null); questStages.FindPropertyRelative("stageConditions").MoveArrayElement(selectedQuestStageConditionIndex, selectedQuestStageConditionIndex + 1); selectedQuestStageConditionIndex = selectedQuestStageConditionIndex + 1; Repaint(); } GUI.enabled = true; EditorGUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); EditorGUILayout.EndVertical(); EditorGUILayout.EndVertical(); } GUILayout.FlexibleSpace(); EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal(); GUILayout.Space(30); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("SAVE", ButtonStyle)) { questObj.ApplyModifiedProperties(); // Refresh database var AllQuestDatabaseFiles = GetAllInstances(); foreach (QuestsDatabaseFile file in AllQuestDatabaseFiles) file.fill(); this.Close(); } if (GUILayout.Button("CANCEL", ButtonStyle)) { this.Close(); } EditorGUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); #endregion break; case CurrentWindow.NPCs: break; case CurrentWindow.Dialogues: break; default: break; } } public static MonoScript[] GetScriptAssetsOfType() { MonoScript[] scripts = (MonoScript[])FindObjectsOfTypeIncludingAssets(typeof(MonoScript)); List result = new List(); foreach (MonoScript m in scripts) { if (m.GetClass() != null && m.GetClass().IsSubclassOf(typeof(T)) && m.GetType() != typeof(Shader)) { result.Add(m); } } return result.ToArray(); } public static List GetAllInstances() where T : QuestsDatabaseFile { string[] guids = AssetDatabase.FindAssets("t:" + typeof(T).Name); List a = new List(guids.Length); for (int i = 0; i < guids.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); a.Add(AssetDatabase.LoadAssetAtPath(path)); } return a; } } }