示例#1
0
//     public static List<IObject> GetEnemyByAOI(Skill skillObj)
//     {
//         if (skillObj == null)
//         {
//             return null;
//         }
//
//         return GetEnemyByAOI(skillObj.mSelfObj, (SkillRangeType)1, 90.0f, skillObj.mSkillProperty.mSkillRange, 0.0f);
//     }

    /// <summary>
    /// 根据AOI获取可攻击范围内列表
    /// </summary>
    /// <param name="self"></param>
    /// <param name="type"></param>
    /// <param name="width"></param>
    /// <param name="maxDistance"></param>
    /// <param name="minDistance"></param>
    public static List <IObject> GetEnemyByAOI(IObject self, SkillRangeType type, float maxDistance, float width, float minDistance = 0.0f)
    {
        if (self == null || self.mAOIList == null)
        {
            return(null);
        }

        List <IObject> list = new List <IObject>();

        if (type == SkillRangeType.SkillRangeType_Self)
        {
            list.Add(self);
        }
        else if (type == SkillRangeType.SkillRangeType_Single)
        {
            IObject target       = null;
            float   tempDistance = float.MaxValue;
            for (int i = 0; i < self.mAOIList.Count; ++i)
            {
                IObject obj = self.mAOIList[i];
                if (obj == null)
                {
                    continue;
                }

                float distance = UtilTools.Vec2Distance(self, obj);
                if (distance <= maxDistance && distance < tempDistance)
                {
                    tempDistance = distance;
                    target       = obj;
                }
            }

            list.Add(target);
        }
        else
        {
            for (int i = 0; i < self.mAOIList.Count; ++i)
            {
                IObject obj = self.mAOIList[i];

                if (!IsObjectInRange(self, obj, maxDistance, type, width, minDistance))
                {
                    continue;
                }

                list.Add(obj);
            }
        }

        return(list);
    }
示例#2
0
 public Skill()
 {
     Id              = 1;
     NameLang        = 10000;
     DescriptionLang = 10001;
     Image           = Resources.Load("Skill/LinerSword", typeof(Sprite)) as Sprite;
     HotKeyIndex     = 0;
     RangeType       = SkillRangeType.Line;
     Range           = 3;
     EffectType      = SkillEffectType.PhysicalDamage;
     CD              = 2;
     Power           = 10000;
 }
示例#3
0
    public Vector2Int[] GetRangeWithRangeType(Vector2Int origin, int maxLength, SkillRangeType rangeType, int beginDistance = 1)
    {
        switch (rangeType)
        {
        case SkillRangeType.Circle:
            return(GetCircleRange(origin, maxLength));

        case SkillRangeType.Square:
            return(null);

        case SkillRangeType.FourRay:
            return(GetFourRayRange(origin, maxLength, beginDistance));
        }
        return(null);
    }
示例#4
0
    /// <summary>
    /// 计算技能作用的对象;
    /// </summary>
    /// <returns><c>true</c>, if range sector was set, <c>false</c> otherwise.</returns>
    public List <Transform> GetTargets(Vector3 center, Vector3 direction, int skillId)
    {
        SkillRangeType my_SkillRangeType = SkillRangeType.SkillRangeType_Unknown;

        switch (my_SkillRangeType)
        {
        case SkillRangeType.SkillRangeType_Unknown:
            break;

        case SkillRangeType.SkillRangeType_SelfSector:
            break;

        case SkillRangeType.SkillRangeType_SelfLine:
            break;

        case SkillRangeType.SkillRangeType_SelfRound:
            break;

        default:
            break;
        }
        return(null);
    }
