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;
}
// Update tool if it's a breakable item (i.e. it had a durability once)
if (creature.RightHand != null && creature.RightHand.IsBreakable)
{
var tool = creature.RightHand;
// No gathering with a broken tool.
if (tool.Durability == 0)
{
this.DoComplete(creature, entityId, collectId, false, 4);
return;
}
// Durability
if (collectData.DurabilityLoss > 0)
{
var reduce = collectData.DurabilityLoss;
creature.Inventory.ReduceDurability(tool, reduce);
}
// Prof
if (tool.Durability != 0)
{
var amount = Item.GetProficiencyGain(creature.Age, ProficiencyGainType.Gathering);
creature.Inventory.AddProficiency(tool, amount);
}
}
// 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)
{
// Get collection bonuses
var collectionBonus = 0;
var collectionBonusProduct = 0;
if (creature.RightHand != null)
{
collectionBonus = creature.RightHand.MetaData1.GetShort("CTBONUS");
collectionBonusProduct = creature.RightHand.MetaData1.GetInt("CTBONUSPT");
}
// Product
var itemId = receiveItemId = collectData.GetRndProduct(rnd, new ProductBonus(collectionBonusProduct, collectionBonus));
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);
// Collection Bonus Upgrade
// CTBONUS is only used for the double drop upgrade if
// CTBONUSPT is not set, which makes use of CTBONUS
// for the increased chance of getting a certain
// product.
if (collectionBonusProduct == 0 && collectionBonus != 0)
{
if (rnd.Next(100) < collectionBonus)
new Item(item).Drop(creature.Region, creaturePosition, DropRange, creature, false);
}
}
else
{
creature.Inventory.Remove(creature.RightHand);
creature.Inventory.Add(item, creature.Inventory.RightHandPocket);
}
}
// Product2
itemId = collectData.GetRndProduct2(rnd, null);
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);
}