// ================================================================================================================ public static void Show(UniRPGBasicEventHandler onAccept, RPGSkill selectedSkill, int helper) { // make sure DB is loaded if (!UniRPGEditorGlobal.LoadDatabase()) return; // create window SkillSelectWiz window = EditorWindow.GetWindow<SkillSelectWiz>(true, "Select Skill", true); window.inited = false; window.selectedSkill = selectedSkill; window.helper = helper; window.OnAccept = onAccept; // show window window.ShowUtility(); }
void OnGUI() { if (!inited) Init(); UniRPGEdGui.UseSkin(); scroll = UniRPGEdGui.BeginScrollView(scroll); { if (UniRPGEditorGlobal.DB.Skills.Length > 0) { for (int i = 0; i < UniRPGEditorGlobal.DB.Skills.Length; i++) { Rect r = EditorGUILayout.BeginHorizontal(); { r.x = 3; r.width = 19; r.height = 19; GUI.DrawTexture(r, (UniRPGEditorGlobal.DB.Skills[i].icon[0] != null ? UniRPGEditorGlobal.DB.Skills[i].icon[0] : UniRPGEdGui.Texture_NoPreview)); GUILayout.Space(21); if (UniRPGEdGui.ToggleButton(selectedSkill == UniRPGEditorGlobal.DB.Skills[i], UniRPGEditorGlobal.DB.Skills[i].screenName, UniRPGEdGui.ButtonRightStyle, UniRPGEdGui.ButtonOnColor, GUILayout.Width(150))) { selectedSkill = UniRPGEditorGlobal.DB.Skills[i]; } } EditorGUILayout.EndHorizontal(); } } else { GUILayout.Label("No Skills are defined", UniRPGEdGui.WarningLabelStyle); } } UniRPGEdGui.EndScrollView(); UniRPGEdGui.DrawHorizontalLine(1, UniRPGEdGui.DividerColor, 0, 10); EditorGUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); if (selectedSkill == null) GUI.enabled = false; if (GUILayout.Button("Accept", UniRPGEdGui.ButtonStyle)) accepted = true; GUI.enabled = true; if (GUILayout.Button("Cancel", UniRPGEdGui.ButtonStyle)) this.Close(); GUILayout.FlexibleSpace(); } EditorGUILayout.EndHorizontal(); GUILayout.Space(10); }
private GameObject aoeTargetingMarker; // this is the instance of aoeTargetingMarkerPrefab , when used // ================================================================================================================ public void CopyTo(RPGSkill s) { s.id = this.id.Copy(); s.screenName = this.screenName; s.description = this.description; s.notes = this.notes; s.icon = new Texture2D[3] { this.icon[0], this.icon[1], this.icon[2] }; s.guiHelper = this.guiHelper; s.onUseMaxTargetDistance = this.onUseMaxTargetDistance; s.validTargetsMask = this.validTargetsMask; s.castTimeSetting = this.castTimeSetting; s.cooldownTimeSetting = this.cooldownTimeSetting; s.startCooldownAfterCast = this.startCooldownAfterCast; s.canBeInterrupted = this.canBeInterrupted; s.ownerCanInterrupt = this.ownerCanInterrupt; s.onUseActions = new List<Action>(0); GameObject g = s.gameObject; foreach (Action act in this.onUseActions) { Action newAct = (Action)g.AddComponent(act.GetType()); newAct.hideFlags = HideFlags.HideInInspector; act.CopyTo(newAct); s.onUseActions.Add(newAct); } s.rightActions = new List<Action>(0); foreach (Action act in this.rightActions) { Action newAct = (Action)g.AddComponent(act.GetType()); newAct.hideFlags = HideFlags.HideInInspector; act.CopyTo(newAct); s.rightActions.Add(newAct); } }
// ================================================================================================================ #region Init/Start public void Awake() { _tr = gameObject.transform; _character = gameObject.GetComponent<CharacterBase>(); InAOESelectMode = false; currSkill = null; nextSkill = null; autoSkill = null; nextSkillTarget = null; autoSkillTarget = null; nextSkillMaxDistance = 0f; }
/// <summary>called by actor class when a skill's execution has stopped</summary> public virtual void DonePerformingSkill(RPGSkill skill) { }
/// <summary> /// called by actor to find out if it is ok to execute the skill? /// a plugin might want to return false here if it is still /// turning the character to look at the skill's target /// </summary> public virtual bool CanPerformSkillNow(RPGSkill skill, Vector3 skillTargetLocation) { return true; }
// ================================================================================================================ #region Skills panel private void DrawSkills() { if (!gui.plrMoveSkills) UniRPGGlobal.GUIConsumedInput = true; if (ShowRightPopMenu >= 0) GUI.enabled = false; GUILayout.BeginArea(r[1], gui.skillPanelName, GUI.skin.window); { if (GUI.Button(new Rect(r[1].width - gui.WindowCloseButton.fixedWidth - GUI.skin.window.padding.right, GUI.skin.window.padding.top + GUI.skin.window.contentOffset.y, gui.WindowCloseButton.fixedWidth, gui.WindowCloseButton.fixedHeight), GUIContent.none, gui.WindowCloseButton)) { PlayButtonFX(); showSkills = false; } scroll[2] = GUILayout.BeginScrollView(scroll[2]); { for (int i = 0; i < UniRPGGlobal.Player.Actor.skills.Count; i++) { if (!string.IsNullOrEmpty(UniRPGGlobal.Player.Actor.skills[i].guiHelper)) continue; if (GUILayout.Button(new GUIContent(" " + UniRPGGlobal.Player.Actor.skills[i].screenName, UniRPGGlobal.Player.Actor.skills[i].icon[0] == null ? gui.txNoIcon : UniRPGGlobal.Player.Actor.skills[i].icon[0], i.ToString()), gui.ListButton)) { PlayButtonFX(); ShowRightPopMenu = i; } if (GUI.tooltip == i.ToString() && GUI.enabled) SetHoverSkill(UniRPGGlobal.Player.Actor.skills[i]); } } GUILayout.EndScrollView(); } GUILayout.EndArea(); if (!showOptions) GUI.enabled = true; int cnt = 2; if (popMenuHelperSkill != null) { cnt = gui.actionSlotsCount + 1; } if (ShowRightPopMenu >= 0 && popRectCalced) { GUILayout.BeginArea(rPopMenu, GUI.skin.box); { if (popMenuHelperSkill != null) { scroll[3] = GUILayout.BeginScrollView(scroll[3]); { if (GUILayout.Button("Cancel")) { PlayButtonFX(); popMenuHelperSkill = null; ShowRightPopMenu = -1; } for (int i = 0; i < gui.actionSlotsCount; i++) { if (GUILayout.Button("Slot " + (i + 1))) { PlayButtonFX(); UniRPGGlobal.Player.Actor.SetActionSlot(i, popMenuHelperSkill); popMenuHelperSkill = null; ShowRightPopMenu = -1; } } } GUILayout.EndScrollView(); } else { if (GUILayout.Button("Equip")) { PlayButtonFX(); popRectCalced = false; scroll[3] = Vector2.zero; popMenuHelperSkill = UniRPGGlobal.Player.Actor.skills[ShowRightPopMenu]; } if (GUILayout.Button("Cancel")) { PlayButtonFX(); popMenuHelperSkill = null; ShowRightPopMenu = -1; } } } GUILayout.EndArea(); } CalcPopMenuRect(cnt, ShowRightPopMenu, popMenuHelperSkill!=null); DrawHoverSkillInfo(); }
/// <summary> /// will queue the skill to be used as soon as current skill is done and/or queued skill is avail for use (cool down might be running) /// setAsAutoQueueSkill=true will cause the skill to be queued and performed as long as target is valid or stopped by an action by the player /// </summary> public void UseSkill(RPGSkill skill, GameObject target, bool setAsAutoQueueSkill) { if (skill.targetMech == RPGSkill.TargetingMechanic.AroundLocation) { // the player must first select a spot with the mouse InAOESelectMode = true; AOESkill = skill; nextSkill = null; autoSkill = null; nextSkillTarget = null; autoSkillTarget = null; } else if ((skill.targetMech == RPGSkill.TargetingMechanic.SingleTarget || skill.targetMech == RPGSkill.TargetingMechanic.AroundTargeted) && skill.validTargetsMask != 0 && ((int)UniRPGGlobal.Target.Self & (int)skill.validTargetsMask) == 0) { if (skill.IsValidTarget(target)) { if (setAsAutoQueueSkill) { autoSkill = skill; autoSkillTarget = target; } nextSkill = skill; nextSkillTarget = target; if (target == null) nextSkillLocation = transform.position; else nextSkillLocation = target.transform.position; nextSkillMaxDistance = nextSkill.onUseMaxTargetDistance; nextSkillMaxDistance = nextSkillMaxDistance * nextSkillMaxDistance; // cause I'm using sqrMagnitude for distance check } else { nextSkill = null; autoSkill = null; nextSkillTarget = null; autoSkillTarget = null; InAOESelectMode = false; AOESkill = null; } } else { if (setAsAutoQueueSkill) { autoSkill = skill; autoSkillTarget = target; } nextSkill = skill; if (skill.targetMech == RPGSkill.TargetingMechanic.AroundOwner) { nextSkillTarget = null; nextSkillLocation = transform.position; //UniRPGGlobal.Player.transform.position; } else { nextSkillTarget = target; nextSkillLocation = Vector3.zero; } if (skill.validTargetsMask == 0 || ((int)UniRPGGlobal.Target.Self & (int)skill.validTargetsMask) != 0) { nextSkillTarget = ((int)UniRPGGlobal.Target.Self & (int)skill.validTargetsMask) != 0 ? gameObject : null; nextSkillLocation = transform.position; nextSkillMaxDistance = 0; } else { nextSkillMaxDistance = nextSkill.onUseMaxTargetDistance; nextSkillMaxDistance = nextSkillMaxDistance * nextSkillMaxDistance; // cause I'm using sqrMagnitude for distance check } } }
private void CreateSkill(System.Object sender) { TextInputWiz wiz = sender as TextInputWiz; string name = wiz.text; wiz.Close(); if (string.IsNullOrEmpty(name)) name = "Skill"; UniRPGEditorGlobal.CheckDatabasePath(UniRPGEditorGlobal.DB_DATA_PATH, UniRPGEditorGlobal.DB_SKILLS_PATH); string fn = UniRPGEditorGlobal.DB_SKILLS_PATH + name + ".prefab"; if (UniRPGEdUtil.RelativeFileExist(fn)) fn = AssetDatabase.GenerateUniqueAssetPath(fn); Object prefab = PrefabUtility.CreateEmptyPrefab(fn); GameObject go = new GameObject(name); // create temp object in scene go.AddComponent<RPGSkill>(); GameObject toRef = PrefabUtility.ReplacePrefab(go, prefab); // save prefab GameObject.DestroyImmediate(go); // clear temp object from scene curr = toRef.GetComponent<RPGSkill>(); curr.screenName = name; ed.db.skillPrefabs.Add(toRef); EditorUtility.SetDirty(curr); EditorUtility.SetDirty(ed.db); AssetDatabase.SaveAssets(); ed.Repaint(); }
// ================================================================================================================ private void LeftPanel() { EditorGUILayout.BeginVertical(GUILayout.Width(DatabaseEditor.LeftPanelWidth)); GUILayout.Space(5); // ------------------------------------------------------------- // the add button EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); if (GUILayout.Button(new GUIContent("Add Skill", UniRPGEdGui.Icon_Plus), EditorStyles.miniButtonLeft)) { GUI.FocusControl(""); TextInputWiz.Show("New Skill", "Enter name for new skill", "", CreateSkill); } if (curr == null) GUI.enabled = false; if (GUILayout.Button(new GUIContent(UniRPGEdGui.Icon_Copy, "Copy"), EditorStyles.miniButtonMid)) { GUI.FocusControl(""); CreateSkillCopy(); } GUI.enabled = true; } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); scroll[0] = UniRPGEdGui.BeginScrollView(scroll[0], GUILayout.Width(DatabaseEditor.LeftPanelWidth)); { if (ed.db.Skills.Length > 0) { foreach (RPGSkill skill in ed.db.Skills) { if (skill == null) continue; Rect r = EditorGUILayout.BeginHorizontal(GUILayout.Width(DatabaseEditor.LeftPanelWidth - 20), GUILayout.ExpandWidth(false)); { r.x = 3; r.width = 19; r.height = 19; GUI.DrawTexture(r, (skill.icon[0] != null ? skill.icon[0] : UniRPGEdGui.Texture_NoPreview)); GUILayout.Space(21); if (UniRPGEdGui.ToggleButton(curr == skill, skill.screenName, UniRPGEdGui.ButtonMidStyle, GUILayout.Width(140), GUILayout.ExpandWidth(false))) { curr = skill; GUI.FocusControl(""); } if (GUILayout.Button("X", UniRPGEdGui.ButtonRightStyle, GUILayout.Width(20))) { del = skill; } } EditorGUILayout.EndHorizontal(); } } else { GUILayout.Label("No Skills are defined", UniRPGEdGui.WarningLabelStyle); } } UniRPGEdGui.EndScrollView(); // ------------------------------------------------------------- GUILayout.Space(3); EditorGUILayout.EndVertical(); if (del != null) { if (curr == del) curr = null; ed.db.skillPrefabs.Remove(del.gameObject); EditorUtility.SetDirty(ed.db); AssetDatabase.SaveAssets(); string path = AssetDatabase.GetAssetPath(del.gameObject); AssetDatabase.DeleteAsset(path); AssetDatabase.Refresh(); del = null; } }
private void UpdateHostileAI() { // try to use the primary skill on the player (it is most likely an attack skill) if (_actor.skills.Count == 0 || TargetedCharacter == null) return; if (_actor.IsPerformingSkill) return; if (skill != null && false == UniRPGGlobal.Player.canBeTargeted || actorType != UniRPGGlobal.ActorType.Hostile) { // player became non-targetable (or the NPC is not hostile any longer) skill = null; ClearTarget(); _actor.ClearQueuedSkill(); return; } chaseTimer -= Time.deltaTime; if (chaseTimer <= 0.0f) { skill = null; ClearTarget(); _actor.ClearQueuedSkill(); return; } // if it has a skill 2 when 1st check if that skill can't rather be used skill = null; if (_actor.skills.Count > 1) { if (_actor.skills[1]) { float distance = Vector3.Distance(UniRPGGlobal.Player.transform.position, _tr.position); if (distance >= detectionRadius * chooseSkill2DistanceMod) skill = _actor.skills[1]; } } if (skill == null) skill = _actor.skills[0]; if (skill) { if (false == UniRPGGlobal.Player.canBeTargeted || actorType != UniRPGGlobal.ActorType.Hostile) { // player became non-targetable (or the NPC is not hostile any longer) ClearTarget(); _actor.ClearQueuedSkill(); return; } if (skill.IsReady) { int r = CheckIfCanPerform(skill, TargetedCharacter.transform.position); if (r == 0) { chaseTimer = chaseTimeout; navi.Stop(); _actor.UseSkill(skill, TargetedCharacter.gameObject, false); navi.LookAt(TargetedCharacter.transform.position); } else { scanTimer -= Time.deltaTime; if (navi.IsMovingOrPathing() == false || scanTimer <= 0f) { scanTimer = 1f; // these updates can only happen in intervals. Do not want MoveTo() called continuously if (r == 1) { // move closer to target navi.MoveTo(TargetedCharacter.transform.position, chaseSpeed, turnSpeed); } else { // at least look in correct direction navi.LookAt(TargetedCharacter.transform.position); } } } } } }
/// <summary>remove queued skill, only if it has the mentioned target</summary> public void ClearQueuedSkill(GameObject ifTargeted) { // only untarget if this target if (nextSkillTarget != ifTargeted) return; CancelAOETargeting(); nextSkill = null; autoSkill = null; nextSkillTarget = null; autoSkillTarget = null; }
/// <summary>Put the Skill in the slot. skill must already be instantiated</summary> public bool SetActionSlot(int slot, RPGSkill skill) { if (skill == null) return false; if (slot < 0 || slot >= actionSlots.Count) return false; actionSlots[slot].SetAsSkill(skill); // clear any other slot that has same skill in it for (int i = 0; i < actionSlots.Count; i++) { if (actionSlots[i].Skill == null) continue; if (i != slot && actionSlots[i].Skill.id == skill.id) ClearActionSlot(i); } return true; }
/// <summary>Get instance of the skill from skill list. return null if actor does not have the skill</summary> public RPGSkill GetSkill(RPGSkill skill) { if (skill) return GetSkill(skill.id); return null; }
/// <summary>return true of the actor has the mentioned skill in skill list</summary> public bool HasSKill(RPGSkill skill) { if (skill) return HasSkill(skill.id); return false; }
/// <summary>will remove the skill from the list of available skills and from any slot it is mounted and then destroy the instance of the skill</summary> public void RemoveSkill(RPGSkill skill) { if (skill) RemoveSkill(skill.id); }
/// <summary>Cancel queued skill and target. useful for AI to cancel any targeting when the player is out of range</summary> public void ClearQueuedSkill() { CancelAOETargeting(); nextSkill = null; autoSkill = null; nextSkillTarget = null; autoSkillTarget = null; }
// 0: yes, 1:too far, 2:turn private int CheckIfCanPerform(RPGSkill skill, Vector3 skillTargetLocation) { Vector3 d = (skillTargetLocation - _tr.position); float m = d.magnitude; if (m > skill.onUseMaxTargetDistance) return 1; // too far d = d.normalized; d.y = _tr.forward.y; if (Vector3.Dot(_tr.forward, d) > 0.8f) return 0; // all good return 2; // need to turn }
// ============================================================================================================ /// <summary>called by actor class when a skill is about to be executed</summary> public override void AboutToPerformSkill(RPGSkill skill) { navi.Stop(); ani.ForceIdle(); IsPerformingSkill = true; }
/// <summary>called by actor class when a skill's execution has stopped</summary> public override void DonePerformingSkill(RPGSkill skill) { IsPerformingSkill = false; }
/// <summary> /// called by actor to find out if it is ok to execute the skill? /// a plugin might want to return false here if it is still /// turning the character to look at the skill's target /// </summary> public override bool CanPerformSkillNow(RPGSkill skill, Vector3 skillTargetLocation) { return true; }
private void CreateSkillCopy() { string name = curr.name; if (string.IsNullOrEmpty(name)) name = "Skill"; UniRPGEditorGlobal.CheckDatabasePath(UniRPGEditorGlobal.DB_DATA_PATH, UniRPGEditorGlobal.DB_SKILLS_PATH); string fn = UniRPGEditorGlobal.DB_SKILLS_PATH + name + ".prefab"; if (UniRPGEdUtil.RelativeFileExist(fn)) fn = AssetDatabase.GenerateUniqueAssetPath(fn); Object prefab = PrefabUtility.CreateEmptyPrefab(fn); GameObject go = new GameObject(name); // create temp object in scene go.AddComponent<RPGSkill>(); GameObject toRef = PrefabUtility.ReplacePrefab(go, prefab); // save prefab GameObject.DestroyImmediate(go); // clear temp object from scene RPGSkill sk = toRef.GetComponent<RPGSkill>(); sk.screenName = name; curr.CopyTo(sk); sk.id = UniRPG.GUID.Create(); curr = sk; ed.db.skillPrefabs.Add(toRef); EditorUtility.SetDirty(curr); EditorUtility.SetDirty(ed.db); AssetDatabase.SaveAssets(); }
/// <summary>checks if the character can use the skill. does it need a target and is target in range?</summary> public virtual bool IsSkillTargetInRange(RPGSkill s) { if (s == null) return false; if (s.targetMech == RPGSkill.TargetingMechanic.AroundOwner || s.targetMech == RPGSkill.TargetingMechanic.AroundLocation) return true; if (s.validTargetsMask == 0) return true; // "Nothing" if (s.validTargetsMask == UniRPGGlobal.Target.Self) return true; if (((int)UniRPGGlobal.Target.Self & (int)s.validTargetsMask) != 0) return true; if (s.validTargetsMask == 0 && TargetInteract == null) return true; if (TargetInteract == null) return false; if (s.IsValidTarget(TargetInteract.gameObject)) { return (Mathf.Abs((TargetInteract.transform.position - _tr.position).sqrMagnitude) <= (s.onUseMaxTargetDistance * s.onUseMaxTargetDistance)); } return false; }
public override bool CanPerformSkillNow(RPGSkill skill, Vector3 skillTargetLocation) { if (skillTargetLocation == _tr.position) return true; // standing on top of target location if (IsLookingAt(skillTargetLocation)) return true; else navi.LookAt(skillTargetLocation); return false; }
/// <summary>called by actor class when a skill is about to be executed</summary> public virtual void AboutToPerformSkill(RPGSkill skill) { }
private void SetHoverSkill(RPGSkill skill) { if (skill == null) { if (Event.current.type == EventType.repaint && !hoverDetected) { hoverSkill = null; } } else { if (hoverSkill == null) hoverSkip = true; hoverDetected = true; hoverSkill = skill; GUI.tooltip = ""; } }
public void CancelAOETargeting() { if (AOESkill != null) { AOESkill.HideAOEMarker(); } AOESkill = null; InAOESelectMode = false; }