示例#5
0
    /// <summary>
    /// 判断对象是否在一个对象的范围内
    /// </summary>
    /// <param name="self"></param>
    /// <param name="target"></param>
    /// <param name="maxDistance"></param>
    /// <param name="width"></param>
    /// <param name="rangeType"></param>
    /// <returns></returns>
    public static bool IsObjectInRange(IObject self, IObject target, float maxDistance, SkillRangeType rangeType, float width, float minDistance = 0.0f)
    {
        if (self == null || target == null)
        {
            return(false);
        }

        if (Mathf.Abs(maxDistance) < 0.01)
        {
            return(false);
        }

        if (rangeType >= SkillRangeType.SkillRangeType_MaxCount ||
            rangeType <= SkillRangeType.SkillRangeType_Unknown)
        {
            return(false);
        }

        Vector3    selfPosition   = self.mPosition;
        Vector3    selfForward    = self.mGameObject.transform.forward;
        Quaternion r              = self.mGameObject.transform.rotation;
        Vector3    targetPosition = target.mPosition;
        Vector3    direction      = (targetPosition - selfPosition).normalized;

        bool isIn = false;

        switch (rangeType)
        {
        case SkillRangeType.SkillRangeType_Single:

            break;

        case SkillRangeType.SkillRangeType_SelfLine:
//                Vector3 left = selfPosition + (r * Vector3.left) * width / 2;
//                Vector3 right = selfPosition + (r * Vector3.right) * width / 2;
//                Vector3 leftEnd = (left + (r * Vector3.forward) * maxDistance);
//                Vector3 rightEnd = (right + (r * Vector3.forward) * maxDistance);
//				//Debug.Log("left = "+left);
//				//Debug.Log("right = "+right);
//				//Debug.Log("leftEnd = "+leftEnd);
//				//Debug.Log("rightEnd = "+rightEnd);
//			singletonNpcTest.GetSingletonNpcTest().svv[0] = left;
//			singletonNpcTest.GetSingletonNpcTest().svv[1] = right;
//			singletonNpcTest.GetSingletonNpcTest().svv[2] = leftEnd;
//			singletonNpcTest.GetSingletonNpcTest().svv[3] = rightEnd;
//
//
//                if (IsInRect(targetPosition, leftEnd, rightEnd, right, left))
//                {
//				//Debug.Log("============true=================");
//                    isIn = true;
//                }

            if (AttackRangeDefine.IsLine(target.mPosition, self.mPosition, self.mGameObject.transform.forward, width, maxDistance))
            {
                isIn = true;
            }
            else
            {
                isIn = false;
            }
            break;

        // 此处width为扇形夹角
        case SkillRangeType.SkillRangeType_SelfSector:
            Vector3 f0 = selfPosition + (r * Vector3.forward) * maxDistance;

            Quaternion r0 = Quaternion.Euler(r.eulerAngles.x, r.eulerAngles.y - width / 2, r.eulerAngles.z);
            Quaternion r1 = Quaternion.Euler(r.eulerAngles.x, r.eulerAngles.y + width / 2, r.eulerAngles.z);

            Vector3 f1 = selfPosition + (r0 * Vector3.forward) * maxDistance;
            Vector3 f2 = selfPosition + (r1 * Vector3.forward) * maxDistance;

            if (IsInTriangle(targetPosition, selfPosition, f1, f0) || IsInTriangle(targetPosition, selfPosition, f2, f0))
            {
                isIn = true;
            }
            break;

        case SkillRangeType.SkillRangeType_SelfRound:
            if (Vector3.Distance(selfPosition, targetPosition) <= maxDistance &&
                Vector3.Distance(selfPosition, targetPosition) > minDistance)
            {
                isIn = true;
            }
            break;

        default:
            break;
        }

        return(isIn);
    }
