/// <summary> /// Reduces weapon's durability and increases its proficiency. /// Only updates weapon type items that are not null. /// </summary> /// <param name="creature"></param> /// <param name="weapon"></param> public static void UpdateWeapon(Creature attacker, Creature target, params Item[] weapons) { if (attacker == null) return; var rnd = RandomProvider.Get(); foreach (var weapon in weapons.Where(a => a != null && a.IsTrainableWeapon)) { // Durability if (!ChannelServer.Instance.Conf.World.NoDurabilityLoss) { var reduce = rnd.Next(1, 30); // Half dura loss if blessed if (weapon.IsBlessed) reduce = Math.Max(1, reduce / 2); attacker.UpdateTool(weapon, reduce); weapon.Durability -= reduce; Send.ItemDurabilityUpdate(attacker, weapon); } // Proficiency // Only if the weapon isn't broken and the target is not "Weakest". if (weapon.Durability != 0 && attacker != null && attacker.GetPowerRating(target) >= PowerRating.Weak) { short prof = 0; if (attacker.Age >= 10 && attacker.Age <= 12) prof = 48; else if (attacker.Age >= 13 && attacker.Age <= 19) prof = 60; else prof = 72; weapon.Proficiency += prof; Send.ItemExpUpdate(attacker, weapon); } } }
/// <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.UpdateTool(creature.RightHand, reduce); 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); }
/// <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.UpdateTool(creature.RightHand, reduce); creature.RightHand.Durability -= reduce; 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 < collectData.ResourceReduction) { this.DoComplete(creature, entityId, collectId, false, 2); return; } // Reduce resources on success if (collectSuccess) { if (!ChannelServer.Instance.Conf.World.InfiniteResources) targetProp.Resource -= collectData.ResourceReduction; 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 < collectData.ResourceReduction) targetProp.SetState("empty"); } else { var targetCreature = (Creature)targetEntity; if (targetCreature.Mana < collectData.ResourceReduction) { this.DoComplete(creature, entityId, collectId, false, 2); return; } if (collectSuccess && !ChannelServer.Instance.Conf.World.InfiniteResources) targetCreature.Mana -= collectData.ResourceReduction; } // 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) item.Drop(creature.Region, creaturePosition.GetRandomInRange(DropRange, rnd)); 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.GetRandomInRange(DropRange, rnd)); } } // 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.GetRandomInRange(DropRange, rnd)); // 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.OnCreatureCollected(new CollectEventArgs(creature, collectData, collectSuccess, receiveItemId)); // Complete this.DoComplete(creature, entityId, collectId, collectSuccess, 0); }