Exemplo n.º 1
0
        private CommandResult HandleShutDown(string command, IList <string> args)
        {
            if (args.Count < 2)
            {
                return(CommandResult.InvalidArgument);
            }

            if (LoginServer.Instance.ChannelClients.Count == 0)
            {
                Log.Error("There are no channel servers currently running.");
                return(CommandResult.Okay);
            }

            // Get time
            int time;

            if (!int.TryParse(args[1], out time))
            {
                return(CommandResult.InvalidArgument);
            }

            time = Math2.Clamp(60, 1800, time);

            Send.ChannelShutdown(time);
            Log.Info("Shutdown request sent to all channel servers.");

            return(CommandResult.Okay);
        }
Exemplo n.º 2
0
        public override void Render(ref StringBuilder sb)
        {
            var quest = ChannelServer.Instance.ScriptManager.QuestScripts.Get(this.QuestId);

            if (quest == null)
            {
                throw new ArgumentException("DialogPtjDesc: Unknown quest '" + this.QuestId + "'.");
            }

            var objective = quest.Objectives.First().Value;

            var now            = ErinnTime.Now;
            var remainingHours = Math.Max(0, quest.DeadlineHour - now.Hour);
            var remainingJobs  = Math2.Clamp(0, this.MaxAvailableJobs, this.RemainingJobs);

            sb.Append("<arbeit>");
            sb.AppendFormat("<name>{0}</name>", this.Name);
            sb.AppendFormat("<id>{0}</id>", this.QuestId);
            sb.AppendFormat("<title>{0}</title>", this.Title);
            foreach (var group in quest.RewardGroups.Values)
            {
                sb.AppendFormat("<rewards id=\"{0}\" type=\"{1}\">", group.Id, (int)group.Type);

                foreach (var reward in group.Rewards.Where(a => a.Result == QuestResult.Perfect))
                {
                    sb.AppendFormat("<reward>* {0}</reward>", reward.ToString());
                }

                sb.AppendFormat("</rewards>");
            }
            sb.AppendFormat("<desc>{0}</desc>", quest.Description);
            sb.AppendFormat("<values maxcount=\"{0}\" remaincount=\"{1}\" remaintime=\"{2}\" history=\"{3}\"/>", this.MaxAvailableJobs, this.RemainingJobs, remainingHours, this.History);
            sb.Append("</arbeit>");
        }
