Beispiel #1
0
		/// <summary>
		/// Completes skill, dropping a cobweb.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		/// <param name="packet"></param>
		public void Complete(Creature creature, Skill skill, Packet packet)
		{
			var cobweb = new Item(ItemId);
			cobweb.Drop(creature.Region, creature.GetPosition(), 200, creature, true);

			Send.SkillComplete(creature, skill.Info.Id);
		}
Beispiel #2
0
		/// <summary>
		/// Completes skill, dropping a cobweb.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		/// <param name="packet"></param>
		public void Complete(Creature creature, Skill skill, Packet packet)
		{
			var cobweb = new Item(ItemId);
			cobweb.Drop(creature.Region, creature.GetPosition().GetRandomInRange(200, RandomProvider.Get()));

			Send.SkillComplete(creature, skill.Info.Id);
		}
Beispiel #3
0
		/// <summary>
		/// Kills creature.
		/// </summary>
		/// <param name="killer"></param>
		public virtual void Kill(Creature killer)
		{
			if (this.Conditions.Has(ConditionsA.Deadly))
				this.Conditions.Deactivate(ConditionsA.Deadly);
			this.Activate(CreatureStates.Dead);

			//Send.SetFinisher(this, killer.EntityId);
			//Send.SetFinisher2(this);
			Send.IsNowDead(this);
			Send.SetFinisher(this, 0);

			ChannelServer.Instance.Events.OnCreatureKilled(this, killer);
			if (killer != null && killer.IsPlayer)
				ChannelServer.Instance.Events.OnCreatureKilledByPlayer(this, killer);
			this.Death.Raise(this, killer);

			if (this.Skills.ActiveSkill != null)
				this.Skills.CancelActiveSkill();

			var rnd = RandomProvider.Get();
			var pos = this.GetPosition();

			// Gold
			if (rnd.NextDouble() < ChannelServer.Instance.Conf.World.GoldDropChance)
			{
				// Random base amount
				var amount = rnd.Next(this.Drops.GoldMin, this.Drops.GoldMax + 1);

				if (amount > 0)
				{
					// Lucky Finish
					var luckyChance = rnd.NextDouble();
					if (luckyChance < ChannelServer.Instance.Conf.World.HugeLuckyFinishChance)
					{
						amount *= 100;

						if (amount >= 2000) killer.Titles.Enable(23); // the Lucky

						Send.CombatMessage(killer, Localization.Get("Huge Lucky Finish!!"));
						Send.Notice(killer, Localization.Get("Huge Lucky Finish!!"));
					}
					else if (luckyChance < ChannelServer.Instance.Conf.World.BigLuckyFinishChance)
					{
						amount *= 5;

						if (amount >= 2000) killer.Titles.Enable(23); // the Lucky

						Send.CombatMessage(killer, Localization.Get("Big Lucky Finish!!"));
						Send.Notice(killer, Localization.Get("Big Lucky Finish!!"));
					}
					else if (luckyChance < ChannelServer.Instance.Conf.World.LuckyFinishChance)
					{
						amount *= 2;

						if (amount >= 2000) killer.Titles.Enable(23); // the Lucky

						Send.CombatMessage(killer, Localization.Get("Lucky Finish!!"));
						Send.Notice(killer, Localization.Get("Lucky Finish!!"));
					}

					// Drop rate muliplicator
					amount = Math.Min(21000, (int)(amount * ChannelServer.Instance.Conf.World.GoldDropRate));

					// Drop stack for stack
					var i = 0;
					var pattern = (amount == 21000);
					do
					{
						Position dropPos;
						if (!pattern)
						{
							dropPos = pos.GetRandomInRange(50, rnd);
						}
						else
						{
							dropPos = new Position(pos.X + CreatureDrops.MaxGoldPattern[i, 0], pos.Y + CreatureDrops.MaxGoldPattern[i, 1]);
							i++;
						}

						var gold = Item.CreateGold(Math.Min(1000, amount));
						gold.Drop(this.Region, pos);

						amount -= gold.Info.Amount;
					}
					while (amount > 0);
				}
			}

			// Drops
			var dropped = new HashSet<int>();
			foreach (var drop in this.Drops.Drops)
			{
				if (drop == null || !AuraData.ItemDb.Exists(drop.ItemId))
				{
					Log.Warning("Creature.Kill: Invalid drop '{0}' from '{1}'.", (drop == null ? "null" : drop.ItemId.ToString()), this.RaceId);
					continue;
				}

				if (rnd.NextDouble() * 100 < drop.Chance * ChannelServer.Instance.Conf.World.DropRate)
				{
					// Only drop any item once
					if (dropped.Contains(drop.ItemId))
						continue;

					var dropPos = pos.GetRandomInRange(50, rnd);

					var item = new Item(drop);
					item.Drop(this.Region, pos);

					dropped.Add(drop.ItemId);
				}
			}

			foreach (var item in this.Drops.StaticDrops)
				item.Drop(this.Region, pos);

			this.Drops.ClearStaticDrops();
		}