示例#6
0
    public static DamageHandler CalculateDamage(SkillCast skill, IFieldActor source, IFieldActor target, double luckCoefficient)
    {
        // TODO: get accuracyWeakness from enemy stats from enemy buff. new stat recommended
        const double AccuracyWeakness = 0;
        double       hitRate          = (source.Stats[StatAttribute.Accuracy].Total + AccuracyWeakness) / Math.Max(target.Stats[StatAttribute.Evasion].Total, 0.1);

        if (Random.Shared.NextDouble() > hitRate)
        {
            return(new(source, target, 0, HitType.Miss)); // we missed
        }

        bool isCrit = skill.IsGuaranteedCrit() || RollCrit(source, target, luckCoefficient);

        double finalCritDamage = 1;

        if (isCrit)
        {
            // TODO: get critResist from enemy stats from enemy buff. new stat recommended
            const double CritResist = 1;
            double       critDamage = 1000 + source.Stats[StatAttribute.CritDamage].Total;
            finalCritDamage = CritResist * ((critDamage / 1000) - 1) + 1;
        }

        double damageBonus = 1 + FetchMultiplier(source.Stats, StatAttribute.TotalDamage);

        damageBonus *= finalCritDamage;

        switch (skill.GetElement())
        {
        case Element.Fire:
            damageBonus += FetchMultiplier(source.Stats, StatAttribute.FireDamage);
            break;

        case Element.Ice:
            damageBonus += FetchMultiplier(source.Stats, StatAttribute.IceDamage);
            break;

        case Element.Electric:
            damageBonus += FetchMultiplier(source.Stats, StatAttribute.ElectricDamage);
            break;

        case Element.Holy:
            damageBonus += FetchMultiplier(source.Stats, StatAttribute.HolyDamage);
            break;

        case Element.Dark:
            damageBonus += FetchMultiplier(source.Stats, StatAttribute.DarkDamage);
            break;

        case Element.Poison:
            damageBonus += FetchMultiplier(source.Stats, StatAttribute.PoisonDamage);
            break;
        }

        SkillRangeType rangeType = skill.GetRangeType();

        if (rangeType != SkillRangeType.Special)
        {
            damageBonus += FetchMultiplier(source.Stats, rangeType == SkillRangeType.Melee ? StatAttribute.MeleeDamage : StatAttribute.RangedDamage);
        }

        bool isBoss = false;

        if (target is INpc npc)
        {
            isBoss = npc.Value.IsBoss();
        }

        damageBonus += isBoss ? FetchMultiplier(source.Stats, StatAttribute.BossDamage) : 0;

        // TODO: properly fetch enemy attack speed weakness from enemy buff. new stat recommended
        const double AttackSpeedWeakness = 0;

        damageBonus += AttackSpeedWeakness * FetchMultiplier(source.Stats, StatAttribute.AttackSpeed);

        double damageMultiplier = damageBonus * skill.GetDamageRate();

        // TODO: properly fetch enemy pierce resistance from enemy buff. new stat recommended
        const double EnemyPierceResistance = 1;

        double defensePierce = 1 - Math.Min(0.3, EnemyPierceResistance * FetchMultiplier(source.Stats, StatAttribute.Pierce));

        damageMultiplier *= 1 / (Math.Max(target.Stats[StatAttribute.Defense].Total, 1) * defensePierce);

        bool          isPhysical     = skill.GetSkillDamageType() == DamageType.Physical;
        StatAttribute resistanceStat = isPhysical ? StatAttribute.PhysicalRes : StatAttribute.MagicRes;
        StatAttribute attackStat     = isPhysical ? StatAttribute.PhysicalAtk : StatAttribute.MagicAtk;
        StatAttribute piercingStat   = isPhysical ? StatAttribute.PhysicalPiercing : StatAttribute.MagicPiercing;

        double targetRes  = target.Stats[resistanceStat].Total;
        double attackType = source.Stats[attackStat].Total;
        double resPierce  = FetchMultiplier(source.Stats, piercingStat);
        double resistance = (1500.0 - Math.Max(0, targetRes - 1500 * resPierce)) / 1500;

        // does this need to be divided by anything at all to account for raw physical attack?
        damageMultiplier *= attackType * resistance;

        // TODO: apply special standalone multipliers like Spicy Maple Noodles buff? it seems to have had it's own multiplier. new stat recommended
        const double FinalDamageMultiplier = 1;

        damageMultiplier *= FinalDamageMultiplier;

        double attackDamage = 300;

        if (source is IFieldActor <Player> player)
        {
            double bonusAttack = player.Stats[StatAttribute.BonusAtk].Total + 0.4 * player.Stats[StatAttribute.PetBonusAtk].Total;

            // TODO: properly fetch enemy bonus attack weakness from enemy buff. new stat recommended
            const double BonusAttackWeakness = 1;

            double minDamage = player.Stats[StatAttribute.MinWeaponAtk].Total + BonusAttackWeakness * bonusAttack;
            double maxDamage = player.Stats[StatAttribute.MaxWeaponAtk].Total + BonusAttackWeakness * bonusAttack;

            attackDamage = minDamage + (maxDamage - minDamage) * Random.Shared.NextDouble();
        }

        attackDamage *= damageMultiplier;

        return(new(source, target, Math.Max(1, attackDamage), isCrit ? HitType.Critical : HitType.Normal));
    }