Exemplo n.º 3
0
        /// <summary>
        /// Checks if attacker has Critical Hit and applies crit bonus
        /// by chance. Also sets the target action's critical option if a
        /// crit happens.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="critChance"></param>
        /// <param name="damage"></param>
        /// <param name="tAction"></param>
        public static void Handle(Creature attacker, float critChance, ref float damage, TargetAction tAction, bool bypassNoviceCheck = false)
        {
            // Check if attacker actually has critical hit
            var critSkill = attacker.Skills.Get(SkillId.CriticalHit);

            if (critSkill == null || (critSkill.Info.Rank == SkillRank.Novice && !bypassNoviceCheck))
            {
                return;
            }

            // Cap crit chance at 30%
            critChance = Math2.Clamp(0, 30, critChance);

            // Cancel if crit doesn't happen
            if (RandomProvider.Get().NextDouble() * 100 >= critChance)
            {
                return;
            }

            // Add crit bonus
            var bonus = critSkill.RankData.Var1 / 100f;

            damage = damage + (damage * bonus);

            // Set target option
            tAction.Set(TargetOptions.Critical);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Spawns creature(s)
        /// </summary>
        /// <param name="raceId">Race to spawn.</param>
        /// <param name="amount">Amount of creatures to spawn.</param>
        /// <param name="regionId">Region to spawn creatures in.</param>
        /// <param name="pos">Position to spawn creatures at.</param>
        /// <param name="radius">Radius around position for random spawn</param>
        /// <param name="effect">Whether to display spawn effect</param>
        /// <param name="onDeath">Runs when one of the creatures dies</param>
        /// <returns>List of creatures spawned by this call.</returns>
        protected List <Creature> Spawn(int raceId, int amount, int regionId, Position pos, int radius, bool effect, Action <Creature, Creature> onDeath)
        {
            var result = new List <Creature>();

            amount = Math2.Clamp(1, 100, amount);

            var rnd = RandomProvider.Get();

            for (int i = 0; i < amount; ++i)
            {
                if (radius > 0)
                {
                    pos = pos.GetRandomInRange(radius, rnd);
                }

                var creature = ChannelServer.Instance.World.SpawnManager.Spawn(raceId, regionId, pos.X, pos.Y, true, effect);

                if (onDeath != null)
                {
                    creature.Death += onDeath;
                }

                result.Add(creature);
            }

            return(result);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Returns success chance between 0 and 100.
        /// </summary>
        /// <remarks>
        /// Unofficial. It's unlikely that officials use a table, instead of
        /// a formula, but for a lack of formula, we're forced to go with
        /// this. The success rates actually seem to be rather static,
        /// so it should work fine. We have all possible combinations,
        /// and with this function we do get the correct base chance.
        /// </remarks>
        /// <param name="creature"></param>
        /// <param name="skill"></param>
        /// <param name="manualRank"></param>
        /// <returns></returns>
        protected int GetSuccessChance(Creature creature, Skill skill, SkillRank manualRank)
        {
            var diff   = ((int)skill.Info.Rank - (int)manualRank);
            var chance = SuccessTable[29 - (diff + 15)];

            // Production Mastery bonus
            var pm = creature.Skills.Get(SkillId.ProductionMastery);

            if (pm != null)
            {
                chance += (byte)pm.Info.Rank;
            }

            // Party bonus
            // http://mabination.com/threads/579-Sooni-s-Guide-to-Tailoring!-(Please-claim-back-from-me)
            if (creature.IsInParty)
            {
                var members      = creature.Party.GetMembers();
                var tailorsCount = members.Where(a => a != creature && a.Skills.Has(skill.Info.Id, SkillRank.RF)).Count();
                if (tailorsCount != 0)
                {
                    chance += (int)(tailorsCount * 5 / 100f * chance);
                }
            }

            return(Math2.Clamp(0, 99, chance));
        }
Exemplo n.º 6
0
        public void    Advance()
        {
            if (_rotationLookVelocity == 0 && _rotationVelocity == 0 && _forwardVelocity == 0 && _rightVelocity == 0)
            {
                _timeLastUpdate = DateTime.Now;
                return;
            }

            DateTime now     = DateTime.Now;
            TimeSpan span    = now - _timeLastUpdate;
            float    seconds = Math.Min(span.Milliseconds / 1000.0f, 0.5f) * 20;

            _timeLastUpdate = now;

            Vector3D localUp      = this.World.LocalUpAxis;
            Vector3D localRight   = this.World.LocalRightAxis;
            Vector3D localForward = this.World.LocalForwardAxis;

            // updating rotations are easy...
            _rotationBody += seconds * (_rotationVelocity * 30);
            _rotationLook  = Math2.Clamp(_rotationLook + seconds * _rotationLookVelocity * 30, -1.4f, 1.4f);


            Matrix3D xfrm = Matrix3D.FromRotation(localUp, _rotationBody);

            Vector3D localVelocity =
                seconds * _forwardVelocity * localForward * 35 +
                seconds * _rightVelocity * localRight * 35;

            Vector3D absoluteVelocity = xfrm * localVelocity;

            Vector3D absoluteUp      = xfrm * this.World.LocalUpAxis;
            Vector3D absoluteRight   = xfrm * this.World.LocalRightAxis;
            Vector3D absoluteForward = xfrm * this.World.LocalForwardAxis;

            //Debug.WriteLine( "Velocity: " + velocityBody );
            //Debug.WriteLine( "TimeStep Velocity: " + incrementalMovement );


            //Vector3D extentCenter	= xfrm * ( localForward * _bodyRadius );
            //Vector3D extentTop		= localUp * _bodyRadius;
            //Vector3D extentBottom	= - localUp * ( _bodyHeight - _liftSize );

            //Debug.WriteLine( "Old Position: " + _translationBody );
            if (absoluteVelocity.GetMagnitude() > 0)
            {
                Vector3D moveDirection = absoluteVelocity.GetUnit();
                Vector3D centerDelta   = SmartStep(_translationBody, moveDirection, _bodyRadius, absoluteVelocity.GetMagnitude());                                          //+ extentCenter, _translationBody + extentCenter + absoluteVelocity ) - ( _translationBody + extentCenter ) - forwardStep;
                Vector3D topDelta      = SmartStep(_translationBody + absoluteUp * _bodyRadius, moveDirection, _bodyRadius, absoluteVelocity.GetMagnitude());               //MoveTo( _translationBody + extentTop, _translationBody + extentTop + absoluteVelocity ) - ( _translationBody + extentTop )    - forwardStep;
                Vector3D bottomDelta   = SmartStep(_translationBody - absoluteUp * (_bodyHeight - _liftSize), moveDirection, _bodyRadius, absoluteVelocity.GetMagnitude()); // MoveTo( _translationBody + extentBottom, _translationBody + extentBottom + absoluteVelocity ) - ( _translationBody + extentBottom ) - forwardStep;

                _translationBody += Vector3D.Min(Vector3D.Min(centerDelta, topDelta), bottomDelta);
            }

            _translationBody += SmartStep(_translationBody, absoluteRight, _bodyRadius, 0);
            _translationBody += SmartStep(_translationBody, -absoluteRight, _bodyRadius, 0);

            _translationBody += SmartStep(_translationBody, -absoluteUp, _bodyHeight, _liftSize);
        }
Exemplo n.º 7
0
        //------------------------------------------------------------------------------------

        static public Color     FromArgb(int a, int r, int g, int b)
        {
            return(Color.FromArgb(
                       Math2.Clamp(a, 0, 255),
                       Math2.Clamp(r, 0, 255),
                       Math2.Clamp(g, 0, 255),
                       Math2.Clamp(b, 0, 255)));
        }
Exemplo n.º 8
0
        public DialogElement Insert(int index, params DialogElement[] elements)
        {
            index = Math2.Clamp(0, this.Children.Count, index);

            this.Children.InsertRange(index, elements);

            return(this);
        }
Exemplo n.º 9
0
        private CommandResult HandleSpawn(ChannelConnection conn, Character character, Character target, string command, string[] args)
        {
            if (args.Length < 2)
            {
                return(CommandResult.InvalidArgument);
            }

            int id;

            if (!int.TryParse(args[1], out id))
            {
                return(CommandResult.InvalidArgument);
            }

            var amount = 1;

            if (args.Length > 2 && !int.TryParse(args[2], out amount))
            {
                return(CommandResult.InvalidArgument);
            }

            amount = Math2.Clamp(1, 100, amount);

            var monsterData = ChannelServer.Instance.Data.MonsterDb.Find(id);

            if (monsterData == null)
            {
                this.SystemMessage(character, "Monster not found.");
                return(CommandResult.Okay);
            }

            var rnd = new Random(Environment.TickCount);

            for (int i = 0; i < amount; ++i)
            {
                var monster = new Monster(id, NpcType.Monster);

                Position  pos;
                Direction dir;
                if (amount == 1)
                {
                    pos = target.Position;
                    dir = target.Direction;
                }
                else
                {
                    pos = target.Position.GetRandomInRange2D(amount * 4, rnd);
                    dir = new Direction(rnd.Next(0, 360));
                }

                monster.Position  = pos;
                monster.Direction = dir;

                target.Map.AddMonster(monster);
            }

            return(CommandResult.Okay);
        }
Exemplo n.º 10
0
        public void Load()
        {
            this.Require("system/conf/world.conf");

            this.ExpRate      = this.GetFloat("exp_rate", 100) / 100.0f;
            this.QuestExpRate = this.GetFloat("quest_exp_rate", 100) / 100.0f;
            this.SkillExpRate = this.GetFloat("skill_exp_rate", 100) / 100.0f;

            this.LevelApRate = this.GetFloat("level_ap_rate", 100) / 100.0f;
            this.QuestApRate = this.GetFloat("quest_ap_rate", 100) / 100.0f;
            this.AgeApRate   = this.GetFloat("age_ap_rate", 100) / 100.0f;

            this.DropRate              = this.GetFloat("drop_rate", 100) / 100.0f;
            this.GoldDropChance        = this.GetFloat("gold_drop_chance", 30) / 100.0f;
            this.GoldDropRate          = this.GetFloat("gold_drop_rate", 100) / 100.0f;
            this.LuckyFinishChance     = this.GetFloat("lucky_finish_chance", 0.015f) / 100.0f;
            this.BigLuckyFinishChance  = this.GetFloat("big_lucky_finish_chance", 0.005f) / 100.0f;
            this.HugeLuckyFinishChance = this.GetFloat("huge_lucky_finish_chance", 0.001f) / 100.0f;
            this.PropDropChance        = this.GetFloat("prop_drop_chance", 30) / 100.0f;
            this.LootStealProtection   = this.GetInt("loot_steal_protection", NPC.DisappearDelay);

            this.DeadlyNpcs       = this.GetBool("deadly_npcs", true);
            this.EnableHunger     = this.GetBool("enable_hunger", true);
            this.YouAreWhatYouEat = this.GetBool("you_are_what_you_eat", true);

            var gmcpCommand = ChannelServer.Instance.CommandProcessor.GetCommand("gmcp");

            this.GmcpMinAuth = gmcpCommand != null ? gmcpCommand.Auth : this.GetInt("gmcp_min_auth", 50);

            this.PerfectPlay       = this.GetBool("perfect_play", false);
            this.InfiniteResources = this.GetBool("infinite_resources", false);
            this.PerfectFishing    = this.GetBool("perfect_fishing", false);
            this.InfiniteBait      = this.GetBool("infinite_bait", false);
            this.InfiniteArrows    = this.GetBool("infinite_arrows", false);
            this.SharpMindChance   = this.GetFloat("sharp_mind_chance", 50);

            this.Bagception        = this.GetBool("bagception", false);
            this.NoDurabilityLoss  = this.GetBool("no_durability_loss", false);
            this.UnlimitedUpgrades = this.GetBool("unlimited_upgrades", false);
            this.UncapProficiency  = this.GetBool("uncap_proficiency", false);
            this.UnlimitedDyes     = this.GetBool("unlimited_dyes", false);
            this.DyeDifficulty     = Math2.Clamp(1, 5, this.GetInt("dye_difficulty", 5));

            this.RebirthTime = TimeSpan.FromDays(this.GetInt("rebirth_time", 6));

            this.BankGoldPerCharacter = this.GetInt("gold_per_character", 5000000);

            this.PtjInfiniteMemory = this.GetBool("ptj_infinite_memory", false);

            this.PrivateDungeons = this.GetBool("private_dungeons", false);
            this.EasySwitch      = this.GetBool("easy_switch", false);
            this.RandomFloors    = this.GetBool("random_floors", false);

            this.PartyExpBonus     = this.GetFloat("party_exp_bonus", 0);
            this.PartyMaxSize      = Math2.Clamp(1, 99, this.GetInt("party_max_size", 8));
            this.PartyQuestMinSize = Math2.Clamp(1, this.PartyMaxSize, this.GetInt("party_quest_min_size", 2));
        }
Exemplo n.º 11
0
Arquivo: Party.cs Projeto: yukpiz/aura
 /// <summary>
 /// Sets given options without updating the clients.
 /// </summary>
 /// <param name="type"></param>
 /// <param name="name"></param>
 /// <param name="dungeonLevel"></param>
 /// <param name="info"></param>
 /// <param name="password"></param>
 /// <param name="maxSize"></param>
 private void SetSettings(PartyType type, string name, string dungeonLevel, string info, string password, int maxSize)
 {
     this.Type         = type;
     this.Name         = name;
     this.DungeonLevel = (string.IsNullOrWhiteSpace(dungeonLevel) ? null : dungeonLevel);
     this.Info         = (string.IsNullOrWhiteSpace(info) ? null : info);
     this.Password     = (string.IsNullOrWhiteSpace(password) ? null : password);
     this.MaxSize      = Math2.Clamp(this.MemberCount, ChannelServer.Instance.Conf.World.PartyMaxSize, maxSize);
 }
Exemplo n.º 12
0
Arquivo: Party.cs Projeto: yukpiz/aura
        /// <summary>
        /// Sets party's max size.
        /// </summary>
        /// <param name="size"></param>
        public void SetMaxSize(int size)
        {
            this.MaxSize = Math2.Clamp(this.MemberCount, ChannelServer.Instance.Conf.World.PartyMaxSize, size);

            if (this.IsOpen)
            {
                Send.PartyMemberWantedRefresh(this);
            }
        }
Exemplo n.º 13
0
        public void Clamp()
        {
            Assert.Equal(10, Math2.Clamp(10, 20, 05));
            Assert.Equal(20, Math2.Clamp(10, 20, 25));
            Assert.Equal(15, Math2.Clamp(10, 20, 15));

            Assert.Equal(10.5f, Math2.Clamp(10.5f, 20.5f, 05.5f));
            Assert.Equal(20.5f, Math2.Clamp(10.5f, 20.5f, 25.5f));
            Assert.Equal(15.5f, Math2.Clamp(10.5f, 20.5f, 15.5f));
        }
Exemplo n.º 14
0
        /// <summary>
        /// Converts a world X coordinate to the index based on the number of color in the current color map.
        /// </summary>
        /// <param name="worldX">World X coordinate</param>
        /// <returns>Corresponding color map index</returns>
        private int WorldToIndex(int worldX)
        {
            if (_colormap.Count <= 1)
            {
                return(0);
            }


            return(Math2.Clamp((int)Math.Round(((float)(_colormap.Count - 1) * (float)worldX / (float)ClientSize.Width)), 0, _colormap.Count - 1));
        }
Exemplo n.º 15
0
        public DialogElement Replace(int index, params DialogElement[] elements)
        {
            index = Math2.Clamp(0, this.Children.Count, index);

            if (this.Children.Count != 0)
            {
                this.Children.RemoveAt(index);
            }
            this.Children.InsertRange(index, elements);

            return(this);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Activates weaken conditions for creature.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="levels">Amount of levels to lower the power level.</param>
        /// <param name="duration">Duration of the state.</param>
        protected void Weaken(Creature creature, int levels, int duration)
        {
            levels = Math2.Clamp(1, 255, levels);

            var extra = new MabiDictionary();

            extra.SetByte("WKN_LV", (byte)levels);

            // min -> ms
            duration = duration * 60 * 1000;

            Send.Notice(creature, Localization.Get("The enemies seem to be much more powerful now."));
            creature.Conditions.Activate(ConditionsA.Weaken, extra, duration);
        }
Exemplo n.º 17
0
        /// <summary>
        /// Calculates quality based on recipe and ingredients.
        /// </summary>
        /// <remarks>
        /// The formula used in this method is unofficial. While it does feel
        /// very similar in some test cases, it could potentially create
        /// very different results. Officials also RNG the results,
        /// which this method currently does not.
        ///
        /// The Help fields in the return value specify a tip on what went
        /// wrong with the cooking attempt, if certain requirements are
        /// fulfilled. In that case it will set the item to the item in
        /// question, and the amount to the amount the ingredient differed
        /// from the recipe. If the value is lower than 0, it was less,
        /// if it's greater, it was more. If no helpful tip could be found,
        /// item is null.
        /// </remarks>
        /// <param name="recipe"></param>
        /// <param name="ingredients"></param>
        /// <returns></returns>
        private Judgement JudgeQuality(RecipeData recipe, List <Ingredient> ingredients)
        {
            Judgement result;

            result.Quality    = 0;
            result.HelpItem   = null;
            result.HelpAmount = 0;

            var total = (float)recipe.MainIngredients.Sum(a => a.Amount);

            foreach (var ingredient in ingredients)
            {
                // Every item *should* only appear once in main or other.
                var ingredientData = recipe.MainIngredients.FirstOrDefault(a => a.ItemId == ingredient.Item.Info.Id);
                if (ingredientData == null)
                {
                    ingredientData = recipe.OtherIngredients.FirstOrDefault(a => a.ItemId == ingredient.Item.Info.Id);
                    if (ingredientData == null)
                    {
                        Log.Error("Cooking.JudgeQuality: Failed to get ingredient data for item '{0}' in recipe '{1},{2}'.", ingredient.Item.Info.Id, recipe.Method, recipe.ItemId);
                        break;
                    }
                }

                // Calculate the amount difference between the provided
                // ingredient and the recipe.
                var amount        = ingredient.Amount;
                var ideal         = (1f / total * ingredientData.Amount);
                var difference    = ideal - amount;
                var differenceAbs = Math.Abs(difference);

                // Calculate quality
                var rate       = 1f - (1f / ideal * (differenceAbs * 2f));
                var qualityAdd = ingredientData.QualityMin + rate * (ingredientData.QualityMax - ingredientData.QualityMin);

                result.Quality = Math2.Clamp(-100, 100, result.Quality + qualityAdd);

                // Save the ingredient with the biggest difference,
                // for the help message.
                if (differenceAbs > 0.05f && Math.Abs(result.HelpAmount) < differenceAbs)
                {
                    result.HelpAmount = -difference;
                    result.HelpItem   = ingredient.Item;
                }
            }

            return(result);
        }
Exemplo n.º 18
0
        public static NeuralNetwork Generate(int inputLength, int outputLength)
        {
            var hiddenLayers = Math2.RoundToInt(inputLength * (2f / 3) + outputLength);

            hiddenLayers = Math2.Clamp(hiddenLayers, inputLength, outputLength);
            hiddenLayers = Math2.Clamp(hiddenLayers, 0, inputLength * 2 - 1);

            var network = new NeuralNetwork();

            network.AddLayerInput(inputLength);
            network.AddLayerHidden(hiddenLayers);
            network.AddLayerHidden(hiddenLayers);
            network.AddLayerOutput(outputLength);
            network.ConnectLayers();
            return(network);
        }
Exemplo n.º 19
0
        static unsafe public Bitmap CreateContrastedBitmap(Bitmap original, float contrast)
        {
            Bitmap     lightenedBitmap = new Bitmap(original);
            BitmapData bd = lightenedBitmap.LockBits(new Rectangle(0, 0, lightenedBitmap.Width, lightenedBitmap.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

            int *rgba = (int *)bd.Scan0.ToPointer();

            for (int i = 0; i < (lightenedBitmap.Width * lightenedBitmap.Height); i++)
            {
                Color clr = Color.FromArgb(rgba[i]);
                rgba[i] = Color.FromArgb(clr.A,
                                         Math2.Clamp((int)((clr.R - 255) * contrast + 255), 0, 255),
                                         Math2.Clamp((int)((clr.G - 255) * contrast + 255), 0, 255),
                                         Math2.Clamp((int)((clr.B - 255) * contrast + 255), 0, 255)).ToArgb();
            }

            lightenedBitmap.UnlockBits(bd);

            return(lightenedBitmap);
        }
Exemplo n.º 20
0
        public void GmcpBoost(ChannelClient client, Packet packet)
        {
            var multiplier = packet.GetFloat();

            var creature = client.GetCreatureSafe(packet.Id);

            var speedBonus = (short)(multiplier * 100 - 100);

            speedBonus = (short)Math2.Clamp(0, 1000, speedBonus);

            if (speedBonus == 0)
            {
                creature.Conditions.Deactivate(ConditionsC.Hurry);
            }
            else
            {
                creature.Conditions.Activate(ConditionsC.Hurry, speedBonus);
            }

            Send.ServerMessage(creature, Localization.Get("Speed boost: {0}x"), multiplier.ToString("0.0", CultureInfo.InvariantCulture));
        }
Exemplo n.º 21
0
        public MainForm()
        {
            InitializeComponent();
            _connectionStatus.Text = "Not Connected";
            _packetReceived.Text   = "";

            _airOn.Value      = Math2.Clamp(Settings.Default.IntakeOpen, _airOn.Minimum, _airOn.Maximum);
            _airOff.Value     = Math2.Clamp(Settings.Default.IntakeClose, _airOff.Minimum, _airOff.Maximum);
            _exhaustOn.Value  = Math2.Clamp(Settings.Default.ExhaustOpen, _exhaustOn.Minimum, _exhaustOff.Maximum);
            _exhaustOff.Value = Math2.Clamp(Settings.Default.ExhaustClose, _exhaustOff.Minimum, _exhaustOff.Maximum);

            UpdateValues();
            Program.ComService.StatusChanged += ComService_StatusChanged;
            Program.ComService.DataArrived   += ComService_DataArrived;

            using (FileStream stream = File.Open(SettingsLogFile, FileMode.Create))
                using (TextWriter writer = new StreamWriter(stream))
                {
                    string line = "RPMs,AirOn,AirOff,ExhaustOn,ExhaustOff";
                    writer.WriteLine(line);
                }
        }
Exemplo n.º 22
0
        private CommandResult HandleShutDown(string command, IList <string> args)
        {
            if (args.Count < 2)
            {
                return(CommandResult.InvalidArgument);
            }

            // Get time
            int time;

            if (!int.TryParse(args[1], out time))
            {
                return(CommandResult.InvalidArgument);
            }

            time = Math2.Clamp(60, 1800, time);

            /*Send.ChannelShutdown(time);
             * Log.Info("Shutdown request sent to all channel servers.");*/

            return(CommandResult.Okay);
        }
Exemplo n.º 23
0
        public void GmcpBoost(ChannelClient client, Packet packet)
        {
            var multiplier = packet.GetFloat();

            var creature = client.GetCreatureSafe(packet.Id);

            var speedBonus = (short)(multiplier * 100 - 100);

            speedBonus = (short)Math2.Clamp(0, 1000, speedBonus);

            if (speedBonus == 0)
            {
                creature.Conditions.Deactivate(ConditionsC.Hurry);
            }
            else
            {
                var extra = new MabiDictionary();
                extra.SetShort("VAL", speedBonus);
                creature.Conditions.Activate(ConditionsC.Hurry, extra);
            }

            Send.ServerMessage(creature, Localization.Get("Speed boost: {0:0.0}x"), multiplier);
        }
Exemplo n.º 24
0
    public void PlayerUnequipsItem(Creature creature, Item item)
    {
        // Remove Mana on unequipping wand
        // http://mabinogiworld.com/view/Mana_Evaporation
        if (!IsEnabled("ManaBurnRemove"))
        {
            if (item.HasTag("/wand/|/staff/"))
            {
                var rate = Math2.Clamp(0, 100, 100 - creature.Inventory.GetManaBurnBonus());
                creature.BurnMana(rate);

                if (rate == 100)
                {
                    Send.Notice(creature, L("The Mana connected to the Wand has disappeared!"));
                }
                else
                {
                    // Unofficial, but makes more sense.
                    Send.Notice(creature, L("Some Mana connected to the Wand has disappeared!"));
                }
            }
        }
    }
Exemplo n.º 25
0
 public QuestRewardAp(short amount)
 {
     this.Amount = (short)Math2.Clamp(0, short.MaxValue, amount * ChannelServer.Instance.Conf.World.QuestApRate);
 }
Exemplo n.º 26
0
        /// <summary>
        /// Returns success chance, based on skill, option set, and powder
        /// used.
        /// <remarks>
        /// Unofficial. It kinda matches the debug output of the client,
        /// but it is a little off.
        /// </remarks>
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="rightHand"></param>
        /// <param name="skill"></param>
        /// <param name="optionSetData"></param>
        /// <returns></returns>
        private float GetChance(Creature creature, Item rightHand, Skill skill, OptionSetData optionSetData)
        {
            // Check right hand, only use it if it's powder
            if (rightHand != null && !rightHand.HasTag("/enchant/powder/"))
            {
                rightHand = null;
            }

            // Get base chance, based on skill and powder
            var baseChance = _baseChanceB00;             // (Blessed) Magic Powder/None

            if (skill.Info.Id == SkillId.Enchant && rightHand != null)
            {
                if (rightHand.HasTag("/powder02/"))                 // Elite Magic Powder
                {
                    baseChance = _baseChanceB05;
                }
                else if (rightHand.HasTag("/powder03/"))                 // Elven Magic Powder
                {
                    baseChance = _baseChanceB10;
                }
                else if (rightHand.HasTag("/powder01/"))                 // Ancient Magic Powder
                {
                    baseChance = _baseChanceB50;
                }
                else if (rightHand.HasTag("/powder04/") && rightHand.Info.Id == 85865)                 // Notorious Magic Powder
                {
                    baseChance = _baseChanceB60;
                }
            }

            // Get chance
            var rank          = Math2.Clamp(0, _baseChanceB00.Length - 1, (int)optionSetData.Rank - 1);
            var chance        = baseChance[rank];
            var intBonus      = 1f;
            var thursdayBonus = 0f;

            // Int bonus if using powder
            if (skill.Info.Id == SkillId.Enchant && rightHand != null)
            {
                intBonus = 1f + ((creature.Int - 35f) / 350f);
            }

            // Thursday bonus
            if (ErinnTime.Now.Month == 4)
            {
                thursdayBonus = Math.Max(0, (15 - rank) / 2f);
            }

            // Result
            var result = Math2.Clamp(0, 90, chance * intBonus + thursdayBonus);

            // Debug
            if (creature.Titles.SelectedTitle == TitleId.devCAT)
            {
                Send.ServerMessage(creature,
                                   "Debug: Enchant success chance: {0:0} (base: {1:0}, int: {2:0}, thu: {3:0})",
                                   result, chance, (chance / 1f * (intBonus - 1f)), thursdayBonus);
            }

            return(result);
        }
Exemplo n.º 27
0
        /// <summary>
        /// Called once ready to pull the fish out.
        /// </summary>
        /// <remarks>
        /// When you catch something just before running out of bait,
        /// and you send MotionCancel2 from Cancel, there's a
        /// visual bug on Aura, where the item keeps flying to you until
        /// you move. This does not happen on NA for unknown reason.
        /// The workaround: Check for cancellation in advance and only
        /// send the real in effect if the skill wasn't canceled.
        /// </remarks>
        /// <param name="creature"></param>
        /// <param name="method">Method used on this try</param>
        /// <param name="success">Success of manual try</param>
        public void OnResponse(Creature creature, FishingMethod method, bool success)
        {
            // Get skill
            var skill = creature.Skills.Get(SkillId.Fishing);

            if (skill == null)
            {
                Log.Error("Fishing.OnResponse: Missing skill.");
                return;
            }

            var rnd = RandomProvider.Get();

            // Update prop state
            creature.Temp.FishingProp.SetState("empty");

            // Get auto success
            if (method == FishingMethod.Auto)
            {
                success = rnd.NextDouble() < skill.RankData.Var3 / 100f;
            }

            // Perfect fishing
            if (ChannelServer.Instance.Conf.World.PerfectFishing)
            {
                success = true;
            }

            // Check fishing ground
            if (creature.Temp.FishingDrop == null)
            {
                Send.ServerMessage(creature, "Error: No items found.");
                Log.Error("Fishing.OnResponse: Failing, no drop found.");
                success = false;
            }

            // Check equipment
            if (!this.CheckEquipment(creature))
            {
                Send.ServerMessage(creature, "Error: Missing equipment.");
                Log.Error("Fishing.OnResponse: Failing, Missing equipment.");
                // TODO: Security violation once we're sure this can't happen
                //   without modding.
                success = false;
            }

            var cancel = false;

            // Reduce durability
            if (creature.RightHand != null)
            {
                creature.Inventory.ReduceDurability(creature.RightHand, 15);

                // Check rod durability
                if (creature.RightHand.Durability == 0)
                {
                    cancel = true;
                }
            }

            // Remove bait
            if (creature.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteBait)
            {
                creature.Inventory.Decrement(creature.Magazine);

                // Check if bait was removed because it was empty
                if (creature.Magazine == null)
                {
                    cancel = true;
                }
            }

            // Fail
            Item item = null;

            if (!success)
            {
                Send.Notice(creature, Localization.Get("I was hesistating for a bit, and it got away..."));                 // More responses?
                Send.Effect(creature, Effect.Fishing, (byte)FishingEffectType.Fall, true);
            }
            // Success
            else
            {
                var propName = "prop_caught_objbox_01";
                var propSize = 0;
                var size     = 0;
                var dropData = creature.Temp.FishingDrop;

                // Create item
                if (dropData.QuestId != 0)
                {
                    item = Item.CreateQuestScroll(dropData.QuestId);
                }
                else
                {
                    item = new Item(dropData);
                }

                // Check fish
                var fish = AuraData.FishDb.Find(dropData.ItemId);
                if (fish != null)
                {
                    propName = fish.PropName;
                    propSize = fish.PropSize;

                    // Random fish size, unofficial
                    if (fish.SizeMin + fish.SizeMax != 0)
                    {
                        var min = fish.SizeMin;
                        var max = fish.SizeMax;

                        // Var1 bonus
                        min += (int)skill.RankData.Var1;

                        // Var4 bonus
                        min += (int)Math.Max(0, (item.Data.BaseSize - fish.SizeMin) / 100f * skill.RankData.Var4);

                        // Modify min and max, so the size falls into big or
                        // small territory.
                        var mid = (max - min) / 2;
                        if (creature.Temp.CatchSize == CatchSize.BigOne)
                        {
                            min += mid;
                        }
                        else
                        {
                            max -= mid;
                        }

                        // Cap
                        if (max < min)
                        {
                            max = min;
                        }
                        if (min > max)
                        {
                            min = max;
                        }

                        size = Math2.Clamp(fish.SizeMin, fish.SizeMax, rnd.Next(min, max + 1));
                        var scale = (1f / item.Data.BaseSize * size);

                        item.MetaData1.SetFloat("SCALE", scale);
                    }
                }

                // Set equipment durability to 0, does not apply to
                // unrepairable items, like Gargoyle Swords.
                // http://wiki.mabinogiworld.com/view/Fishing#Details
                if (item.HasTag("/equip/") && !item.HasTag("/not_repairable/"))
                {
                    item.Durability = 0;
                }

                // Drop if inv add failed
                List <Item> changed;
                if (!creature.Inventory.Insert(item, false, out changed))
                {
                    item.Drop(creature.Region, creature.GetPosition(), 100, creature, false);
                }

                var itemEntityId = (changed == null || changed.Count == 0 ? item.EntityId : changed.First().EntityId);

                // Show acquire using the item's entity id if it wasn't added
                // to a stack, or using the stack's id if it was.
                Send.AcquireInfo2(creature, "fishing", itemEntityId);

                // Holding up fish effect
                if (!cancel)
                {
                    Send.Effect(creature, Effect.Fishing, (byte)FishingEffectType.ReelIn, true, creature.Temp.FishingProp.EntityId, item.Info.Id, size, propName, propSize);
                }
            }

            creature.Temp.FishingDrop = null;

            // Handle training
            this.Training(creature, skill, success, item);

            // Fishing event
            ChannelServer.Instance.Events.OnCreatureFished(creature, item);

            // Cancel
            if (cancel)
            {
                creature.Skills.CancelActiveSkill();
                return;
            }

            // Next round
            this.StartFishing(creature, 6000);
        }
Exemplo n.º 28
0
        public void Load()
        {
            this.Require("system/conf/world.conf");

            this.ExpRate                    = this.GetFloat("exp_rate", 100) / 100.0f;
            this.QuestExpRate               = this.GetFloat("quest_exp_rate", 100) / 100.0f;
            this.SkillExpRate               = this.GetFloat("skill_exp_rate", 100) / 100.0f;
            this.LifeSkillExpRate           = this.GetFloat("life_skill_exp_rate", 100) / 100.0f;
            this.CombatSkillExpRate         = this.GetFloat("combat_skill_exp_rate", 100) / 100.0f;
            this.MagicSkillExpRate          = this.GetFloat("magic_skill_exp_rate", 100) / 100.0f;
            this.AlchemySkillExpRate        = this.GetFloat("alchemy_skill_exp_rate", 100) / 100.0f;
            this.FighterSkillExpRate        = this.GetFloat("fighter_skill_exp_rate", 100) / 100.0f;
            this.MusicSkillExpRate          = this.GetFloat("music_skill_exp_rate", 100) / 100.0f;
            this.PuppetSkillExpRate         = this.GetFloat("puppetry_skill_exp_rate", 100) / 100.0f;
            this.GunsSkillExpRate           = this.GetFloat("dualgun_skill_exp_rate", 100) / 100.0f;
            this.NinjaSkillExpRate          = this.GetFloat("ninja_skill_exp_rate", 100) / 100.0f;
            this.TransformationSkillExpRate = this.GetFloat("transformations_skill_exp_rate", 100) / 100.0f;
            this.DemiSkillExpRate           = this.GetFloat("demigod_skill_exp_rate", 100) / 100.0f;
            this.DivineKnightsSkillExpRate  = this.GetFloat("crusader_skill_exp_rate", 100) / 100.0f;

            this.LevelApRate = this.GetFloat("level_ap_rate", 100) / 100.0f;
            this.QuestApRate = this.GetFloat("quest_ap_rate", 100) / 100.0f;
            this.AgeApRate   = this.GetFloat("age_ap_rate", 100) / 100.0f;

            this.DropRate              = this.GetFloat("drop_rate", 100) / 100.0f;
            this.GoldDropChance        = this.GetFloat("gold_drop_chance", 30) / 100.0f;
            this.GoldDropRate          = this.GetFloat("gold_drop_rate", 100) / 100.0f;
            this.LuckyFinishChance     = this.GetFloat("lucky_finish_chance", 0.015f) / 100.0f;
            this.BigLuckyFinishChance  = this.GetFloat("big_lucky_finish_chance", 0.005f) / 100.0f;
            this.HugeLuckyFinishChance = this.GetFloat("huge_lucky_finish_chance", 0.001f) / 100.0f;
            this.PropDropChance        = this.GetFloat("prop_drop_chance", 30) / 100.0f;
            this.LootStealProtection   = this.GetInt("loot_steal_protection", NPC.DisappearDelay);

            this.DeadlyNpcs       = this.GetBool("deadly_npcs", true);
            this.EnableHunger     = this.GetBool("enable_hunger", true);
            this.YouAreWhatYouEat = this.GetBool("you_are_what_you_eat", true);

            var gmcpCommand = ChannelServer.Instance.CommandProcessor.GetCommand("gmcp");

            this.GmcpMinAuth = gmcpCommand != null ? gmcpCommand.Auth : this.GetInt("gmcp_min_auth", 50);

            this.PerfectPlay       = this.GetBool("perfect_play", false);
            this.InfiniteResources = this.GetBool("infinite_resources", false);
            this.PerfectFishing    = this.GetBool("perfect_fishing", false);
            this.InfiniteBait      = this.GetBool("infinite_bait", false);
            this.InfiniteArrows    = this.GetBool("infinite_arrows", false);
            this.SharpMindChance   = this.GetFloat("sharp_mind_chance", 50);
            this.SafeEnchanting    = this.GetBool("safe_enchanting", false);

            this.Bagception                  = this.GetBool("bagception", false);
            this.NoDurabilityLoss            = this.GetBool("no_durability_loss", false);
            this.UnlimitedUpgrades           = this.GetBool("unlimited_upgrades", false);
            this.UncapProficiency            = this.GetBool("uncap_proficiency", false);
            this.UnlimitedDyes               = this.GetBool("unlimited_dyes", false);
            this.DyeDifficulty               = Math2.Clamp(1, 5, this.GetInt("dye_difficulty", 5));
            this.BrokenEggs                  = this.GetBool("broken_eggs", true);
            this.SwitchCancelBolts           = this.GetBool("switch_cancel_bolts", true);
            this.ProficiencyRate             = this.GetFloat("proficiency_rate", 100);
            this.GlobalBank                  = this.GetBool("global_bank", true);
            this.ReusingPersonalShopLicenses = this.GetBool("reusing_personal_shop_licenses", false);

            this.RebirthTime = TimeSpan.FromDays(this.GetInt("rebirth_time", 6));

            this.BankGoldPerCharacter = this.GetInt("gold_per_character", 5000000);

            this.PtjInfiniteMemory = this.GetBool("ptj_infinite_memory", false);

            this.PrivateDungeons = this.GetBool("private_dungeons", false);
            this.EasySwitch      = this.GetBool("easy_switch", false);
            this.RandomFloors    = this.GetBool("random_floors", false);

            this.PartyExpBonus     = this.GetFloat("party_exp_bonus", 0);
            this.PartyMaxSize      = Math2.Clamp(1, 99, this.GetInt("party_max_size", 8));
            this.PartyQuestMinSize = Math2.Clamp(1, this.PartyMaxSize, this.GetInt("party_quest_min_size", 2));

            this.GoldQuestRewardRate = this.GetFloat("gold_quest_reward_rate", 100) / 100.0f;
        }
Exemplo n.º 29
0
        /// <summary>
        /// Uses WM, attacking targets.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="targetAreaId"></param>
        /// <param name="unkInt1"></param>
        /// <param name="unkInt2"></param>
        public void Use(Creature attacker, Skill skill, long targetAreaId, int unkInt1, int unkInt2)
        {
            var range   = this.GetRange(attacker, skill);
            var targets = attacker.GetTargetableCreaturesInRange(range, TargetableOptions.AddAttackRange);

            // Check targets
            if (targets.Count == 0)
            {
                Send.Notice(attacker, Localization.Get("There isn't a target nearby to use that on."));
                Send.SkillUseSilentCancel(attacker);
                return;
            }

            // Create actions
            var cap = new CombatActionPack(attacker, skill.Info.Id);

            var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId);

            aAction.Set(AttackerOptions.Result);
            aAction.Stun = CombatMastery.GetAttackerStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);

            cap.Add(aAction);

            var survived = new List <Creature>();
            var rnd      = RandomProvider.Get();

            // Check crit
            var crit      = false;
            var critSkill = attacker.Skills.Get(SkillId.CriticalHit);

            if (critSkill != null && critSkill.Info.Rank > SkillRank.Novice)
            {
                var critChance = Math2.Clamp(0, 30, attacker.GetTotalCritChance(0));
                if (rnd.NextDouble() * 100 < critChance)
                {
                    crit = true;
                }
            }

            // Handle all targets
            foreach (var target in targets)
            {
                target.StopMove();

                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                tAction.Delay = 300;                 // Usually 300, sometimes 350?

                // Calculate damage
                var damage = attacker.GetRndTotalDamage();
                damage *= skill.RankData.Var1 / 100f;

                // Elementals
                damage *= attacker.CalculateElementalDamageMultiplier(target);

                // Crit bonus
                if (crit)
                {
                    var bonus = critSkill.RankData.Var1 / 100f;
                    damage = damage + (damage * bonus);

                    tAction.Set(TargetOptions.Critical);
                }

                // Handle skills and reductions
                SkillHelper.HandleDefenseProtection(target, ref damage);
                Defense.Handle(aAction, tAction, ref damage);
                ManaShield.Handle(target, ref damage, tAction);
                HeavyStander.Handle(attacker, target, ref damage, tAction);

                // Clean Hit if not defended nor critical
                if (tAction.SkillId != SkillId.Defense && !tAction.Has(TargetOptions.Critical))
                {
                    tAction.Set(TargetOptions.CleanHit);
                }

                // Take damage if any is left
                if (damage > 0)
                {
                    target.TakeDamage(tAction.Damage = damage, attacker);
                }

                // Knock down on deadly
                if (target.Conditions.Has(ConditionsA.Deadly))
                {
                    tAction.Set(TargetOptions.KnockDown);
                    tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);
                }

                // Finish if dead, knock down if not defended
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.KnockDownFinish);
                }
                else if (tAction.SkillId != SkillId.Defense)
                {
                    tAction.Set(TargetOptions.KnockDown);
                }

                // Anger Management
                if (!target.IsDead)
                {
                    survived.Add(target);
                }

                // Stun and shove if not defended
                if (target.IsDead || tAction.SkillId != SkillId.Defense || target.Conditions.Has(ConditionsA.Deadly))
                {
                    tAction.Stun     = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);
                    target.Stability = Creature.MinStability;
                    attacker.Shove(target, KnockbackDistance);
                }

                // Add action
                cap.Add(tAction);
            }

            // Only select a random aggro if there is no aggro yet,
            // WM only aggroes one target at a time.
            if (survived.Count != 0 && attacker.Region.CountAggro(attacker) < 1)
            {
                var aggroTarget = survived.Random();
                aggroTarget.Aggro(attacker);
            }

            // Reduce life in old combat system
            if (!AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal"))
            {
                var amount = (attacker.LifeMax < 10 ? 2 : attacker.LifeMax / 10);
                attacker.ModifyLife(-amount);

                // TODO: Invincibility
            }

            // Spin it~
            Send.UseMotion(attacker, 8, 4);

            cap.Handle();

            Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2);

            skill.Stacks = 0;
        }
