Merge pull request #108 from DeKaN/artisan-train

Simplify artisan training, fix Zoltan and Kanai cube reveal
This commit is contained in:
Lucca Faria Ferri 2023-01-28 09:43:23 -03:00 committed by GitHub
commit c1907ea5e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 255 additions and 320 deletions

View File

@ -73,7 +73,7 @@ namespace DiIiS_NA.Core.Logging
case Logger.Level.Warn:
return $"[darkorange3_1{postfix}]";
case Logger.Level.Error:
return "[indianred1{postfix}]";
return $"[indianred1{postfix}]";
case Logger.Level.Fatal:
return $"[red3{postfix}]";
default:

View File

@ -1,24 +1,19 @@
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Interactions;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
public class Artisan : InteractiveNPC
{
public Artisan(World world, ActorSno sno, TagMap tags)
: base(world, sno, tags)
{
Attributes[GameAttribute.MinimapActive] = true;
Interactions.Add(new CraftInteraction());
//Interactions.Add(new IdentifyAllInteraction());
}
@ -26,7 +21,6 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
public override void OnCraft(Player player)
{
player.InGameClient.SendMessage(new ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
//player.InGameClient.SendMessage(new OpenArtisanWindowMessage() { ArtisanID = this.DynamicID(player) });
}
}

View File

@ -1,10 +1,14 @@
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.Core.Logging;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.World;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
[HandledSNO(
ActorSno._pt_blacksmith_forgeweaponshortcut /* PT_Blacksmith_ForgeWeaponShortcut.acr */,
@ -14,10 +18,12 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
ActorSno._pt_jeweler_combineshortcut /* Actor PT_Jeweler_CombineShortcut */,
ActorSno._pt_jeweler_removegemshortcut /* Actor PT_Jeweler_RemoveGemShortcut */,
ActorSno._pt_mystic_enhanceshortcut /* Actor PT_Mystic_EnhanceShortcut */,
ActorSno._pt_mystic_identifyshortcut /* Actor PT_Mystic_IdentifyShortcut */
ActorSno._pt_mystic_identifyshortcut /* Actor PT_Mystic_IdentifyShortcut */,
ActorSno._kanaicube_stand /* Actor KanaiCube_Stand */
)]
public class ArtisanShortcut : InteractiveNPC
{
private static readonly Logger logger = LogManager.CreateLogger();
/*
[437895]p4_Ruins_Frost_KanaiCube_Altar
[439695] Lore_P3_ZoltunKulle_CubeHistory_01
@ -40,7 +46,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
[442282] kanai_Cube_Wash
[138979] NephalemCube
//*/
public ArtisanShortcut(MapSystem.World world, ActorSno sno, TagMap tags)
public ArtisanShortcut(World world, ActorSno sno, TagMap tags)
: base(world, sno, tags)
{
Attributes[GameAttribute.MinimapActive] = false;
@ -49,24 +55,26 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
public override void OnTargeted(Player player, TargetMessage message)
{
player.InGameClient.SendMessage(new MessageSystem.Message.Definitions.Misc.ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
switch (SNO)
player.InGameClient.SendMessage(new ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
player.CurrentArtisan = SNO switch
{
case ActorSno._pt_blacksmith_repairshortcut:
case ActorSno._pt_blacksmith_forgeweaponshortcut:
case ActorSno._pt_blacksmith_forgearmorshortcut:
player.ArtisanInteraction = "Blacksmith";
break;
case ActorSno._pt_jeweler_combineshortcut:
case ActorSno._pt_jeweler_addsocketshortcut:
case ActorSno._pt_jeweler_removegemshortcut:
player.ArtisanInteraction = "Jeweler";
break;
case ActorSno._pt_mystic_identifyshortcut:
case ActorSno._pt_mystic_enhanceshortcut:
player.ArtisanInteraction = "Mystic";
break;
}
ActorSno._pt_blacksmith_repairshortcut or
ActorSno._pt_blacksmith_forgeweaponshortcut or
ActorSno._pt_blacksmith_forgearmorshortcut => ArtisanType.Blacksmith,
ActorSno._pt_jeweler_combineshortcut or
ActorSno._pt_jeweler_addsocketshortcut or
ActorSno._pt_jeweler_removegemshortcut => ArtisanType.Jeweler,
ActorSno._pt_mystic_identifyshortcut or
ActorSno._pt_mystic_enhanceshortcut => ArtisanType.Mystic,
ActorSno._kanaicube_stand => ArtisanType.Cube,
_ => null,
};
if (player.CurrentArtisan == null)
logger.Error("Unhandled SNO {}", SNO);
}
public override bool Reveal(Player player)
{
@ -93,6 +101,9 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
break;
}
}
if (SNO == ActorSno._kanaicube_stand && !player.KanaiUnlocked)
return false;
return base.Reveal(player);
}

View File

@ -0,0 +1,11 @@
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
public enum ArtisanType
{
Blacksmith,
Jeweler,
Mystic,
Nephalem,
Cube
}
}

View File

@ -1,16 +1,10 @@
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
[HandledSNO(ActorSno._pt_blacksmith /* PT_Blacksmith.acr */)]
public class Blacksmith : Artisan
@ -25,8 +19,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
public override void OnCraft(Player player)
{
player.InGameClient.SendMessage(new ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
player.ArtisanInteraction = "Blacksmith";
base.OnCraft(player);
player.CurrentArtisan = ArtisanType.Blacksmith;
}
public override bool Reveal(Player player)

View File

@ -1,12 +1,12 @@
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.ItemsSystem;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
[HandledSNO(ActorSno._pt_jeweler /* PT_Jewler.acr */)]
public class Jeweler : Artisan
@ -26,8 +26,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
public override void OnCraft(Player player)
{
player.InGameClient.SendMessage(new ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
player.ArtisanInteraction = "Jeweler";
base.OnCraft(player);
player.CurrentArtisan = ArtisanType.Jeweler;
}
public override bool Reveal(Player player)

View File

@ -1,12 +1,10 @@
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ItemsSystem;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
[HandledSNO(ActorSno._pt_mystic /* PT_Mystic.acr */)]
public class Mystic : Artisan
@ -18,8 +16,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
public override void OnCraft(Player player)
{
player.InGameClient.SendMessage(new ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
player.ArtisanInteraction = "Mystic";
base.OnCraft(player);
player.CurrentArtisan = ArtisanType.Mystic;
}
public override bool Reveal(Player player)

View File

@ -1,13 +1,12 @@
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ItemsSystem;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Quest;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
[HandledSNO(ActorSno._p1_lr_tieredrift_nephalem /* P1_LR_TieredRift_Nephalem.acr */)]
public class Nephalem : Artisan
@ -15,14 +14,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
public Nephalem(World world, ActorSno sno, TagMap tags)
: base(world, sno, tags)
{
Attributes[GameAttribute.NPC_Is_Operatable] = true;
Attributes[GameAttribute.Is_NPC] = true;
Attributes[GameAttribute.In_Tiered_Loot_Run_Level] = 0;
Attributes[GameAttribute.MinimapActive] = true;
Attributes[GameAttribute.NPC_Has_Interact_Options, 0] = true;
Attributes[GameAttribute.NPC_Has_Interact_Options, 1] = true;
Attributes[GameAttribute.NPC_Has_Interact_Options, 2] = true;
Attributes[GameAttribute.NPC_Has_Interact_Options, 3] = true;
//this.Attributes[GameAttribute.Conversation_Icon] = 2;
//this.ForceConversationSNO =
}
@ -55,8 +47,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
}
}
player.InGameClient.SendMessage(new ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
player.ArtisanInteraction = "Mystic";
base.OnCraft(player);
player.CurrentArtisan = ArtisanType.Nephalem;
}
public override bool Reveal(Player player)

View File

@ -1,22 +1,20 @@
using DiIiS_NA.Core.Storage;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Interactions;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Misc;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.World;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
namespace DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans
{
[HandledSNO(ActorSno._p2_hq_zoltunkulle)] //Zoltun
//[HandledSNO(431095)] //Wardrobe
public class ZoltunNPC : Artisan
{
public ZoltunNPC(MapSystem.World world, ActorSno sno, TagMap tags)
public ZoltunNPC(World world, ActorSno sno, TagMap tags)
: base(world, sno, tags)
{
if (world.Game.CurrentAct == 3000)
@ -30,10 +28,23 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
}
}
public override void OnTargeted(Player player, MessageSystem.Message.Definitions.World.TargetMessage message)
public override void OnCraft(Player player)
{
base.OnTargeted(player, message);//player.InGameClient.SendMessage(new MessageSystem.Message.Definitions.Misc.ANNDataMessage(MessageSystem.Opcodes.OpenArtisanWindowMessage) { ActorID = this.DynamicID });
player.ArtisanInteraction = "KanaiCube";
base.OnCraft(player);
player.CurrentArtisan = ArtisanType.Cube;
}
public override void OnTargeted(Player player, TargetMessage message)
{
// TODO: check behavior for campaign mode
if (World.Game.CurrentAct == 3000 && player.KanaiUnlocked)
{
// works as ArtisanShortcut if we've found a cube. maybe only after all conversations
OnCraft(player);
} else
{
base.OnTargeted(player, message);
}
}
public override bool Reveal(Player player)
@ -49,21 +60,4 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans
return base.Reveal(player);
}
}
[HandledSNO(ActorSno._kanaicube_stand /* Actor KanaiCube_Stand */)]
public class CubeShortcut : InteractiveNPC
{
public CubeShortcut(MapSystem.World world, ActorSno sno, TagMap tags)
: base(world, sno, tags)
{
Attributes[GameAttribute.MinimapActive] = true;
Attributes[GameAttribute.Conversation_Icon, 0] = 0;
}
public override void OnTargeted(Player player, MessageSystem.Message.Definitions.World.TargetMessage message)
{
player.InGameClient.SendMessage(new MessageSystem.Message.Definitions.Misc.ANNDataMessage(Opcodes.OpenArtisanWindowMessage) { ActorID = DynamicID(player) });
player.ArtisanInteraction = "Cube";
}
}
}