示例#7
0
    protected override List <SkillMetadata> Parse()
    {
        List <SkillMetadata> skillList = new();

        foreach (PackFileEntry entry in Resources.XmlReader.Files)
        {
            // Parsing Skills
            if (entry.Name.StartsWith("skill"))
            {
                XmlDocument document  = Resources.XmlReader.GetXmlDocument(entry);
                XmlNode     ui        = document.SelectSingleNode("/ms2/basic/ui");
                XmlNode     kinds     = document.SelectSingleNode("/ms2/basic/kinds");
                XmlNode     stateAttr = document.SelectSingleNode("/ms2/basic/stateAttr");
                XmlNodeList levels    = document.SelectNodes("/ms2/level");

                int            skillId         = int.Parse(Path.GetFileNameWithoutExtension(entry.Name));
                string         skillState      = kinds.Attributes["state"]?.Value ?? "";
                byte           skillAttackType = byte.Parse(ui.Attributes["attackType"]?.Value ?? "0");
                SkillType      skillType       = (SkillType)byte.Parse(kinds.Attributes["type"].Value);
                SkillSubType   skillSubType    = (SkillSubType)byte.Parse(kinds.Attributes["subType"]?.Value ?? "0");
                SkillRangeType skillRangeType  = (SkillRangeType)byte.Parse(kinds.Attributes["rangeType"]?.Value ?? "0");
                byte           skillElement    = byte.Parse(kinds.Attributes["element"].Value);
                byte           skillSuperArmor = byte.Parse(stateAttr.Attributes["superArmor"].Value);
                bool           skillRecovery   = int.Parse(kinds.Attributes["spRecoverySkill"]?.Value ?? "0") == 1;

                List <SkillLevel> skillLevels = new();
                foreach (XmlNode level in levels)
                {
                    // Getting all skills level
                    string feature    = level.Attributes["feature"]?.Value ?? "";
                    int    levelValue = int.Parse(level.Attributes["value"].Value ?? "0");
                    // We prevent duplicates levels from older balances.
                    if (skillLevels.Exists(x => x.Level == levelValue))
                    {
                        continue;
                    }

                    List <SkillMotion> skillMotions = new();
                    foreach (XmlNode motionNode in level.SelectNodes("motion"))
                    {
                        string sequenceName = motionNode.SelectSingleNode("motionProperty")?.Attributes["sequenceName"].Value ?? "";
                        string motionEffect = motionNode.SelectSingleNode("motionProperty")?.Attributes["motionEffect"].Value ?? "";

                        List <SkillAttack> skillAttacks = new();
                        foreach (XmlNode attackNode in motionNode.SelectNodes("attack"))
                        {
                            // TODO: Parse other properties like: pause, arrow
                            DamageProperty damageProperty = ParseDamageProperty(attackNode);
                            RangeProperty  rangeProperty  = ParseRangeProperty(attackNode);

                            byte  attackPoint     = byte.Parse(Regex.Match(attackNode.Attributes["point"]?.Value, @"\d").Value);
                            short targetCount     = short.Parse(attackNode.Attributes["targetCount"].Value);
                            long  magicPathId     = long.Parse(attackNode.Attributes["magicPathID"]?.Value ?? "0");
                            long  cubeMagicPathId = long.Parse(attackNode.Attributes["cubeMagicPathID"]?.Value ?? "0");

                            List <SkillCondition> skillConditions = new();
                            foreach (XmlNode conditionNode in attackNode.SelectNodes("conditionSkill"))
                            {
                                int   conditionSkillId    = int.Parse(conditionNode.Attributes["skillID"]?.Value ?? "0");
                                short conditionSkillLevel = short.Parse(conditionNode.Attributes["level"]?.Value ?? "0");
                                bool  splash          = conditionNode.Attributes["splash"]?.Value == "1";
                                byte  target          = byte.Parse(conditionNode.Attributes["skillTarget"].Value ?? "0");
                                byte  owner           = byte.Parse(conditionNode.Attributes["skillOwner"]?.Value ?? "0");
                                bool  immediateActive = conditionNode.Attributes["immediateActive"]?.Value == "1";
                                short fireCount       = short.Parse(conditionNode.Attributes["fireCount"].Value ?? "0");
                                int   interval        = int.Parse(conditionNode.Attributes["interval"].Value ?? "0");

                                skillConditions.Add(new(conditionSkillId, conditionSkillLevel, splash, target, owner, fireCount, interval, immediateActive));
                            }

                            skillAttacks.Add(new(attackPoint, targetCount, magicPathId, cubeMagicPathId, rangeProperty, skillConditions, damageProperty));
                        }

                        skillMotions.Add(new(sequenceName, motionEffect, skillAttacks));
                    }

                    SkillUpgrade skillUpgrade = ParseSkillUpgrade(level);
                    (int spirit, int stamina) = ParseConsume(level);

                    skillLevels.Add(new(levelValue, spirit, stamina, feature, skillMotions, skillUpgrade));
                }

                skillList.Add(new(skillId, skillLevels, skillState, skillAttackType, skillType, skillSubType, skillElement, skillSuperArmor, skillRecovery, skillRangeType));
            }

            // Parsing SubSkills
            if (entry.Name.StartsWith("table/job"))
            {
                XmlDocument document = Resources.XmlReader.GetXmlDocument(entry);
                XmlNodeList jobs     = document.SelectNodes("/ms2/job");
                foreach (XmlNode job in jobs)
                {
                    // Grabs all the skills and them the jobCode.
                    XmlNodeList skills  = job.SelectNodes("skills/skill");
                    int         jobCode = int.Parse(job.Attributes["code"].Value);
                    foreach (XmlNode skill in skills)
                    {
                        int   id       = int.Parse(skill.Attributes["main"].Value);
                        short maxLevel = short.Parse(skill.Attributes["maxLevel"]?.Value ?? "1");
                        skillList.Find(x => x.SkillId == id).Job      = jobCode;
                        skillList.Find(x => x.SkillId == id).MaxLevel = maxLevel;

                        // If it has subSkill, add as well.
                        if (skill.Attributes["sub"] == null)
                        {
                            continue;
                        }

                        int[] sub = skill.Attributes["sub"].Value.SplitAndParseToInt(',').ToArray();
                        skillList.Find(x => x.SkillId == id).SubSkills = sub;
                        foreach (int subSkillId in sub)
                        {
                            SkillMetadata subSkill = skillList.FirstOrDefault(x => x.SkillId == subSkillId);
                            if (subSkill is null)
                            {
                                continue;
                            }

                            subSkill.Job = jobCode;
                        }
                    }
                }
            }
        }

        // Parsing Additional Data
        foreach (PackFileEntry entry in Resources.XmlReader.Files)
        {
            if (!entry.Name.StartsWith("additionaleffect"))
            {
                continue;
            }

            XmlDocument document   = Resources.XmlReader.GetXmlDocument(entry);
            XmlNodeList levelNodes = document.SelectNodes("/ms2/level");
            int         skillId    = int.Parse(Path.GetFileNameWithoutExtension(entry.Name));

            SkillMetadata skill = skillList.FirstOrDefault(x => x.SkillId == skillId);
            if (skill is null)
            {
                continue;
            }

            foreach (XmlNode levelNode in levelNodes)
            {
                int        currentLevel = int.Parse(levelNode.SelectSingleNode("BasicProperty").Attributes["level"]?.Value ?? "0");
                SkillLevel skillLevel   = skill.SkillLevels.FirstOrDefault(x => x.Level == currentLevel);
                if (skillLevel is null)
                {
                    continue;
                }

                skillLevel.SkillAdditionalData = ParseSkillData(levelNode);
            }
        }

        return(skillList);
    }