Beispiel #4
0
		/// <summary>
		/// Completes skill, handling the whole item gathering process.
		/// </summary>
		/// <param name="creature"></param>
		/// <param name="skill"></param>
		/// <param name="packet"></param>
		public void Complete(Creature creature, Skill skill, Packet packet)
		{
			var entityId = packet.GetLong();
			var collectId = packet.GetInt();

			var rnd = RandomProvider.Get();

			// Check data
			var collectData = AuraData.CollectingDb.Find(collectId);
			if (collectData == null)
			{
				Log.Warning("Gathering.Complete: Unknown collect id '{0}'", collectId);
				this.DoComplete(creature, entityId, collectId, false, 1);
				return;
			}

			// Check tools
			if (!this.CheckHand(collectData.RightHand, creature.RightHand) || !this.CheckHand(collectData.LeftHand, creature.LeftHand))
			{
				Log.Warning("Gathering.Complete: Collecting using invalid tool.", collectId);
				this.DoComplete(creature, entityId, collectId, false, 1);
				return;
			}

			// Reduce tool's durability
			if (creature.RightHand != null && collectData.DurabilityLoss > 0)
			{
				var reduce = collectData.DurabilityLoss;

				// Half dura loss if blessed
				if (creature.RightHand.IsBlessed)
					reduce = Math.Max(1, reduce / 2);

				creature.RightHand.Durability -= reduce;
				Send.ItemDurabilityUpdate(creature, creature.RightHand);
				Send.ItemExpUpdate(creature, creature.RightHand);
			}

			// Get target (either prop or creature)
			var targetEntity = this.GetTargetEntity(creature.Region, entityId);

			// Check target
			if (targetEntity == null || !targetEntity.HasTag(collectData.Target))
			{
				Log.Warning("Gathering.Complete: Collecting from invalid entity '{0:X16}'", entityId);
				this.DoComplete(creature, entityId, collectId, false, 1);
				return;
			}

			// Check position
			var creaturePosition = creature.GetPosition();
			var targetPosition = targetEntity.GetPosition();

			if (!creaturePosition.InRange(targetPosition, MaxDistance))
			{
				Send.Notice(creature, Localization.Get("Your arms are too short to reach that from here."));
				this.DoComplete(creature, entityId, collectId, false, 1);
				return;
			}

			// Check if moved
			if (creature.Temp.GatheringTargetPosition.GetDistance(targetPosition) > MaxMoveDistance)
			{
				this.DoComplete(creature, entityId, collectId, false, 3);
				return;
			}

			// Determine success
			var successChance = this.GetSuccessChance(creature, collectData);
			var collectSuccess = rnd.NextDouble() * 100 < successChance;

			// Get reduction
			var reduction = collectData.ResourceReduction;
			if (ChannelServer.Instance.Weather.GetWeatherType(creature.RegionId) == WeatherType.Rain)
				reduction += collectData.ResourceReductionRainBonus;

			// Check resource
			if (targetEntity is Prop)
			{
				var targetProp = (Prop)targetEntity;

				// Check if prop was emptied
				if (targetProp.State == "empty")
				{
					this.DoComplete(creature, entityId, collectId, false, 2);
					return;
				}

				// Regenerate resources
				targetProp.Resource += (float)((DateTime.Now - targetProp.LastCollect).TotalMinutes * collectData.ResourceRecovering);

				// Fail if currently no resources available
				if (targetProp.Resource < reduction)
				{
					this.DoComplete(creature, entityId, collectId, false, 2);
					return;
				}

				// Reduce resources on success
				if (collectSuccess)
				{
					if (!ChannelServer.Instance.Conf.World.InfiniteResources)
						targetProp.Resource -= reduction;
					targetProp.LastCollect = DateTime.Now;
				}

				// Set prop's state to "empty" if it was emptied and is not
				// regenerating resources.
				if (collectData.ResourceRecovering == 0 && targetProp.Resource < reduction)
					targetProp.SetState("empty");
			}
			else
			{
				var targetCreature = (Creature)targetEntity;

				// Fail if creature doesn't have enough mana
				if (targetCreature.Mana < reduction)
				{
					this.DoComplete(creature, entityId, collectId, false, 2);
					return;
				}

				if (collectSuccess && !ChannelServer.Instance.Conf.World.InfiniteResources)
					targetCreature.Mana -= reduction;
			}

			// Drop
			var receiveItemId = 0;
			if (collectSuccess)
			{
				// Product
				var itemId = receiveItemId = collectData.GetRndProduct(rnd);
				if (itemId != 0)
				{
					var item = new Item(itemId);
					if (collectData.Source == 0)
					{
						// Try to drop item in the middle, between creature
						// and target. If there already is an item on that
						// position, find another random one.
						var pos = targetPosition.GetRelative(creaturePosition, -FeetDropDistance);
						for (int i = 0; creature.Region.GetItem(a => a.GetPosition() == pos) != null && i < 10; ++i)
							pos = creaturePosition.GetRandomInRange(DropRange, rnd);

						item.Drop(creature.Region, pos, 0, creature, false);
					}
					else
					{
						creature.Inventory.Remove(creature.RightHand);
						creature.Inventory.Add(item, creature.Inventory.RightHandPocket);
					}
				}

				// Product2
				itemId = collectData.GetRndProduct2(rnd);
				if (itemId != 0)
				{
					var item = new Item(itemId);
					item.Drop(creature.Region, creaturePosition, DropRange, creature, false);
				}
			}
			// TODO: Figure out how fail products work.
			//else
			//{
			//	// FailProduct
			//	var itemId = receiveItemId = collectData.GetRndFailProduct(rnd);
			//	if (itemId != 0)
			//	{
			//		var item = new Item(itemId);
			//		if (collectData.Source == 0)
			//			item.Drop(creature.Region, creaturePosition, DropRange);
			//		else
			//		{
			//			creature.Inventory.Remove(creature.RightHand);
			//			creature.Inventory.Add(item, creature.Inventory.RightHandPocket);
			//		}
			//	}

			//	// FailProduct2
			//	itemId = collectData.GetRndFailProduct2(rnd);
			//	if (itemId != 0)
			//	{
			//		var item = new Item(itemId);
			//		item.Drop(creature.Region, creaturePosition.GetRandomInRange(DropRange, rnd));
			//	}
			//}

			// Events
			ChannelServer.Instance.Events.OnCreatureGathered(new CollectEventArgs(creature, collectData, collectSuccess, receiveItemId));

			// Complete
			this.DoComplete(creature, entityId, collectId, collectSuccess, 0);
		}
