Пример #1
0
		/// <summary>
		/// Sends SkillInfo to creature's client.
		/// </summary>
		/// <param name="client"></param>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		public static void SkillInfo(Creature creature, Skill skill)
		{
			var packet = new Packet(Op.SkillInfo, creature.EntityId);
			packet.PutBin(skill.Info);

			creature.Client.Send(packet);
		}
Пример #2
0
		public void SetCooldown(Skill skill, DateTime endTime)
		{
			if (this._cooldownDictionary.ContainsKey(skill.Info.Id))
				this._cooldownDictionary[skill.Info.Id] = endTime;
			else
				this._cooldownDictionary.Add(skill.Info.Id, endTime);
		}
Пример #3
0
		/// <summary>
		/// Sends SkillRankUp to creature's client.
		/// </summary>
		/// <param name="client"></param>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		public static void SkillRankUp(Creature creature, Skill skill)
		{
			var packet = new Packet(Op.SkillRankUp, creature.EntityId);
			packet.PutByte(1);
			packet.PutBin(skill.Info);
			packet.PutFloat(0);

			creature.Client.Send(packet);
		}
Пример #4
0
		/// <summary>
		/// Adds skill silently. Returns false if the skill already exists,
		/// with a rank that's equal or higher.
		/// </summary>
		/// <param name="skill"></param>
		public bool Add(Skill skill)
		{
			if (this.Has(skill.Info.Id, skill.Info.Rank))
				return false;

			lock (_skills)
				_skills[skill.Info.Id] = skill;

			this.AddBonuses(skill);

			return true;
		}
Пример #5
0
		/// <summary>
		/// Adds skill silently. Returns false if the skill already exists,
		/// with a rank that's equal or higher.
		/// </summary>
		/// <param name="skill"></param>
		public bool Add(Skill skill)
		{
			// Cancel if skill exists with equal or higher rank.
			if (this.Has(skill.Info.Id, skill.Info.Rank))
				return false;

			var oldSkill = this.Get(skill.Info.Id);

			lock (_skills)
				_skills[skill.Info.Id] = skill;

			// Remove previous bonuses if skill is replaced
			if (oldSkill != null)
				this.RemoveBonuses(oldSkill);

			// Add new bonuses
			this.AddBonuses(skill);

			return true;
		}
Пример #6
0
		/// <summary>
		/// Cancels active skill.
		/// </summary>
		/// <remarks>
		/// SkillCancel is sent in any case, even if something goes wrong,
		/// like the method not being implemented. Unless no skill is active.
		/// </remarks>
		public void CancelActiveSkill()
		{
			if (this.ActiveSkill == null)
			{
				Log.Warning("CancelActiveSkill: Player '{0}' tried to cancel a skill, without one being active.", _creature.Name);
				return;
			}

			var handler = ChannelServer.Instance.SkillManager.GetHandler<ICancelable>(this.ActiveSkill.Info.Id);
			if (handler == null)
			{
				Log.Unimplemented("CancelActiveSkill: Skill handler or interface for '{0}'.", this.ActiveSkill.Info.Id);
				goto L_Cancel;
			}

			try
			{
				handler.Cancel(_creature, this.ActiveSkill);
			}
			catch (NotImplementedException)
			{
				Log.Unimplemented("CancelActiveSkill: Skill cancel method for '{0}'.", this.ActiveSkill.Info.Id);
				goto L_Cancel;
			}

		L_Cancel:
			this.ActiveSkill.Stacks = 0;

			Send.SkillCancel(_creature);

			this.ActiveSkill.State = SkillState.Canceled;
			this.ActiveSkill = null;

			_creature.Unlock(Locks.All);
		}
Пример #7
0
		/// <summary>
		/// Returns party production bonus for the given skill if creature
		/// is in a party.
		/// </summary>
		/// <remarks>
		// http://wiki.mabinogiworld.com/view/Party#Production_Bonus
		/// </remarks>
		/// <param name="skill"></param>
		/// <returns></returns>
		public float GetProductionPartyBonus(Skill skill)
		{
			// No bonus when not in party
			if (!this.IsInParty)
				return 0;

			var result = 0f;

			var members = this.Party.GetMembers();
			foreach (var member in members)
			{
				// Exclude this creature
				if (member == this)
					continue;

				// Exclude members that don't have Production Master rF+
				var productionMastery = member.Skills.Get(SkillId.ProductionMastery);
				if (productionMastery == null || productionMastery.Info.Rank < SkillRank.RF)
					continue;

				// Exclude members that don't have the production skill on rF+
				var memberSkill = member.Skills.Get(skill.Info.Id);
				if (memberSkill == null || memberSkill.Info.Rank < SkillRank.RF)
					continue;

				// +1% if member has the skill on a lower rank
				if (memberSkill.Info.Rank < skill.Info.Rank)
					result += 1;
				// +5% if member has the skill on same or higher rank
				else
					result += 5;
			}

			// Cap at 35
			return Math.Min(35, result);
		}