Exemplo n.º 30
0
        /// <summary>
        /// Uses LightningRod
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="packet"></param>
        public void Use(Creature attacker, Skill skill, Packet packet)
        {
            // Set full charge variable
            attacker.Temp.LightningRodFullCharge = (DateTime.Now >= attacker.Temp.LightningRodPrepareTime.AddMilliseconds(skill.RankData.Var3));

            // Get direction for target Area
            var direction = Mabi.MabiMath.ByteToRadian(attacker.Direction);

            var attackerPos = attacker.GetPosition();

            // Calculate polygon points
            var r     = MabiMath.ByteToRadian(attacker.Direction);
            var poe   = attackerPos.GetRelative(r, 800);
            var pivot = new Point(poe.X, poe.Y);
            var p1    = new Point(pivot.X - SkillLength / 2, pivot.Y - SkillWidth / 2);
            var p2    = new Point(pivot.X - SkillLength / 2, pivot.Y + SkillWidth / 2);
            var p3    = new Point(pivot.X + SkillLength / 2, pivot.Y + SkillWidth / 2);
            var p4    = new Point(pivot.X + SkillLength / 2, pivot.Y - SkillWidth / 2);

            p1 = this.RotatePoint(p1, pivot, r);
            p2 = this.RotatePoint(p2, pivot, r);
            p3 = this.RotatePoint(p3, pivot, r);
            p4 = this.RotatePoint(p4, pivot, r);

            // TargetProp
            var lProp = new Prop(280, attacker.RegionId, poe.X, poe.Y, MabiMath.ByteToRadian(attacker.Direction), 1f, 0f, "single");

            attacker.Region.AddProp(lProp);

            // Prepare Combat Actions
            var cap = new CombatActionPack(attacker, skill.Info.Id);

            var targetAreaId = new Location(attacker.RegionId, poe).ToLocationId();

            var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId);

            aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect);
            aAction.PropId = lProp.EntityId;
            cap.Add(aAction);

            // Get targets in Polygon - includes collission check
            var targets = attacker.Region.GetCreaturesInPolygon(p1, p2, p3, p4).Where(x => attacker.CanTarget(x) && !attacker.Region.Collisions.Any(attacker.GetPosition(), x.GetPosition())).ToList();

            var rnd = RandomProvider.Get();

            // Check crit
            var crit      = false;
            var critSkill = attacker.Skills.Get(SkillId.CriticalHit);

            if (critSkill != null && critSkill.Info.Rank > SkillRank.Novice)
            {
                var critChance = Math2.Clamp(0, 30, attacker.GetTotalCritChance(0));
                if (rnd.NextDouble() * 100 < critChance)
                {
                    crit = true;
                }
            }

            foreach (var target in targets)
            {
                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, SkillId.CombatMastery);
                tAction.Set(TargetOptions.None);
                tAction.AttackerSkillId = skill.Info.Id;
                cap.Add(tAction);

                var damage = attacker.GetRndMagicDamage(skill, skill.RankData.Var1, skill.RankData.Var2);

                // Add damage if the skill is fully charged
                var dmgMultiplier = skill.RankData.Var4 / 100f;
                if (attacker.Temp.LightningRodFullCharge)
                {
                    damage += (damage * dmgMultiplier);
                }

                // Critical Hit
                if (crit)
                {
                    var bonus = critSkill.RankData.Var1 / 100f;
                    damage = damage + (damage * bonus);

                    tAction.Set(TargetOptions.Critical);
                }

                // MDef and MProt
                SkillHelper.HandleMagicDefenseProtection(target, ref damage);

                // Mana Deflector
                var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction);

                // Mana Shield
                ManaShield.Handle(target, ref damage, tAction);

                // Apply Damage
                target.TakeDamage(tAction.Damage = damage, attacker);

                // Stun Time
                tAction.Stun = TargetStun;

                // Death or Knockback
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                    attacker.Shove(target, KnockbackDistance);
                }
                else
                {
                    // Always knock down
                    if (target.Is(RaceStands.KnockDownable))
                    {
                        tAction.Set(TargetOptions.KnockDown);
                        attacker.Shove(target, KnockbackDistance);
                    }
                }
            }
            cap.Handle();

            Send.Effect(attacker, Effect.LightningRod, (int)LightningRodEffect.Attack, poe.X, poe.Y);

            Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1);
            skill.Train(1);             // Use the Skill

            attacker.Region.RemoveProp(lProp);
        }