View File

@ -48,8 +48,12 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
var Cube = World.GetActorBySNO(ActorSno._p4_ruins_frost_kanaicube_altar);
Cube.PlayActionAnimation(AnimationSno.p4_ruins_frost_kanaicube_altar_active);
//{[Actor] [Type: Gizmo] SNOId:437895 GlobalId: 1017303610 Position: x:331.9304 y:867.761 z:5.41071 Name: p4_Ruins_Frost_KanaiCube_Altar}
// TODO: check all players OR all players at current map
foreach (var plr in player.InGameClient.Game.Players.Values)
{
plr.GrantCriteria(74987252674266);
plr.KanaiUnlocked = true;
}
}
}
}

View File

@ -935,7 +935,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
Logger.Trace("Learning recipe...");
for (var i = 0; i < 10; i++)
if (ItemDefinition.RecipeToGrant[i] != -1)
player.LearnRecipe(player.ArtisanInteraction, ItemDefinition.RecipeToGrant[i]);
player.LearnRecipe(player.CurrentArtisan, ItemDefinition.RecipeToGrant[i]);
else
break;

View File

@ -0,0 +1,93 @@
using DiIiS_NA.Core.Storage.AccountDataBase.Entities;
using DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans;
using System;
using System.Collections.Generic;
using System.Linq;
namespace DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem
{
internal class ArtisanTrainHelper
{
private const int maxLevel = 12;
private static readonly ArtisanType[] canBeTrained = new[] { ArtisanType.Blacksmith, ArtisanType.Jeweler, ArtisanType.Mystic };
private static readonly Dictionary<ArtisanType, string> recipeTemplates = new()
{
[ArtisanType.Blacksmith] = "BlackSmith_Train_Level{0}",
[ArtisanType.Jeweler] = "Jeweler_Train_Level{0}",
[ArtisanType.Mystic] = "Mystic_Train_Level{0}"
};
private static readonly Dictionary<ArtisanType, long[]> achievements = new()
{
[ArtisanType.Blacksmith] = new[] { 74987243307767, 74987243307768, 74987243307769, 74987251817289 },
[ArtisanType.Jeweler] = new[] { 74987243307781, 74987243307782, 74987243307783, 74987257153995 },
[ArtisanType.Mystic] = new[] { 74987253584575, 74987256660015, 74987248802163, 74987251397159 }
};
private static readonly Dictionary<ArtisanType, long> criteriaForLevel10 = new()
{
[ArtisanType.Blacksmith] = 74987249071497,
[ArtisanType.Jeweler] = 74987245845978,
[ArtisanType.Mystic] = 74987259424359
};
private static readonly int[] animationTags = new[] {
0x00011500,
0x00011510,
0x00011520,
0x00011530,
0x00011540,
0x00011550,
0x00011560,
0x00011570,
0x00011580,
0x00011590,
// fixme no animation
0x00011600,
// fixme no animation
0x00011610,
};
private static readonly int[] idleAnimationTags = new[] {
0x00011210,
0x00011220,
0x00011230,
0x00011240,
0x00011250,
0x00011260,
0x00011270,
0x00011280,
0x00011290,
0x00011300,
// fixme no animation
0x00011310,
// fixme no animation
0x00011320
};
private readonly ArtisanType artisanType;
internal ArtisanTrainHelper(DBCraft dBCraft, ArtisanType type)
{
if (!canBeTrained.Contains(type))
throw new ArgumentException("Unsupported artisan type", nameof(type));
DbRef = dBCraft ?? throw new ArgumentNullException(nameof(dBCraft));
artisanType = type;
}
internal DBCraft DbRef { get; }
internal string TrainRecipeName => string.Format(recipeTemplates[artisanType], Math.Min(DbRef.Level, maxLevel - 1));
internal bool HasMaxLevel => DbRef.Level >= maxLevel;
internal ulong? Achievement => DbRef.Level switch
{
// index by level: 2 -> 0, 5 -> 1, 10 -> 2, 12 -> 3
2 or 5 or 10 or 12 => (ulong)achievements[artisanType][DbRef.Level / 4],
_ => null,
};
internal ulong? Criteria => DbRef.Level == 10 ? (ulong)criteriaForLevel10[artisanType] : null;
internal int AnimationTag => animationTags[DbRef.Level - 1];
internal int IdleAnimationTag => idleAnimationTags[DbRef.Level - 1];
internal int Type => Array.IndexOf(canBeTrained, artisanType);
}
}