Beispiel #5
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
			// TODO: update prop state method
			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 && !ChannelServer.Instance.Conf.World.NoDurabilityLoss)
			{
				var reduce = 15;

				// Half dura loss if blessed
				if (creature.RightHand.IsBlessed)
					reduce = Math.Max(1, reduce / 2);

				creature.RightHand.Durability -= reduce;
				Send.ItemDurabilityUpdate(creature, creature.RightHand);

				// 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;

				// Create item
				item = new Item(creature.Temp.FishingDrop);

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

					// Random fish size, unofficial
					if (fish.SizeMin + fish.SizeMax != 0)
					{
						var min = fish.SizeMin + (int)Math.Max(0, (item.Data.BaseSize - fish.SizeMin) / 100f * skill.RankData.Var4);
						var max = fish.SizeMax;

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

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

				// Set equipment durability
				if (item.HasTag("/equip/") && item.OptionInfo.DurabilityMax >= 1)
					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().GetRandomInRange(100, rnd));

				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);

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

			// Next round
			this.StartFishing(creature, 6000);
		}
Beispiel #6
0
		/// <summary>
		/// Handles dropping of items in given collection.
		/// </summary>
		/// <param name="dataCollection"></param>
		private void DropItems(Creature killer, Random rnd, Position pos, IEnumerable<DropData> dataCollection)
		{
			var dropped = new HashSet<int>();
			foreach (var dropData in dataCollection)
			{
				if (dropData == null || !AuraData.ItemDb.Exists(dropData.ItemId))
				{
					Log.Warning("Creature.Kill: Invalid drop '{0}' from '{1}'.", (dropData == null ? "null" : dropData.ItemId.ToString()), this.RaceId);
					continue;
				}

				var dropRate = dropData.Chance;
				var dropChance = rnd.NextDouble() * 100;
				var month = ErinnTime.Now.Month;

				// Add global bonus
				float itemDropBonus;
				string bonuses;
				if (ChannelServer.Instance.GameEventManager.GlobalBonuses.GetBonusMultiplier(GlobalBonusStat.ItemDropRate, out itemDropBonus, out bonuses))
					dropRate *= itemDropBonus;

				// Tuesday: Increase in dungeon item drop rate.
				// Wednesday: Increase in item drop rate from animals and nature.
				// +50%, bonus is unofficial.
				if ((month == ErinnMonth.Baltane && this.Region.IsDungeon) || (month == ErinnMonth.AlbanHeruin && !this.Region.IsDungeon))
					dropRate *= 1.5f;

				// Add conf
				dropRate *= ChannelServer.Instance.Conf.World.DropRate;

				if (dropChance < dropRate)
				{
					// Only drop any item once
					if (dropped.Contains(dropData.ItemId))
						continue;

					var item = new Item(dropData);
					item.ModifyEquipStats(rnd);
					item.Drop(this.Region, pos, Item.DropRadius, killer, false);

					dropped.Add(dropData.ItemId);
				}
			}
		}