Пример #8
0
        /// <summary>
        /// Adds skill at rank, or updates it.
        /// Sends appropriate packets.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="rank"></param>
        public void Give(SkillId id, SkillRank rank)
        {
            var skill = this.Get(id);
            if (skill == null)
            {
                this.Add(skill = new Skill(_creature, id, rank, _creature.RaceId));

                Send.SkillInfo(_creature, skill);
                if (_creature.Region != Region.Limbo)
                    Send.RankUp(_creature);

                ChannelServer.Instance.Events.OnSkillRankChanged(_creature, skill);
            }
            else
            {
                this.RemoveBonuses(skill);
                skill.ChangeRank(rank);

                Send.SkillRankUp(_creature, skill);
                if (_creature.Region != Region.Limbo)
                    Send.RankUp(_creature, skill.Info.Id);

                this.AddBonuses(skill);
            }

            Send.StatUpdate(_creature, StatUpdateType.Private,
                Stat.Str, Stat.Int, Stat.Dex, Stat.Will, Stat.Luck,
                Stat.Life, Stat.LifeInjured, Stat.LifeMaxMod, Stat.LifeMax, Stat.Mana, Stat.ManaMaxMod, Stat.ManaMax, Stat.Stamina, Stat.Hunger, Stat.StaminaMaxMod, Stat.StaminaMax
            );
            Send.StatUpdate(_creature, StatUpdateType.Public, Stat.Life, Stat.LifeInjured, Stat.LifeMaxMod, Stat.LifeMax);

            this.RankChanged.Raise(_creature, skill);
        }
Пример #9
0
		/// <summary>
		/// Calculates random base Magic damage for skill, using the given values.
		/// </summary>
		/// <remarks>
		/// http://wiki.mabinogiworld.com/view/Stats#Magic_Damage
		/// </remarks>
		/// <param name="skill"></param>
		/// <param name="baseMin"></param>
		/// <param name="baseMax"></param>
		/// <returns></returns>
		public float GetRndMagicDamage(Skill skill, float baseMin, float baseMax)
		{
			var rnd = RandomProvider.Get();

			var baseDamage = rnd.Between(baseMin, baseMax);
			var factor = rnd.Between(skill.RankData.FactorMin, skill.RankData.FactorMax);

			var wandBonus = 0f;
			var chargeMultiplier = 0f;

			if (skill.Info.Id == SkillId.Icebolt && this.RightHand != null && this.RightHand.HasTag("/ice_wand/"))
				wandBonus = 5;
			else if (skill.Info.Id == SkillId.Firebolt && this.RightHand != null && this.RightHand.HasTag("/fire_wand/"))
				wandBonus = 5;
			else if (skill.Info.Id == SkillId.Lightningbolt && this.RightHand != null && this.RightHand.HasTag("/lightning_wand/"))
				wandBonus = 3.5f;

			if (skill.Info.Id == SkillId.Firebolt || skill.Info.Id == SkillId.IceSpear || skill.Info.Id == SkillId.HailStorm)
				chargeMultiplier = skill.Stacks;

			// TODO: Enchants

			var damage = (float)(baseDamage + Math.Floor(wandBonus * (1 + chargeMultiplier)) + (factor * this.MagicAttack));

			return (damage * this.GetRndMagicBalance());
		}
Пример #10
0
		public bool IsOnCooldown(Skill skill)
		{
			if (this._cooldownDictionary.ContainsKey(skill.Info.Id))
				return (DateTime.Now < this._cooldownDictionary[skill.Info.Id]);
			return false;
		}
Пример #11
0
		/// <summary>
		/// Raised when one of the inventory's creature's skill's rank changes.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		private void OnCreatureSkillRankChanged(Creature creature, Skill skill)
		{
			this.UpdateStatBonuses();
		}