View File

@ -22,7 +22,6 @@ using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Effect;
using DiIiS_NA.GameServer.ClientSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Base;
using static DiIiS_NA.Core.MPQ.FileFormats.GameBalance;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Artisans;
using DiIiS_NA.Core.Extensions;
namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem

View File

@ -118,6 +118,9 @@ using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Encounter;
//Blizzless Project 2022
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.UI;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Artisans;
using DiIiS_NA.D3_GameServer.GSSystem.PlayerSystem;
using NHibernate.Util;
namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
{
@ -143,7 +146,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
/// <summary>
/// Current crafting NPC type(for learning recipes)
/// </summary>
public string ArtisanInteraction = "None";
public ArtisanType? CurrentArtisan { get; set; }
/// <summary>
/// The player's toon.
@ -374,22 +377,20 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
var achievements = InGameClient.Game.GameDBSession.SessionQueryWhere<DBAchievements>(dba => dba.DBGameAccount.Id == Toon.GameAccount.PersistentID);
BlacksmithUnlocked = achievements.Where(dba => dba.AchievementId == 74987243307766).Count() > 0;
JewelerUnlocked = achievements.Where(dba => dba.AchievementId == 74987243307780).Count() > 0;
MysticUnlocked = achievements.Where(dba => dba.AchievementId == 74987247205955).Count() > 0;
BlacksmithUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307766);
JewelerUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307780);
MysticUnlocked = achievements.Any(dba => dba.AchievementId == 74987247205955);
KanaiUnlocked = false;
foreach (var achi in achievements.Where(dba => dba.AchievementId == 74987254626662).ToList())
foreach (var crit in AchievementSystem.AchievementManager.UnserializeBytes(achi.Criteria))
if (crit == unchecked((uint)74987252674266))
KanaiUnlocked = true;
KanaiUnlocked = achievements.Where(dba => dba.AchievementId == 74987254626662)
.SelectMany(x => AchievementSystem.AchievementManager.UnserializeBytes(x.Criteria))
.Any(x => x == unchecked((uint)74987252674266));
if (Level >= 70)
GrantCriteria(74987254853541);
HirelingTemplarUnlocked = achievements.Where(dba => dba.AchievementId == 74987243307073).Count() > 0;
HirelingScoundrelUnlocked = achievements.Where(dba => dba.AchievementId == 74987243307147).Count() > 0;
HirelingEnchantressUnlocked = achievements.Where(dba => dba.AchievementId == 74987243307145).Count() > 0;
HirelingTemplarUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307073);
HirelingScoundrelUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307147);
HirelingEnchantressUnlocked = achievements.Any(dba => dba.AchievementId == 74987243307145);
SkillSet = new SkillSet(this, Toon.Class, Toon);
GroundItems = new Dictionary<uint, Item>();
Followers = new Dictionary<uint, ActorSno>();
@ -1527,7 +1528,6 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
}
public void AcceptBossEncounter()
{
ArtisanInteraction = "QueueAccepted";
InGameClient.Game.AcceptBossEncounter();
}
public void DeclineBossEncounter()
@ -2700,213 +2700,56 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
private void OnArtisanWindowClosed()
{
CurrentArtisan = null;
}
//*
private void TrainArtisan(GameClient client, RequestTrainArtisanMessage message)
{
int AnimByLevel = 0;
int IdleByLevel = 0;
if (ArtisanInteraction == "Blacksmith")
{
if (blacksmith_data.Level > 55) return;
var recipeDefinition = ItemGenerator.GetRecipeDefinition(string.Format("BlackSmith_Train_Level{0}", Math.Min(blacksmith_data.Level, 55)));
//Logger.Trace(string.Format("BlackSmith_Train_Level{0}", Math.Min(blacksmith_data.Level, 45)));
if (Inventory.GetGoldAmount() < recipeDefinition.Gold) return;
bool haveEnoughIngredients = true;
foreach (var ingr in recipeDefinition.Ingredients) //first loop (checking)
{
if (ingr.ItemsGBID == -1) continue;
if (!Inventory.HaveEnough(ingr.ItemsGBID, ingr.Count)) { haveEnoughIngredients = false; break; } //if havent enough then exit
if (CurrentArtisan == null || !artisanTrainHelpers.ContainsKey(CurrentArtisan.Value)) {
Logger.Warn("Training for artisan {} is not supported", CurrentArtisan);
return;
}
if (!haveEnoughIngredients) return;
Inventory.RemoveGoldAmount(recipeDefinition.Gold);
var trainHelper = artisanTrainHelpers[CurrentArtisan.Value];
if (trainHelper.HasMaxLevel)
return;
foreach (var ingr in recipeDefinition.Ingredients) //second loop (getting)
var recipeDefinition = ItemGenerator.GetRecipeDefinition(trainHelper.TrainRecipeName);
if (Inventory.GetGoldAmount() < recipeDefinition.Gold)
return;
var requiredIngridients = recipeDefinition.Ingredients.Where(x => x.ItemsGBID > 0);
// FIXME: Inventory.HaveEnough doesn't work for some craft consumables
var haveEnoughIngredients = requiredIngridients.All(x => Inventory.HaveEnough(x.ItemsGBID, x.Count));
if (!haveEnoughIngredients)
return;
Inventory.RemoveGoldAmount(recipeDefinition.Gold);
foreach (var ingr in requiredIngridients)
{
if (ingr.ItemsGBID == -1) continue;
// FIXME: Inventory.GrabSomeItems doesn't work for some craft consumables
Inventory.GrabSomeItems(ingr.ItemsGBID, ingr.Count);
}
blacksmith_data.Level++;
World.Game.GameDBSession.SessionUpdate(blacksmith_data);
if (blacksmith_data.Level == 2)
GrantAchievement(74987243307767);
if (blacksmith_data.Level == 5)
GrantAchievement(74987243307768);
if (blacksmith_data.Level == 10)
{
GrantAchievement(74987243307769);
GrantCriteria(74987249071497);
}
if (blacksmith_data.Level == 12)
{
GrantAchievement(74987251817289);
//74987249993545
if (jeweler_data.Level == 12 && mystic_data.Level == 12)
{
GrantCriteria(74987249993545);
}
}
trainHelper.DbRef.Level++;
World.Game.GameDBSession.SessionUpdate(trainHelper.DbRef);
if (trainHelper.Achievement is not null)
GrantAchievement(trainHelper.Achievement.Value);
if (trainHelper.Criteria is not null)
GrantCriteria(trainHelper.Criteria.Value);
if (artisanTrainHelpers.All(x => x.Value.HasMaxLevel))
GrantCriteria(74987249993545);
switch (blacksmith_data.Level)
{
case 1: AnimByLevel = 0x00011500; IdleByLevel = 0x00011210; break;
case 2: AnimByLevel = 0x00011510; IdleByLevel = 0x00011220; break;
case 3: AnimByLevel = 0x00011520; IdleByLevel = 0x00011230; break;
case 4: AnimByLevel = 0x00011530; IdleByLevel = 0x00011240; break;
case 5: AnimByLevel = 0x00011540; IdleByLevel = 0x00011250; break;
case 6: AnimByLevel = 0x00011550; IdleByLevel = 0x00011260; break;
case 7: AnimByLevel = 0x00011560; IdleByLevel = 0x00011270; break;
case 8: AnimByLevel = 0x00011570; IdleByLevel = 0x00011280; break;
case 9: AnimByLevel = 0x00011580; IdleByLevel = 0x00011290; break;
case 10: AnimByLevel = 0x00011590; IdleByLevel = 0x00011300; break;
case 11: AnimByLevel = 0x00011600; IdleByLevel = 0x00011310; break;
case 12: AnimByLevel = 0x00011610; IdleByLevel = 0x00011320; break;
}
client.SendMessage(new CrafterLevelUpMessage
{
Type = 0,
AnimTag = AnimByLevel,
NewIdle = IdleByLevel,
Level = blacksmith_data.Level
Type = trainHelper.Type,
AnimTag = trainHelper.AnimationTag,
NewIdle = trainHelper.IdleAnimationTag,
Level = trainHelper.DbRef.Level
});
}
if (ArtisanInteraction == "Jeweler")
{
if (jeweler_data.Level > 12) return;
var recipeDefinition = ItemGenerator.GetRecipeDefinition(string.Format("Jeweler_Train_Level{0}", Math.Min(jeweler_data.Level, 11)));
if (Inventory.GetGoldAmount() < recipeDefinition.Gold) return;
bool haveEnoughIngredients = true;
foreach (var ingr in recipeDefinition.Ingredients) //first loop (checking)
{
if (ingr.ItemsGBID == -1) continue;
if (!Inventory.HaveEnough(ingr.ItemsGBID, ingr.Count)) { haveEnoughIngredients = false; break; } //if havent enough then exit
}
if (!haveEnoughIngredients) return;
Inventory.RemoveGoldAmount(recipeDefinition.Gold);
foreach (var ingr in recipeDefinition.Ingredients) //second loop (getting)
{
if (ingr.ItemsGBID == -1) continue;
Inventory.GrabSomeItems(ingr.ItemsGBID, ingr.Count);
}
jeweler_data.Level++;
World.Game.GameDBSession.SessionUpdate(jeweler_data);
if (jeweler_data.Level == 2)
GrantAchievement(74987243307781);
if (jeweler_data.Level == 5)
GrantAchievement(74987243307782);
if (jeweler_data.Level == 10)
{
GrantAchievement(74987243307783);
GrantCriteria(74987245845978);
}
if (jeweler_data.Level == 12)
{
GrantAchievement(74987257153995);
if (blacksmith_data.Level == 12 && mystic_data.Level == 12)
{
GrantCriteria(74987249993545);
}
}
switch (jeweler_data.Level)
{
case 1: AnimByLevel = 0x00011500; IdleByLevel = 0x00011210; break;
case 2: AnimByLevel = 0x00011510; IdleByLevel = 0x00011220; break;
case 3: AnimByLevel = 0x00011520; IdleByLevel = 0x00011230; break;
case 4: AnimByLevel = 0x00011530; IdleByLevel = 0x00011240; break;
case 5: AnimByLevel = 0x00011540; IdleByLevel = 0x00011250; break;
case 6: AnimByLevel = 0x00011550; IdleByLevel = 0x00011260; break;
case 7: AnimByLevel = 0x00011560; IdleByLevel = 0x00011270; break;
case 8: AnimByLevel = 0x00011570; IdleByLevel = 0x00011280; break;
case 9: AnimByLevel = 0x00011580; IdleByLevel = 0x00011290; break;
case 10: AnimByLevel = 0x00011590; IdleByLevel = 0x00011300; break;
case 11: AnimByLevel = 0x00011600; IdleByLevel = 0x00011310; break;
case 12: AnimByLevel = 0x00011610; IdleByLevel = 0x00011320; break;
}
client.SendMessage(new CrafterLevelUpMessage
{
Type = 1,
AnimTag = AnimByLevel,
NewIdle = IdleByLevel,
Level = jeweler_data.Level
});
}
if (ArtisanInteraction == "Mystic")
{
if (mystic_data.Level > 12) return;
var recipeDefinition = ItemGenerator.GetRecipeDefinition(string.Format("Mystic_Train_Level{0}", Math.Min(mystic_data.Level, 11)));
if (Inventory.GetGoldAmount() < recipeDefinition.Gold) return;
bool haveEnoughIngredients = true;
foreach (var ingr in recipeDefinition.Ingredients) //first loop (checking)
{
if (ingr.ItemsGBID == -1) continue;
if (!Inventory.HaveEnough(ingr.ItemsGBID, ingr.Count)) { haveEnoughIngredients = false; break; } //if havent enough then exit
}
if (!haveEnoughIngredients) return;
Inventory.RemoveGoldAmount(recipeDefinition.Gold);
foreach (var ingr in recipeDefinition.Ingredients) //second loop (getting)
{
if (ingr.ItemsGBID == -1) continue;
Inventory.GrabSomeItems(ingr.ItemsGBID, ingr.Count);
}
mystic_data.Level++;
World.Game.GameDBSession.SessionUpdate(mystic_data);
if (mystic_data.Level == 2)
GrantAchievement(74987253584575);
if (mystic_data.Level == 5)
GrantAchievement(74987256660015);
if (mystic_data.Level == 10)
{
GrantAchievement(74987248802163);
GrantCriteria(74987259424359);
}
if (mystic_data.Level == 12)
{
//this.GrantAchievement(74987256206128);
if (jeweler_data.Level == 12 && blacksmith_data.Level == 12)
{
GrantCriteria(74987249993545);
}
}
switch (mystic_data.Level)
{
case 1: AnimByLevel = 0x00011500; IdleByLevel = 0x00011210; break;
case 2: AnimByLevel = 0x00011510; IdleByLevel = 0x00011220; break;
case 3: AnimByLevel = 0x00011520; IdleByLevel = 0x00011230; break;
case 4: AnimByLevel = 0x00011530; IdleByLevel = 0x00011240; break;
case 5: AnimByLevel = 0x00011540; IdleByLevel = 0x00011250; break;
case 6: AnimByLevel = 0x00011550; IdleByLevel = 0x00011260; break;
case 7: AnimByLevel = 0x00011560; IdleByLevel = 0x00011270; break;
case 8: AnimByLevel = 0x00011570; IdleByLevel = 0x00011280; break;
case 9: AnimByLevel = 0x00011580; IdleByLevel = 0x00011290; break;
case 10: AnimByLevel = 0x00011590; IdleByLevel = 0x00011300; break;
case 11: AnimByLevel = 0x00011600; IdleByLevel = 0x00011310; break;
case 12: AnimByLevel = 0x00011610; IdleByLevel = 0x00011320; break;
}
client.SendMessage(new CrafterLevelUpMessage
{
Type = 2,
AnimTag = AnimByLevel,
NewIdle = IdleByLevel,
Level = mystic_data.Level
});
}
LoadCrafterData();
@ -4273,7 +4116,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
return data.SelectMany(BitConverter.GetBytes).ToArray();
}
public void LearnRecipe(string artisan, int recipe)
public void LearnRecipe(ArtisanType? artisan, int recipe)
{
Logger.Trace("Learning recipe #{0}, Artisan type: {1}", recipe, artisan);
/*var query = this.World.Game.GameDBSession.SessionQuerySingle<DBCraft>(
@ -4281,14 +4124,14 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
dbi.DBGameAccount.Id == this.Toon.GameAccount.PersistentID &&
dbi.Artisan == artisan &&
dbi.isHardcore == this.World.Game.IsHardcore);*/
if (artisan == "Blacksmith")
if (artisan == ArtisanType.Blacksmith)
{
learnedBlacksmithRecipes.Add(recipe);
blacksmith_data.LearnedRecipes = SerializeBytes(learnedBlacksmithRecipes);
World.Game.GameDBSession.SessionUpdate(blacksmith_data);
UpdateAchievementCounter(404, 1, 0);
}
if (artisan == "Jeweler")
else if (artisan == ArtisanType.Jeweler)
{
learnedJewelerRecipes.Add(recipe);
jeweler_data.LearnedRecipes = SerializeBytes(learnedJewelerRecipes);
@ -4322,6 +4165,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
private DBCraft blacksmith_data = null;
private DBCraft jeweler_data = null;
private DBCraft mystic_data = null;
private Dictionary<ArtisanType, ArtisanTrainHelper> artisanTrainHelpers = new();
public void LoadCrafterData()
{
@ -4332,6 +4176,10 @@ namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
blacksmith_data = craft_data.Single(dbc => dbc.Artisan == "Blacksmith" && dbc.isHardcore == World.Game.IsHardcore && dbc.isSeasoned == World.Game.IsSeasoned);
jeweler_data = craft_data.Single(dbc => dbc.Artisan == "Jeweler" && dbc.isHardcore == World.Game.IsHardcore && dbc.isSeasoned == World.Game.IsSeasoned);
mystic_data = craft_data.Single(dbc => dbc.Artisan == "Mystic" && dbc.isHardcore == World.Game.IsHardcore && dbc.isSeasoned == World.Game.IsSeasoned);
artisanTrainHelpers[ArtisanType.Blacksmith] = new ArtisanTrainHelper(blacksmith_data, ArtisanType.Blacksmith);
artisanTrainHelpers[ArtisanType.Jeweler] = new ArtisanTrainHelper(jeweler_data, ArtisanType.Jeweler);
artisanTrainHelpers[ArtisanType.Mystic] = new ArtisanTrainHelper(mystic_data, ArtisanType.Mystic);
}

View File

@ -1,4 +1,4 @@
//Blizzless Project 2022
//Blizzless Project 2022
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.D3_GameServer.GSSystem.ActorSystem.Implementations.Minions;
using DiIiS_NA.GameServer.Core.Types.Math;
@ -2338,7 +2338,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations
else
StartCooldown(60f);
List<Actor> ancients = new List<Actor>();
var ancients = new List<AncientBarbarian>();
for (int i = 0; i < 3; i++)
{
var ancient = SpawnAncient(i);
@ -2352,9 +2352,9 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations
}
yield return WaitSeconds(0.8f);
foreach (Actor ancient in ancients)
foreach (var ancient in ancients)
{
(ancient as Minion).Brain.Activate();
ancient.Brain.Activate();
ancient.Attributes[GameAttribute.Untargetable] = false;
ancient.Attributes.BroadcastChangedIfRevealed();
}

View File

@ -2122,7 +2122,7 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations
yield return WaitSeconds(0.2f);
}
}
if (Rune_E > 0)
else if (Rune_E > 0)
{
for (int i = 0; i < ScriptFormula(13); i++)
{
@ -2133,13 +2133,13 @@ namespace DiIiS_NA.GameServer.GSSystem.PowerSystem.Implementations
}
}
yield return WaitSeconds(0.5f);
foreach (var Fetish in fetishes)
foreach (var fetish in fetishes)
{
Fetish.MakeFetishLive(customLifeTime: null);
fetish.MakeFetishLive(customLifeTime: null);
if (Rune_A > 0)
{
Fetish.PlayEffectGroup(133761);
WeaponDamage(GetEnemiesInRadius(Fetish.Position, 5f), ScriptFormula(5), DamageType.Physical);
fetish.PlayEffectGroup(133761);
WeaponDamage(GetEnemiesInRadius(fetish.Position, 5f), ScriptFormula(5), DamageType.Physical);
}
}

View File

@ -1,12 +1,10 @@
//Blizzless Project 2022
//Blizzless Project 2022
using System;
//Blizzless Project 2022
using System.Collections.Generic;
//Blizzless Project 2022
using System.Linq;
//Blizzless Project 2022
using System.Text;
//Blizzless Project 2022
using System.Threading.Tasks;
//Blizzless Project 2022
using DiIiS_NA.Core.Logging;

View File

@ -17,7 +17,6 @@ namespace DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Encounter
public void Handle(GameClient client)
{
client.Player.ArtisanInteraction = "QueueAccepted";
client.Game.AcceptBossEncounter();
}