Fix the Artisan Upgrade (without anim lvl 11 and 12), improve the inventory check and consumable materials.
This commit is contained in:
parent
9c3ae670b6
commit
4adf4a86b5
@ -8,7 +8,7 @@
|
|||||||
| | `add` | `!account add test@ 12345678 test` | Allows you to add a new user account |
|
| | `add` | `!account add test@ 12345678 test` | Allows you to add a new user account |
|
||||||
| | `setpassword` | `!account setpassword test@ 12345678` | Allows you to set a new password for account |
|
| | `setpassword` | `!account setpassword test@ 12345678` | Allows you to set a new password for account |
|
||||||
| | `setbtag` | `!account setbtag test@ NonTest` | Allows you to change battle tag for account |
|
| | `setbtag` | `!account setbtag test@ NonTest` | Allows you to change battle tag for account |
|
||||||
| | `setuserlevel` | `!account setuserlevel admin test@` | Allows you to set a new user level for account |
|
| | `setuserlevel` | `!account setuserlevel test@ admin` | Allows you to set a new user level for account |
|
||||||
| Mute Command | `mute` | `!mute test@` | Disable chat functions for user |
|
| Mute Command | `mute` | `!mute test@` | Disable chat functions for user |
|
||||||
|
|
||||||
## Game Commands
|
## Game Commands
|
||||||
|
|||||||
@ -856,7 +856,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
|
|||||||
Destroy();
|
Destroy();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ActorSno._crafting_looted_reagent_05: //Death's Breath
|
case ActorSno._crafting_looted_reagent_05: //Death's Breath GBID? 2087837753
|
||||||
playerAcc.CraftItem4++;
|
playerAcc.CraftItem4++;
|
||||||
Destroy();
|
Destroy();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -10,24 +10,34 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem
|
|||||||
{
|
{
|
||||||
private const int maxLevel = 12;
|
private const int maxLevel = 12;
|
||||||
private static readonly ArtisanType[] canBeTrained = new[] { ArtisanType.Blacksmith, ArtisanType.Jeweler, ArtisanType.Mystic };
|
private static readonly ArtisanType[] canBeTrained = new[] { ArtisanType.Blacksmith, ArtisanType.Jeweler, ArtisanType.Mystic };
|
||||||
|
|
||||||
private static readonly Dictionary<ArtisanType, string> recipeTemplates = new()
|
private static readonly Dictionary<ArtisanType, string> recipeTemplates = new()
|
||||||
{
|
{
|
||||||
[ArtisanType.Blacksmith] = "BlackSmith_Train_Level{0}",
|
[ArtisanType.Blacksmith] = "BlackSmith_Train_Level{0}",
|
||||||
[ArtisanType.Jeweler] = "Jeweler_Train_Level{0}",
|
[ArtisanType.Jeweler] = "Jeweler_Train_Level{0}",
|
||||||
[ArtisanType.Mystic] = "Mystic_Train_Level{0}"
|
[ArtisanType.Mystic] = "Mystic_Train_Level{0}"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<ArtisanType, long[]> achievements = new()
|
private static readonly Dictionary<ArtisanType, long[]> achievements = new()
|
||||||
{
|
{
|
||||||
[ArtisanType.Blacksmith] = new[] { 74987243307767, 74987243307768, 74987243307769, 74987251817289 },
|
[ArtisanType.Blacksmith] = new[] { 74987243307767, 74987243307768, 74987243307769, 74987251817289 },
|
||||||
[ArtisanType.Jeweler] = new[] { 74987243307781, 74987243307782, 74987243307783, 74987257153995 },
|
[ArtisanType.Jeweler] = new[] { 74987243307781, 74987243307782, 74987243307783, 74987257153995 },
|
||||||
[ArtisanType.Mystic] = new[] { 74987253584575, 74987256660015, 74987248802163, 74987251397159 }
|
[ArtisanType.Mystic] = new[] { 74987253584575, 74987256660015, 74987248802163, 74987251397159 }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<ArtisanType, long> criteriaForLevel10 = new()
|
private static readonly Dictionary<ArtisanType, long> criteriaForLevel10 = new()
|
||||||
{
|
{
|
||||||
[ArtisanType.Blacksmith] = 74987249071497,
|
[ArtisanType.Blacksmith] = 74987249071497,
|
||||||
[ArtisanType.Jeweler] = 74987245845978,
|
[ArtisanType.Jeweler] = 74987245845978,
|
||||||
[ArtisanType.Mystic] = 74987259424359
|
[ArtisanType.Mystic] = 74987259424359
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// To'do it's necessary to get the correct Animation for Lvl 11 and 12.
|
||||||
|
// For now I'm just using the Lvl 10 Animation.
|
||||||
|
// fixme no animation level 11
|
||||||
|
// 0x00011600,
|
||||||
|
// fixme no animation level 12
|
||||||
|
// 0x00011610,
|
||||||
private static readonly int[] animationTags = new[] {
|
private static readonly int[] animationTags = new[] {
|
||||||
0x00011500,
|
0x00011500,
|
||||||
0x00011510,
|
0x00011510,
|
||||||
@ -38,12 +48,15 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem
|
|||||||
0x00011560,
|
0x00011560,
|
||||||
0x00011570,
|
0x00011570,
|
||||||
0x00011580,
|
0x00011580,
|
||||||
0x00011590,
|
0x00011590
|
||||||
// fixme no animation
|
|
||||||
0x00011600,
|
|
||||||
// fixme no animation
|
|
||||||
0x00011610,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// To'do it's necessary to get the correct Animation for Lvl 11 and 12.
|
||||||
|
// For now I'm just using the Lvl 10 Animation.
|
||||||
|
// fixme no animation level 11
|
||||||
|
// 0x00011310,
|
||||||
|
// fixme no animation level 12
|
||||||
|
// 0x00011320
|
||||||
private static readonly int[] idleAnimationTags = new[] {
|
private static readonly int[] idleAnimationTags = new[] {
|
||||||
0x00011210,
|
0x00011210,
|
||||||
0x00011220,
|
0x00011220,
|
||||||
@ -54,22 +67,20 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem
|
|||||||
0x00011270,
|
0x00011270,
|
||||||
0x00011280,
|
0x00011280,
|
||||||
0x00011290,
|
0x00011290,
|
||||||
0x00011300,
|
0x00011300
|
||||||
// fixme no animation
|
|
||||||
0x00011310,
|
|
||||||
// fixme no animation
|
|
||||||
0x00011320
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private readonly ArtisanType artisanType;
|
private readonly ArtisanType artisanType;
|
||||||
|
|
||||||
internal ArtisanTrainHelper(DBCraft dBCraft, ArtisanType type)
|
internal ArtisanTrainHelper(DBCraft dBCraft, ArtisanType type)
|
||||||
{
|
{
|
||||||
if (!canBeTrained.Contains(type))
|
if (!canBeTrained.Contains(type))
|
||||||
throw new ArgumentException("Unsupported artisan type", nameof(type));
|
throw new ArgumentException("Unsupported artisan type", nameof(type));
|
||||||
|
|
||||||
DbRef = dBCraft ?? throw new ArgumentNullException(nameof(dBCraft));
|
DbRef = dBCraft ?? throw new ArgumentNullException(nameof(dBCraft));
|
||||||
artisanType = type;
|
artisanType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal DBCraft DbRef { get; }
|
internal DBCraft DbRef { get; }
|
||||||
|
|
||||||
internal string TrainRecipeName => string.Format(recipeTemplates[artisanType], Math.Min(DbRef.Level, maxLevel - 1));
|
internal string TrainRecipeName => string.Format(recipeTemplates[artisanType], Math.Min(DbRef.Level, maxLevel - 1));
|
||||||
@ -85,8 +96,27 @@ namespace DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem
|
|||||||
|
|
||||||
internal ulong? Criteria => DbRef.Level == 10 ? (ulong)criteriaForLevel10[artisanType] : null;
|
internal ulong? Criteria => DbRef.Level == 10 ? (ulong)criteriaForLevel10[artisanType] : null;
|
||||||
|
|
||||||
internal int AnimationTag => animationTags[DbRef.Level - 1];
|
internal int AnimationTag
|
||||||
internal int IdleAnimationTag => idleAnimationTags[DbRef.Level - 1];
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (DbRef.Level >= 10)
|
||||||
|
return animationTags[9]; // Force to use the LVL 10 Animation.
|
||||||
|
|
||||||
|
return animationTags[DbRef.Level - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int IdleAnimationTag
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (DbRef.Level >= 10)
|
||||||
|
return idleAnimationTags[9]; // Force to use the LVL 10 Idle Animation.
|
||||||
|
|
||||||
|
return idleAnimationTags[DbRef.Level - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal int Type => Array.IndexOf(canBeTrained, artisanType);
|
internal int Type => Array.IndexOf(canBeTrained, artisanType);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +1,32 @@
|
|||||||
using System;
|
using DiIiS_NA.Core.Extensions;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using DiIiS_NA.Core.Logging;
|
|
||||||
using DiIiS_NA.Core.Helpers.Math;
|
using DiIiS_NA.Core.Helpers.Math;
|
||||||
using DiIiS_NA.Core.Storage.AccountDataBase.Entities;
|
using DiIiS_NA.Core.Logging;
|
||||||
using DiIiS_NA.Core.MPQ;
|
using DiIiS_NA.Core.MPQ;
|
||||||
using DiIiS_NA.Core.MPQ.FileFormats;
|
using DiIiS_NA.Core.MPQ.FileFormats;
|
||||||
|
using DiIiS_NA.Core.Storage.AccountDataBase.Entities;
|
||||||
|
using DiIiS_NA.GameServer.ClientSystem;
|
||||||
|
using DiIiS_NA.GameServer.Core;
|
||||||
using DiIiS_NA.GameServer.Core.Types.SNO;
|
using DiIiS_NA.GameServer.Core.Types.SNO;
|
||||||
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
|
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
|
||||||
using DiIiS_NA.GameServer.GSSystem.ItemsSystem;
|
using DiIiS_NA.GameServer.GSSystem.ItemsSystem;
|
||||||
|
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
|
||||||
|
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
|
||||||
using DiIiS_NA.GameServer.MessageSystem;
|
using DiIiS_NA.GameServer.MessageSystem;
|
||||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Inventory;
|
|
||||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.ACD;
|
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.ACD;
|
||||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Artisan;
|
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Artisan;
|
||||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
|
|
||||||
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
|
|
||||||
using DiIiS_NA.GameServer.Core;
|
|
||||||
using DiIiS_NA.GameServer.MessageSystem.Message.Fields;
|
|
||||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Effect;
|
|
||||||
using DiIiS_NA.GameServer.ClientSystem;
|
|
||||||
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Base;
|
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Base;
|
||||||
|
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Effect;
|
||||||
|
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Inventory;
|
||||||
|
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
|
||||||
|
using DiIiS_NA.GameServer.MessageSystem.Message.Fields;
|
||||||
|
using DiIiS_NA.LoginServer.AccountsSystem;
|
||||||
|
using Discord;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using static DiIiS_NA.Core.MPQ.FileFormats.GameBalance;
|
using static DiIiS_NA.Core.MPQ.FileFormats.GameBalance;
|
||||||
using DiIiS_NA.Core.Extensions;
|
|
||||||
|
|
||||||
namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
|
namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
|
||||||
{
|
{
|
||||||
@ -98,21 +102,29 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
|
|||||||
return _buybackGrid;
|
return _buybackGrid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HaveEnough(int GBid, int count)
|
public bool HaveEnough(int gBid, int count, Player? player = null)
|
||||||
{
|
{
|
||||||
return (_inventoryGrid.TotalItemCount(GBid) + _stashGrid.TotalItemCount(GBid)) >= count;
|
// 2087837753 = Death's Breath -> AKA: CraftItem4 _crafting_looted_reagent_05.
|
||||||
|
if (player != null && gBid == 2087837753)
|
||||||
|
{
|
||||||
|
var playerAcc = player.InGameClient.BnetClient.Account.GameAccount;
|
||||||
|
return playerAcc.CraftItem4 > count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GrabSomeItems(int GBid, int count)
|
return (_inventoryGrid.TotalItemCount(gBid) + _stashGrid.TotalItemCount(gBid)) >= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GrabSomeItems(int gBid, int count)
|
||||||
{
|
{
|
||||||
if (_inventoryGrid.HaveEnough(GBid, count))
|
|
||||||
_inventoryGrid.GrabSomeItems(GBid, count);
|
if (_inventoryGrid.HaveEnough(gBid, count))
|
||||||
|
_inventoryGrid.GrabSomeItems(gBid, count);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int inBag = _inventoryGrid.TotalItemCount(GBid);
|
int inBag = _inventoryGrid.TotalItemCount(gBid);
|
||||||
_inventoryGrid.GrabSomeItems(GBid, inBag);
|
_inventoryGrid.GrabSomeItems(gBid, inBag);
|
||||||
count -= inBag;
|
count -= inBag;
|
||||||
_stashGrid.GrabSomeItems(GBid, count);
|
_stashGrid.GrabSomeItems(gBid, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2938,31 +2938,51 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var recipeDefinition = ItemGenerator.GetRecipeDefinition(trainHelper.TrainRecipeName);
|
var recipeDefinition = ItemGenerator.GetRecipeDefinition(trainHelper.TrainRecipeName);
|
||||||
|
|
||||||
|
// 1) Validade the Gold.
|
||||||
if (Inventory.GetGoldAmount() < recipeDefinition.Gold)
|
if (Inventory.GetGoldAmount() < recipeDefinition.Gold)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var requiredIngridients = recipeDefinition.Ingredients.Where(x => x.ItemsGBID > 0);
|
// 2) Extract only valid ingredients (actual items).
|
||||||
// FIXME: Inventory.HaveEnough doesn't work for some craft consumables
|
var requiredIngredients = recipeDefinition.Ingredients
|
||||||
var haveEnoughIngredients = requiredIngridients.All(x => Inventory.HaveEnough(x.ItemsGBID, x.Count));
|
.Where(x => x.ItemsGBID > 0 && x.Count > 0)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// 3) If the recipe requires items, validate whether they exist in the Inventory.
|
||||||
|
if (requiredIngredients.Any())
|
||||||
|
{
|
||||||
|
|
||||||
|
var haveEnoughIngredients = requiredIngredients
|
||||||
|
.All(x => Inventory.HaveEnough(x.ItemsGBID, x.Count, this));
|
||||||
|
|
||||||
if (!haveEnoughIngredients)
|
if (!haveEnoughIngredients)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Inventory.RemoveGoldAmount(recipeDefinition.Gold);
|
var playerAcc = this.InGameClient.BnetClient.Account.GameAccount;
|
||||||
foreach (var ingr in requiredIngridients)
|
|
||||||
// FIXME: Inventory.GrabSomeItems doesn't work for some craft consumables
|
|
||||||
Inventory.GrabSomeItems(ingr.ItemsGBID, ingr.Count);
|
|
||||||
|
|
||||||
|
// We already know that Artisan training is just consume Death's breath.
|
||||||
|
playerAcc.CraftItem4--;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) Always discount Gold (all recipes have a gold cost).
|
||||||
|
Inventory.RemoveGoldAmount(recipeDefinition.Gold);
|
||||||
|
|
||||||
|
// 5) Advance the artisan's level.
|
||||||
trainHelper.DbRef.Level++;
|
trainHelper.DbRef.Level++;
|
||||||
World.Game.GameDbSession.SessionUpdate(trainHelper.DbRef);
|
World.Game.GameDbSession.SessionUpdate(trainHelper.DbRef);
|
||||||
|
|
||||||
|
// 6) Related achievements & criteria.
|
||||||
if (trainHelper.Achievement is not null)
|
if (trainHelper.Achievement is not null)
|
||||||
GrantAchievement(trainHelper.Achievement.Value);
|
GrantAchievement(trainHelper.Achievement.Value);
|
||||||
|
|
||||||
if (trainHelper.Criteria is not null)
|
if (trainHelper.Criteria is not null)
|
||||||
GrantCriteria(trainHelper.Criteria.Value);
|
GrantCriteria(trainHelper.Criteria.Value);
|
||||||
|
|
||||||
if (_artisanTrainHelpers.All(x => x.Value.HasMaxLevel))
|
if (_artisanTrainHelpers.All(x => x.Value.HasMaxLevel))
|
||||||
GrantCriteria(74987249993545);
|
GrantCriteria(74987249993545);
|
||||||
|
|
||||||
|
// 7) Notify the Client.
|
||||||
client.SendMessage(new CrafterLevelUpMessage
|
client.SendMessage(new CrafterLevelUpMessage
|
||||||
{
|
{
|
||||||
Type = trainHelper.Type,
|
Type = trainHelper.Type,
|
||||||
@ -2972,9 +2992,6 @@ public class Player : Actor, IMessageConsumer, IUpdateable
|
|||||||
});
|
});
|
||||||
|
|
||||||
LoadCrafterData();
|
LoadCrafterData();
|
||||||
|
|
||||||
|
|
||||||
/**/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnlockTransmog(int transmogGBID)
|
public void UnlockTransmog(int transmogGBID)
|
||||||
|
|||||||
Loading…
Reference in New Issue
user.block.title