Beispiel #1
0
        /// <summary>
        /// Gets the melee damages inflicted by an attacker to a defender.
        /// </summary>
        /// <returns><see cref="AttackResult"/></returns>
        public AttackResult OnDamage()
        {
            var attackResult = new AttackResult
            {
                Flags = this.GetAttackFlags()
            };

            if (attackResult.Flags.HasFlag(AttackFlags.AF_MISS))
            {
                return(attackResult);
            }

            if (this._attacker is IPlayerEntity player)
            {
                Item rightWeapon = player.Inventory.GetItem(x => x.Slot == InventorySystem.RightWeaponSlot) ?? InventorySystem.Hand;

                // TODO: GetDamagePropertyFactor()
                int weaponAttack = BattleHelper.GetWeaponAttackDamages(rightWeapon.Data.WeaponType, player);
                attackResult.AttackMin = rightWeapon.Data.AbilityMin * 2 + weaponAttack;
                attackResult.AttackMax = rightWeapon.Data.AbilityMax * 2 + weaponAttack;
            }
            else if (this._attacker is IMonsterEntity monster)
            {
                attackResult.AttackMin = monster.Data.AttackMin;
                attackResult.AttackMax = monster.Data.AttackMax;
            }

            if (this.IsCriticalAttack(this._attacker, attackResult.Flags))
            {
                attackResult.Flags |= AttackFlags.AF_CRITICAL;
                this.CalculateCriticalDamages(attackResult);

                if (this.IsKnockback(attackResult.Flags))
                {
                    attackResult.Flags |= AttackFlags.AF_FLYING;
                }
            }

            attackResult.Damages  = RandomHelper.Random(attackResult.AttackMin, attackResult.AttackMax);
            attackResult.Damages -= this.GetDefenderDefense(attackResult);

            if (attackResult.Damages > 0)
            {
                float blockFactor = this.GetDefenderBlockFactor();
                if (blockFactor < 1f)
                {
                    attackResult.Flags  |= AttackFlags.AF_BLOCKING;
                    attackResult.Damages = (int)(attackResult.Damages * blockFactor);
                }
            }
            else
            {
                attackResult.Damages = 0;
                attackResult.Flags  &= ~AttackFlags.AF_CRITICAL;
                attackResult.Flags  &= ~AttackFlags.AF_FLYING;
            }

            return(attackResult);
        }
Beispiel #2
0
        /// <summary>
        /// Process the melee attack algorithm.
        /// </summary>
        /// <param name="attacker">Attacker</param>
        /// <param name="e">Melee attack event arguments</param>
        private void ProcessMeleeAttack(ILivingEntity attacker, MeleeAttackEventArgs e)
        {
            ILivingEntity defender = e.Target;

            if (defender.Health.IsDead)
            {
                Logger.LogError($"{attacker.Object.Name} cannot attack {defender.Object.Name} because target is already dead.");
                this.ClearBattleTargets(defender);
                this.ClearBattleTargets(attacker);
                return;
            }

            attacker.Battle.Target = defender;
            defender.Battle.Target = attacker;

            AttackResult meleeAttackResult = new MeleeAttackArbiter(attacker, defender).OnDamage();

            Logger.LogDebug($"{attacker.Object.Name} inflicted {meleeAttackResult.Damages} to {defender.Object.Name}");

            if (meleeAttackResult.Flags.HasFlag(AttackFlags.AF_FLYING))
            {
                BattleHelper.KnockbackEntity(defender);
            }

            WorldPacketFactory.SendAddDamage(defender, attacker, meleeAttackResult.Flags, meleeAttackResult.Damages);
            WorldPacketFactory.SendMeleeAttack(attacker, e.AttackType, defender.Id, e.UnknownParameter, meleeAttackResult.Flags);

            defender.Health.Hp -= meleeAttackResult.Damages;

            if (defender.Health.IsDead)
            {
                Logger.LogDebug($"{attacker.Object.Name} killed {defender.Object.Name}.");
                defender.Health.Hp = 0;
                this.ClearBattleTargets(defender);
                this.ClearBattleTargets(attacker);
                WorldPacketFactory.SendDie(attacker as IPlayerEntity, defender, attacker, e.AttackType);

                if (defender is IMonsterEntity deadMonster)
                {
                    var worldServerConfiguration = DependencyContainer.Instance.Resolve <WorldConfiguration>();
                    var itemsData = DependencyContainer.Instance.Resolve <ItemLoader>();
                    var expTable  = DependencyContainer.Instance.Resolve <ExpTableLoader>();

                    deadMonster.Timers.DespawnTime = Time.TimeInSeconds() + 5;

                    // Drop items
                    int itemCount = 0;
                    foreach (DropItemData dropItem in deadMonster.Data.DropItems)
                    {
                        if (itemCount >= deadMonster.Data.MaxDropItem)
                        {
                            break;
                        }

                        long dropChance = RandomHelper.LongRandom(0, DropSystem.MaxDropChance);

                        if (dropItem.Probability * worldServerConfiguration.Rates.Drop >= dropChance)
                        {
                            var item = new Item(dropItem.ItemId, 1, -1, -1, -1, (byte)RandomHelper.Random(0, dropItem.ItemMaxRefine));

                            deadMonster.NotifySystem <DropSystem>(new DropItemEventArgs(item, attacker));
                            itemCount++;
                        }
                    }

                    // Drop item kinds
                    foreach (DropItemKindData dropItemKind in deadMonster.Data.DropItemsKind)
                    {
                        var itemsDataByItemKind = itemsData.GetItems(x => x.ItemKind3 == dropItemKind.ItemKind && x.Rare >= dropItemKind.UniqueMin && x.Rare <= dropItemKind.UniqueMax);

                        if (!itemsDataByItemKind.Any())
                        {
                            continue;
                        }

                        var itemData = itemsDataByItemKind.ElementAt(RandomHelper.Random(0, itemsDataByItemKind.Count() - 1));

                        int itemRefine = RandomHelper.Random(0, 10);

                        for (int i = itemRefine; i >= 0; i--)
                        {
                            long itemDropProbability = (long)(expTable.GetDropLuck(itemData.Level > 120 ? 119 : itemData.Level, itemRefine) * (deadMonster.Data.CorrectionValue / 100f));
                            long dropChance          = RandomHelper.LongRandom(0, DropSystem.MaxDropChance);

                            if (dropChance < itemDropProbability * worldServerConfiguration.Rates.Drop)
                            {
                                var item = new Item(itemData.Id, 1, -1, -1, -1, (byte)itemRefine);

                                deadMonster.NotifySystem <DropSystem>(new DropItemEventArgs(item, attacker));
                                break;
                            }
                        }
                    }

                    // Drop gold
                    int goldDropped = RandomHelper.Random(deadMonster.Data.DropGoldMin, deadMonster.Data.DropGoldMax);
                    deadMonster.NotifySystem <DropSystem>(new DropGoldEventArgs(goldDropped, attacker));

                    // TODO: give exp
                }
            }
        }