Beispiel #7
0
		/// <summary>
		/// Returns prop behavior for dropping.
		/// </summary>
		/// <param name="dropType"></param>
		/// <returns></returns>
		public static PropFunc GetDropBehavior(int dropType)
		{
			return (creature, prop) =>
			{
				if (RandomProvider.Get().NextDouble() > ChannelServer.Instance.Conf.World.PropDropChance)
					return;

				var dropInfo = AuraData.PropDropDb.Find(dropType);
				if (dropInfo == null)
				{
					Log.Warning("GetDropBehavior: Unknown prop drop type '{0}'.", dropType);
					return;
				}

				var rnd = RandomProvider.Get();

				// Get random item from potential drops
				var dropItemInfo = dropInfo.GetRndItem(rnd);
				var rndAmount = (dropItemInfo.Amount > 1 ? (ushort)rnd.Next(1, dropItemInfo.Amount) : (ushort)1);

				var item = new Item(dropItemInfo.ItemClass);
				item.Info.Amount = rndAmount;
				item.Drop(prop.Region, creature.GetPosition(), creature, false);
			};
		}
Beispiel #8
0
        /// <summary>
        /// Drops creature's drop items.
        /// </summary>
        /// <param name="killer"></param>
        /// <param name="rnd"></param>
        /// <param name="pos"></param>
        private void DropItems(Creature killer, Random rnd, Position pos)
        {
            // Normal
            var dropped = new HashSet<int>();
            foreach (var dropData in this.Drops.Drops)
            {
                if (dropData == null || !AuraData.ItemDb.Exists(dropData.ItemId))
                {
                    Log.Warning("Creature.Kill: Invalid drop '{0}' from '{1}'.", (dropData == null ? "null" : dropData.ItemId.ToString()), this.RaceId);
                    continue;
                }

                var dropRate = dropData.Chance * ChannelServer.Instance.Conf.World.DropRate;
                var dropChance = rnd.NextDouble() * 100;
                var month = ErinnTime.Now.Month;

                // Tuesday: Increase in dungeon item drop rate.
                // Wednesday: Increase in item drop rate from animals and nature.
                // +50%, bonus is unofficial.
                if ((month == ErinnMonth.Baltane && this.Region.IsDungeon) || (month == ErinnMonth.AlbanHeruin && !this.Region.IsDungeon))
                    dropRate *= 1.5f;

                if (dropChance < dropRate)
                {
                    // Only drop any item once
                    if (dropped.Contains(dropData.ItemId))
                        continue;

                    var item = new Item(dropData);

                    // Equip stat modification
                    // http://wiki.mabinogiworld.com/view/Category:Weapons
                    if (item.HasTag("/righthand/weapon/|/twohand/weapon/"))
                    {
                        var num = rnd.Next(100);

                        // Durability
                        if (num == 0)
                            item.OptionInfo.DurabilityMax += 4000;
                        else if (num <= 5)
                            item.OptionInfo.DurabilityMax += 3000;
                        else if (num <= 10)
                            item.OptionInfo.DurabilityMax += 2000;
                        else if (num <= 25)
                            item.OptionInfo.DurabilityMax += 1000;

                        // Attack
                        if (num == 0)
                        {
                            item.OptionInfo.AttackMin += 3;
                            item.OptionInfo.AttackMax += 3;
                        }
                        else if (num <= 30)
                        {
                            item.OptionInfo.AttackMin += 2;
                            item.OptionInfo.AttackMax += 2;
                        }
                        else if (num <= 60)
                        {
                            item.OptionInfo.AttackMin += 1;
                            item.OptionInfo.AttackMax += 1;
                        }

                        // Crit
                        if (num == 0)
                            item.OptionInfo.Critical += 3;
                        else if (num <= 30)
                            item.OptionInfo.Critical += 2;
                        else if (num <= 60)
                            item.OptionInfo.Critical += 1;

                        // Balance
                        if (num == 0)
                            item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 12);
                        else if (num <= 10)
                            item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 10);
                        else if (num <= 30)
                            item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 8);
                        else if (num <= 50)
                            item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 6);
                        else if (num <= 70)
                            item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 4);
                        else if (num <= 90)
                            item.OptionInfo.Balance = (byte)Math.Max(0, item.OptionInfo.Balance - 2);
                    }

                    item.Drop(this.Region, pos, Item.DropRadius, killer, false);

                    dropped.Add(dropData.ItemId);
                }
            }

            // Static
            foreach (var item in this.Drops.StaticDrops)
                item.Drop(this.Region, pos, Item.DropRadius, killer, false);

            this.Drops.ClearStaticDrops();
        }