Пример #12
0
        /// <summary>
        /// Sends SkillTrainingUp to creature's client.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="skill"></param>
        /// <param name="exp">Exp gained</param>
        public static void SkillTrainingUp(Creature creature, Skill skill, float exp, string bonus = "")
        {
            var packet = new Packet(Op.SkillTrainingUp, creature.EntityId);
            packet.PutBin(skill.Info);
            packet.PutFloat(exp);
            packet.PutByte(1);
            packet.PutString(bonus); // (Specialized Skill Bonus: x2)

            creature.Client.Send(packet);
        }
Пример #13
0
        /// <summary>
        /// Sends SkillStop to creature's client or broadcasts it if skill is
        /// of type "BroadcastStartStop".
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="skill"></param>
        /// <param name="unkByte"></param>
        public static void SkillStop(Creature creature, Skill skill, byte unkByte)
        {
            var packet = new Packet(Op.SkillStop, creature.EntityId);
            packet.PutUShort((ushort)skill.Info.Id);
            packet.PutByte(unkByte);

            if (skill.Data.Type != SkillType.BroadcastStartStop)
                creature.Client.Send(packet);
            else
                creature.Region.Broadcast(packet, creature);
        }
Пример #14
0
		/// <summary>
		/// Calculates and sets splash damage reductions and bonuses against splashTarget.
		/// </summary>
		/// <param name="splashTarget"></param>
		/// <param name="damageSplash"></param>
		/// <param name="skill"></param>
		/// <param name="critSkill"></param>
		/// <param name="aAction"></param>
		/// <param name="tAction"></param>
		/// <param name="tSplashAction"></param>
		public void CalculateSplashDamage(Creature splashTarget, ref float damageSplash, Skill skill, Skill critSkill, AttackerAction aAction, TargetAction tAction, TargetAction tSplashAction, Item weapon = null)
		{
			//Splash Damage Reduction
			if (skill.Info.Id == SkillId.Smash)
				damageSplash *= skill.Info.Rank < SkillRank.R1 ? 0.1f : 0.2f;
			else
				damageSplash *= weapon != null ? weapon.Data.SplashDamage : 0f;

			// Critical Hit
			if (critSkill != null && tAction.Has(TargetOptions.Critical))
			{
				// Add crit bonus
				var bonus = critSkill.RankData.Var1 / 100f;
				damageSplash = damageSplash + (damageSplash * bonus);

				// Set splashTarget option
				tSplashAction.Set(TargetOptions.Critical);
			}

			var maxDamageSplash = damageSplash; //Damage without Defense and Protection
			// Subtract splashTarget def/prot
			SkillHelper.HandleDefenseProtection(splashTarget, ref damageSplash);

			// Defense
			Channel.Skills.Combat.Defense.Handle(aAction, tSplashAction, ref damageSplash);

			// Mana Shield
			ManaShield.Handle(splashTarget, ref damageSplash, tSplashAction, maxDamageSplash);

			if (damageSplash <= 0f)
				damageSplash = 1f;
		}
Пример #15
0
		/// <summary>
		/// Updates reach rank objectives.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		private void OnSkillRankChanged(Creature creature, Skill skill)
		{
			if (this.CheckPrerequisites(creature))
				creature.Quests.SendOwl(this.Id);

			this.CheckCurrentObjective(creature);
		}
Пример #16
0
		/// <summary>
		/// Updates UseSkill objectives.
		/// </summary>
		/// <param name="args"></param>
		private void OnPlayerUsedSkill(Creature creature, Skill skill)
		{
			if (creature == null || skill == null)
				return;

			var quests = creature.Quests.GetAllIncomplete(this.Id);
			foreach (var quest in quests)
			{
				var progress = quest.CurrentObjectiveOrLast;
				if (progress == null) return;

				var objective = this.Objectives[progress.Ident];
				if (objective == null || objective.Type != ObjectiveType.UseSkill) return;

				var useSkillObjective = (objective as QuestObjectiveUseSkill);
				if (!progress.Done && skill.Info.Id == useSkillObjective.Id)
				{
					quest.SetDone(progress.Ident);
					Send.QuestUpdate(creature, quest);
				}
			}
		}