示例#8
0
    public bool LoadFromLua(LuaTable skill)
    {
        if (skill["DisType"] == null || skill["DisType"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("DisType of Skill is invalid." + skill["DisType"]);
            return(false);
        }
        int type = Convert.ToInt32((double)skill["DisType"]);

        m_disType = (SkillDisType)type;

        if (skill["RangeType"] == null || skill["RangeType"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("RangeType of Skill is invalid.");
            return(false);
        }
        type        = Convert.ToInt32((double)skill["RangeType"]);
        m_rangeType = (SkillRangeType)type;

        if (skill["HurtType"] == null || skill["HurtType"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("HurtType of Skill is invalid.");
            return(false);
        }
        type       = Convert.ToInt32((double)skill["HurtType"]);
        m_hurtType = (SkillHurtType)type;

        if (skill["CDGroup"] == null || skill["CDGroup"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("CDGroup of Skill is invalid.");
            return(false);
        }
        int id = Convert.ToInt32((double)skill["CDGroup"]);

        m_nCDGroup = id;

        if (skill["Damage"] == null || skill["Damage"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("Damage of Skill is invalid.");
            return(false);
        }
        int damage = Convert.ToInt32((double)skill["Damage"]);

        m_nDamage = damage;

        if (skill["CostSP"] == null || skill["CostSP"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("CostSP of Skill is invalid.");
            return(false);
        }
        int costSP = Convert.ToInt32((double)skill["CostSP"]);

        m_nCostSP = costSP;

        string animName1 = (string)skill["animation"];

        if (animName1 != null && animName1 != "")
        {
            m_hash1 = Animator.StringToHash(animName1);
        }

        string animName2 = (string)skill["animation"];

        if (animName2 != null && animName2 != "")
        {
            m_hash2 = Animator.StringToHash(animName2);
        }

        if (skill["CheckType"] == null || skill["CheckType"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("CheckType of Skill is invalid.");
            return(false);
        }
        type        = Convert.ToInt32((double)skill["CheckType"]);
        m_checkType = (CStateType)type;

        if (skill["AfterType"] == null || skill["AfterType"].GetType().ToString() != "System.Double")
        {
            Debug.LogError("AfterType of Skill is invalid.");
            return(false);
        }
        type        = Convert.ToInt32((double)skill["AfterType"]);
        m_afterType = (CStateType)type;

        m_timer = m_life.GetCDTimerById(m_nCDGroup);
        if (m_timer == null)
        {
            Debug.LogError("Failed to LoadFromFile. CDTimer doesn't exist.");
            return(false);
        }

        return(true);
    }