Пример #17
0
		/// <summary>
		/// Calculates random base Magic damage for skill, using the given values.
		/// </summary>
		/// <remarks>
		/// http://wiki.mabinogiworld.com/view/Stats#Magic_Damage
		/// </remarks>
		/// <param name="skill"></param>
		/// <param name="baseMin"></param>
		/// <param name="baseMax"></param>
		/// <returns></returns>
		public float GetRndMagicDamage(Skill skill, float baseMin, float baseMax)
		{
			var rnd = RandomProvider.Get();

			// Base damage
			float min = baseMin;
			float max = baseMax;

			// Bonus
			var factor = rnd.Between(skill.RankData.FactorMin, skill.RankData.FactorMax);
			var totalMagicAttack = this.MagicAttack + this.MagicAttackMod;

			var wandBonus = 0f;
			var chargeMultiplier = 0f;

			if (skill.Info.Id == SkillId.Icebolt && this.RightHand != null && this.RightHand.HasTag("/ice_wand/"))
				wandBonus = 5;
			else if (skill.Info.Id == SkillId.Firebolt && this.RightHand != null && this.RightHand.HasTag("/fire_wand/"))
				wandBonus = 5;
			else if (skill.Info.Id == SkillId.Lightningbolt && this.RightHand != null && this.RightHand.HasTag("/lightning_wand/"))
				wandBonus = 3.5f;

			if (skill.Info.Id == SkillId.Firebolt || skill.Info.Id == SkillId.IceSpear || skill.Info.Id == SkillId.HailStorm)
				chargeMultiplier = skill.Stacks;

			var bonusDamage = (float)Math.Floor(wandBonus * (1 + chargeMultiplier)) + (factor * totalMagicAttack);
			min += bonusDamage;
			max += bonusDamage;

			// Random balance multiplier
			var multiplier = this.GetRndMagicBalance() / 100f;

			if (min > max)
				min = max;

			return (min + (max - min) * multiplier);
		}
Пример #18
0
		/// <summary>
		/// Calculates and returns general production skill success chance.
		/// </summary>
		/// <remarks>
		/// Unofficial, but seems to work fine in most cases.
		/// Dex bonus: http://mabination.com/threads/57123-Chaos-Life-Skill-Guide-Refining
		/// </remarks>
		/// <returns></returns>
		public float GetProductionSuccessChance(Skill skill, ProductionCategory category, int baseChance, int rainBonus)
		{
			// Base
			float result = baseChance;
			if (skill.Info.Id != SkillId.PotionMaking && skill.Info.Id != SkillId.Milling)
				result += (this.Dex - 60) * (baseChance / 300f);

			// Production Mastery bonus
			var pm = this.Skills.Get(SkillId.ProductionMastery);
			if (pm != null)
				result += (byte)pm.Info.Rank;

			// Weather bonus
			if (ChannelServer.Instance.Weather.GetWeatherType(this.RegionId) == WeatherType.Rain)
			{
				if (category == ProductionCategory.Weaving)
					result += rainBonus * 2;
				else
					result *= 1 + (rainBonus / 100f);
			}

			// Party bonus
			result += this.GetProductionPartyBonus(skill);

			// Monday: Increase in success rate for production skills.
			// +10%, bonus is unofficial.
			if (ErinnTime.Now.Month == ErinnMonth.AlbanEiler)
				result += 5;

			return Math2.Clamp(0, 99, result);
		}
Пример #19
0
		/// <summary>
		/// Updates reach rank objectives.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		private void OnSkillRankChanged(Creature creature, Skill skill)
		{
			this.CheckCurrentObjective(creature);
		}
Пример #20
0
        /// <summary>
        /// Adds stat bonuses for skill's rank to creature.
        /// </summary>
        /// <param name="skill"></param>
        public void AddBonuses(Skill skill)
        {
            _creature.StrBaseSkill += skill.RankData.StrTotal;
            _creature.IntBaseSkill += skill.RankData.IntTotal;
            _creature.DexBaseSkill += skill.RankData.DexTotal;
            _creature.WillBaseSkill += skill.RankData.WillTotal;
            _creature.LuckBaseSkill += skill.RankData.LuckTotal;
            _creature.LifeMaxBaseSkill += skill.RankData.LifeTotal;
            _creature.Life += skill.RankData.LifeTotal;
            _creature.ManaMaxBaseSkill += skill.RankData.ManaTotal;
            _creature.Mana += skill.RankData.ManaTotal;
            _creature.StaminaMaxBaseSkill += skill.RankData.StaminaTotal;
            _creature.Stamina += skill.RankData.StaminaTotal;

            if (skill.Info.Id == SkillId.CombatMastery)
            {
                _creature.StatMods.Add(Stat.LifeMaxMod, skill.RankData.Var3, StatModSource.SkillRank, (int)skill.Info.Id);
                _creature.Life += skill.RankData.Var3;
            }
            else if (skill.Info.Id == SkillId.MagicMastery)
            {
                _creature.StatMods.Add(Stat.ManaMaxMod, skill.RankData.Var1, StatModSource.SkillRank, (int)skill.Info.Id);
                _creature.Mana += skill.RankData.Var1;
            }
            else if (skill.Info.Id == SkillId.Defense)
            {
                _creature.StatMods.Add(Stat.DefenseBaseMod, skill.RankData.Var1, StatModSource.SkillRank, (int)skill.Info.Id);
            }

            this.UpdateHighestSkills();
        }
Пример #21
0
		/// <summary>
		/// Calculates and returns general production skill success chance.
		/// </summary>
		/// <remarks>
		/// Unofficial, but seems to work fine in most cases.
		/// Dex bonus: http://mabination.com/threads/57123-Chaos-Life-Skill-Guide-Refining
		/// </remarks>
		/// <returns></returns>
		public float GetProductionSuccessChance(Skill skill, ProductionCategory category, int baseChance, int rainBonus)
		{
			// Base
			float result = baseChance;
			if (skill.Info.Id != SkillId.PotionMaking && skill.Info.Id != SkillId.Milling)
				result += (this.Dex - 60) * (baseChance / 300f);

			// Production Mastery bonus
			var pm = this.Skills.Get(SkillId.ProductionMastery);
			if (pm != null)
				result += (byte)pm.Info.Rank;

			// Weather bonus
			if (ChannelServer.Instance.Weather.GetWeatherType(this.RegionId) == WeatherType.Rain)
			{
				if (category == ProductionCategory.Weaving)
					result += rainBonus * 2;
				else
					result *= 1 + (rainBonus / 100f);
			}

			// Party bonus
			result += this.GetProductionPartyBonus(skill);

			return Math2.Clamp(0, 99, result);
		}
Пример #22
0
        /// <summary>
        /// Removes stat bonuses for skill's rank from creature.
        /// (To be run before changing a skills rank.)
        /// </summary>
        /// <param name="skill"></param>
        private void RemoveBonuses(Skill skill)
        {
            _creature.StrBaseSkill -= skill.RankData.StrTotal;
            _creature.IntBaseSkill -= skill.RankData.IntTotal;
            _creature.DexBaseSkill -= skill.RankData.DexTotal;
            _creature.WillBaseSkill -= skill.RankData.WillTotal;
            _creature.LuckBaseSkill -= skill.RankData.LuckTotal;
            _creature.Life -= skill.RankData.LifeTotal;
            _creature.LifeMaxBaseSkill -= skill.RankData.LifeTotal;
            _creature.Mana -= skill.RankData.ManaTotal;
            _creature.ManaMaxBaseSkill -= skill.RankData.ManaTotal;
            _creature.Stamina -= skill.RankData.StaminaTotal;
            _creature.StaminaMaxBaseSkill -= skill.RankData.StaminaTotal;

            if (skill.Info.Id == SkillId.CombatMastery)
            {
                _creature.Life -= skill.RankData.Var3;
                _creature.StatMods.Remove(Stat.LifeMaxMod, StatModSource.SkillRank, skill.Info.Id);
            }
            else if (skill.Info.Id == SkillId.MagicMastery)
            {
                _creature.Mana -= skill.RankData.Var1;
                _creature.StatMods.Remove(Stat.ManaMaxMod, StatModSource.SkillRank, skill.Info.Id);
            }
            else if (skill.Info.Id == SkillId.Defense)
            {
                _creature.StatMods.Remove(Stat.DefenseBaseMod, StatModSource.SkillRank, skill.Info.Id);
            }

            this.UpdateHighestSkills();
        }
Пример #23
0
        /// <summary>
        /// Updates reach rank objectives.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="killer"></param>
        private void OnSkillRankChanged(Creature creature, Skill skill)
        {
            if (creature == null || skill == null) return;

            var quest = creature.Quests.Get(this.Id);
            if (quest == null) return;

            var progress = quest.CurrentObjective;
            if (progress == null) return;

            var objective = this.Objectives[progress.Ident] as QuestObjectiveReachRank;
            if (objective == null || objective.Type != ObjectiveType.ReachRank) return;

            if (skill.Info.Id != objective.Id || skill.Info.Rank < objective.Rank) return;

            quest.SetDone(progress.Ident);

            Send.QuestUpdate(creature, quest);
        }