Quests and MPQ work.

Fixed quest to find 2 orbs on the rotten forest;
Fixed load actors to load an actor file that could not be found - as many actors rely on a name which is not always provided on the enum by using a [SnoFileName("TheActual SnoFileName")];
Changed FileFormats.Actor to FileFormats.ActorData
This commit is contained in:
Lucca Faria Ferri 2023-02-02 11:52:36 -08:00
parent bce8acfaf3
commit 97a8bfa8a3
21 changed files with 211 additions and 84 deletions

View File

@ -11,10 +11,21 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using Spectre.Console;
namespace DiIiS_NA.Core.MPQ
{
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class SnoFileNameAttribute : Attribute
{
public string FileName { get; }
public SnoFileNameAttribute(string fileName)
{
FileName = fileName;
}
}
public class Data : MPQPatchChain
{
public Dictionary<SNOGroup, ConcurrentDictionary<int, Asset>> Assets = new Dictionary<SNOGroup, ConcurrentDictionary<int, Asset>>();
@ -56,12 +67,15 @@ namespace DiIiS_NA.Core.MPQ
#endregion
private static new readonly Logger Logger = LogManager.CreateLogger("DataBaseWorker");
private new static readonly Logger Logger = LogManager.CreateLogger("MPQWorker");
public Data()
//: base(0, new List<string> { "CoreData.mpq", "ClientData.mpq" }, "/base/d3-update-base-(?<version>.*?).mpq")
: base(0, new List<string> { "Core.mpq", "Core1.mpq", "Core2.mpq", "Core3.mpq", "Core4.mpq" }, "/base/d3-update-base-(?<version>.*?).mpq")
{ }
: base(0, new List<string> { "Core.mpq", "Core1.mpq", "Core2.mpq", "Core3.mpq", "Core4.mpq" },
"/base/d3-update-base-(?<version>.*?).mpq")
{
}
public void Init()
{

View File

@ -202,7 +202,29 @@ namespace DiIiS_NA.Core.MPQ
}
public static Dictionary<string, int> LoadActors()
{
return Enum.GetValues<ActorSno>().Where(x => x != ActorSno.__NONE).ToDictionary(x => x.ToString().Substring(1), x => (int)x);
var dict = Enum.GetValues<ActorSno>().Where(x => x != ActorSno.__NONE).ToDictionary(x => x.ToString().Substring(1), x => (int)x);
// TODO: merge with LINQ above.
// this parses enum values that has SnoFileNameAttribute, in case the dict linq above didn't get a correct name
// for the actor file.
foreach (var d in Enum.GetValues<ActorSno>())
{
var enumType = typeof(ActorSno);
var memberInfos =
enumType.GetMember(d.ToString());
if (memberInfos.Length == 0)
continue;
var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == enumType);
if (enumValueMemberInfo == null) continue;
var valueAttributes = enumValueMemberInfo.GetCustomAttributes(typeof(SnoFileNameAttribute), false)
.Select(s=>(SnoFileNameAttribute)s)
.FirstOrDefault();
if (valueAttributes != null)
{
dict.Add(valueAttributes.FileName, (int)d);
}
}
return dict;
}
public static Dictionary<string, int> LoadAdventure()
{

View File

@ -12,7 +12,7 @@ using DiIiS_NA.GameServer.Core.Types.TagMap;
namespace DiIiS_NA.Core.MPQ.FileFormats
{
[FileFormat(SNOGroup.Actor)]
public class Actor : FileFormat
public class ActorData : FileFormat
{
public Header Header { get; private set; }
public int Flags { get; private set; }
@ -42,7 +42,7 @@ namespace DiIiS_NA.Core.MPQ.FileFormats
public string CastingNotes { get; private set; }
public string VoiceOverRole { get; private set; }
public Actor(MpqFile file)
public ActorData(MpqFile file)
{
var stream = file.Open();
Header = new Header(stream);

View File

@ -0,0 +1,85 @@
using System;
using System.Linq;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.LoginServer.AccountsSystem;
using DiIiS_NA.LoginServer.Battle;
namespace DiIiS_NA.GameServer.CommandManager;
[CommandGroup("actors",
"Actors info (does not include Players, Minions and Monsters). This is useful for testing purposes.",
Account.UserLevels.Tester)]
public class ActorsCommand : CommandGroup
{
[Command("all", "Lists all actors.", Account.UserLevels.Tester)]
public string All(string[] @params, BattleClient invokerClient)
{
if (invokerClient?.InGameClient?.Player is not {} player)
return "You are not in game.";
return $"World [{player.World.SNO}]\nAll actors:" + string.Join("\n", player.World.Actors
.OrderBy(a =>
{
var position = player.Position;
return a.Value.Position.DistanceSquared(ref position);
}).Select(a =>
{
var position = player.Position;
var distance = a.Value.Position.DistanceSquared(ref position);
return $"[{a.Value.GetType().Name}] - {a.Value.SNO}\n" +
$" > Distance: {distance}\n" +
$" > SnoId: {(int)a.Value.SNO}";
}));
}
[Command("revealed", "Lists all revealed actors.", Account.UserLevels.Tester)]
public string Revealed(string[] @params, BattleClient invokerClient)
{
if (invokerClient?.InGameClient?.Player is not {} player)
return "You are not in game.";
return $"World [{player.World.SNO}]\nVisible actors:" + string.Join("\n", player.World.Actors
.Where(a => a.Value.IsRevealedToPlayer(player))
.OrderBy(a =>
{
var position = player.Position;
return a.Value.Position.DistanceSquared(ref position);
}).Select(a =>
{
var position = player.Position;
var distance = a.Value.Position.DistanceSquared(ref position);
return $"[{a.Value.GetType().Name}] - {a.Value.SNO}\n" +
$" > Distance: {distance}\n" +
$" > SnoId: {(int)a.Value.SNO}";
}));
}
[Command("setoperable", "Sets all actors operable (not the wisest invention).", Account.UserLevels.Tester)]
public string Operable(string[] @params, BattleClient invokerClient)
{
if (invokerClient?.InGameClient?.Player is not {} player)
return "You are not in game.";
if (@params is { Length: > 0 })
{
if (!Enum.TryParse<ActorSno>(@params[0].AsSpan(), out var actorSno))
{
return "Invalid actor SNO.";
}
var actor = player.World.Actors.FirstOrDefault(a => a.Value.SNO == actorSno);
if (actor.Value is null)
return "Actor not found.";
actor.Value.SetVisible(true);
actor.Value.SetUsable(true);
}
var actors = player.World.Actors.Select(s=>s.Value).ToArray();
foreach (var actor in actors)
{
actor.SetVisible(true);
actor.SetUsable(true);
}
return $"All {actors.Length} world actors are now operable.";
}
}

View File

@ -5,8 +5,8 @@ using DiIiS_NA.LoginServer.AccountsSystem;
namespace DiIiS_NA.GameServer.CommandManager;
[CommandGroup("doors", "Information about all doors in the vicinity. This is useful for testing purposes.. Useful for testing.", Account.UserLevels.Tester)]
public class OpenDoorCommand : CommandGroup
[CommandGroup("doors", "Information about all doors in the vicinity. This is useful for testing purposes.", Account.UserLevels.Tester)]
public class DoorsCommand : CommandGroup
{
[Command("all", "Activate all doors. This is useful for testing purposes.\nUsage: !open all", Account.UserLevels.Tester)]
public string OpenAllDoors(string[] @params, BattleClient invokerClient)

View File

@ -9,7 +9,6 @@ using DiIiS_NA.GameServer.GSSystem.ActorSystem;
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.LoginServer.Battle;
using Actor = DiIiS_NA.Core.MPQ.FileFormats.Actor;
namespace DiIiS_NA.GameServer.CommandManager;
@ -194,7 +193,7 @@ public class ModifySpeedCommand : CommandGroup
return matches.Aggregate(matches.Count >= 1 ? "Actor Matches:\n" : "No match found.",
(current, match) => current +
$"[{match.SNOId:D6}] {match.Name} ({((Actor)match.Data).Type} {(((Actor)match.Data).Type == ActorType.Gizmo ? ((int)((Actor)match.Data).TagMap[ActorKeys.GizmoGroup]).ToString() : "")})\n");
$"[{match.SNOId:D6}] {match.Name} ({((ActorData)match.Data).Type} {(((ActorData)match.Data).Type == ActorType.Gizmo ? ((int)((ActorData)match.Data).TagMap[ActorKeys.GizmoGroup]).ToString() : "")})\n");
}
[Command("rope", "Allows you to search for an rope.\nUsage: lookup rope <pattern>")]

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using DiIiS_NA.Core.MPQ;
namespace DiIiS_NA.D3_GameServer.Core.Types.SNO
{
@ -7535,12 +7536,14 @@ namespace DiIiS_NA.D3_GameServer.Core.Types.SNO
_wizard_tornado_golden = 215324,
_inviscylindercollisionsmall = 215351,
_wizard_waveofforce_runecrimson_shell = 215420,
[SnoFileName("a1dun_Caves_Nephalem Altar_A_Chest_03")]
_a1dun_caves_nephalem_altar_a_chest_03 = 215434,
_arcanumorb_model = 215444,
_fallenshaman_a_unique01whipple = 215445,
_wizard_waveofforce_runeobsidian_shell = 215488,
_cow_gem_flippy = 215500,
_wizard_waveofforce_runegolden_shell = 215511,
[SnoFileName("a1dun_Caves_Nephalem Altar_A_Chest_03_B")]
_a1dun_caves_nephalem_altar_a_chest_03_b = 215512,
_wizard_frostnova_critbuff_swipe = 215516,
_monk_hol_stage03_ribbongeo = 215635,

View File

@ -1,7 +1,6 @@
using DiIiS_NA.Core.Logging;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.Math;
using DiIiS_NA.GameServer.Core.Types.Misc;
using DiIiS_NA.GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
@ -9,7 +8,6 @@ using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations.Hirelings;
using DiIiS_NA.GameServer.GSSystem.GameSystem;
using DiIiS_NA.GameServer.GSSystem.GeneratorsSystem;
using DiIiS_NA.GameServer.GSSystem.ItemsSystem;
using DiIiS_NA.GameServer.GSSystem.MapSystem;
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.GSSystem.PowerSystem;
@ -26,8 +24,12 @@ using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using DiIiS_NA.Core.MPQ;
using DiIiS_NA.Core.MPQ.FileFormats;
using DiIiS_NA.D3_GameServer.GSSystem.GameSystem;
using Circle = DiIiS_NA.GameServer.Core.Types.Misc.Circle;
using Player = DiIiS_NA.GameServer.GSSystem.PlayerSystem.Player;
using Scene = DiIiS_NA.GameServer.GSSystem.MapSystem.Scene;
using World = DiIiS_NA.GameServer.GSSystem.MapSystem.World;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
{
@ -168,13 +170,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
/// <summary>
/// The info set for actor. (erekose)
/// </summary>
public DiIiS_NA.Core.MPQ.FileFormats.Actor ActorData
{
get
{
return (DiIiS_NA.Core.MPQ.FileFormats.Actor)MPQStorage.Data.Assets[SNOGroup.Actor][(int)SNO].Data;
}
}
public DiIiS_NA.Core.MPQ.FileFormats.ActorData ActorData
=> (DiIiS_NA.Core.MPQ.FileFormats.ActorData)MPQStorage.Data.Assets[SNOGroup.Actor][(int)SNO].Data;
/// <summary>
/// The animation set for actor.
@ -235,8 +232,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
AffixList = new List<Affix>();
//if (tags != null && tags.ContainsKey(MarkerKeys.OnActorSpawnedScript) && tags[MarkerKeys.OnActorSpawnedScript].Id == 178440)
// this.AnimationSet = (Mooege.Common.MPQ.FileFormats.AnimSet)Mooege.Common.MPQ.MPQStorage.Data.Assets[SNOGroup.AnimSet][11849].Data; //OminNPC_Male (Wounded)
// if (tags != null && tags.ContainsKey(MarkerKeys.OnActorSpawnedScript) && tags[MarkerKeys.OnActorSpawnedScript].Id == 178440)
// AnimationSet = (AnimSet)MPQStorage.Data.Assets[SNOGroup.AnimSet][11849].Data; //OminNPC_Male (Wounded)
//else
// if (this.ActorData.AnimSetSNO != -1)
// this.AnimationSet = (Mooege.Common.MPQ.FileFormats.AnimSet)Mooege.Common.MPQ.MPQStorage.Data.Assets[SNOGroup.AnimSet][this.ActorData.AnimSetSNO].Data;
@ -261,7 +258,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
// Listen for quest progress if the actor has a QuestRange attached to it
//foreach (var quest in World.Game.QuestManager.Quests)
if (_questRange != null)
World.Game.QuestManager.OnQuestProgress += new QuestManager.QuestProgressDelegate(quest_OnQuestProgress);
World.Game.QuestManager.OnQuestProgress += quest_OnQuestProgress;
UpdateQuestRangeVisibility();
}

View File

@ -39,7 +39,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
{
if (!MPQStorage.Data.Assets[SNOGroup.Actor].ContainsKey((int)sno))
{
//Logger.Warn("Actor asset not found, Id: {0}", snoId);
Logger.Error("$[underline on white]$Actor asset not found$[/]$, Id: $[underline white]${0}$[/]$ - $[underline white]${1}$[/]$", (int)sno, sno.ToString());
return null;
}
@ -77,7 +77,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
return null;
var actorAsset = MPQStorage.Data.Assets[SNOGroup.Actor][(int)sno];
var actorData = actorAsset.Data as DiIiS_NA.Core.MPQ.FileFormats.Actor;
var actorData = actorAsset.Data as DiIiS_NA.Core.MPQ.FileFormats.ActorData;
if (actorData == null)
{
Logger.Warn("Actor data not found, Id: {0}", sno);

View File

@ -48,7 +48,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
Attributes[GameAttribute.MinimapActive] = true;
Attributes[GameAttribute.Untargetable] = false;
var bossEncounter = ((ActorSNO.Target as DiIiS_NA.Core.MPQ.FileFormats.Actor).TagMap[MarkerKeys.BossEncounter].Target as DiIiS_NA.Core.MPQ.FileFormats.BossEncounter);
var bossEncounter = ((ActorSNO.Target as DiIiS_NA.Core.MPQ.FileFormats.ActorData).TagMap[MarkerKeys.BossEncounter].Target as DiIiS_NA.Core.MPQ.FileFormats.BossEncounter);
DestWorld = bossEncounter.Worlds[0];
switch (DestWorld)
{

View File

@ -4,7 +4,6 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MonsterFF = DiIiS_NA.Core.MPQ.FileFormats.Monster;
using ActorFF = DiIiS_NA.Core.MPQ.FileFormats.Actor;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Pet;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
using DiIiS_NA.GameServer.MessageSystem;

View File

@ -96,7 +96,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem
};
//this.World.Game.WorldGenerator.Actions.Enqueue(() =>
World.Game.WorldGenerator.LoadActor(ActorToSpawnSNO, location, World, ((DiIiS_NA.Core.MPQ.FileFormats.Actor)ActorToSpawnSNO.Target).TagMap);
World.Game.WorldGenerator.LoadActor(ActorToSpawnSNO, location, World, ((DiIiS_NA.Core.MPQ.FileFormats.ActorData)ActorToSpawnSNO.Target).TagMap);
//Mooege.Core.GS.Generators.WorldGenerator.loadActor(ActorToSpawnSNO, location, this.World, ((Mooege.Common.MPQ.FileFormats.Actor)ActorToSpawnSNO.Target).TagMap);
}

View File

@ -2226,7 +2226,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
/// <param name="world">The world to which to add loaded actors</param>
private void LoadLevelAreas(Dictionary<int, List<Scene>> levelAreas, World world)
{
Dictionary<PRTransform, DiIiS_NA.Core.MPQ.FileFormats.Actor> dict = new Dictionary<PRTransform, DiIiS_NA.Core.MPQ.FileFormats.Actor>();
Dictionary<PRTransform, DiIiS_NA.Core.MPQ.FileFormats.ActorData> dict = new Dictionary<PRTransform, DiIiS_NA.Core.MPQ.FileFormats.ActorData>();
foreach (int la in levelAreas.Keys)
{
SNOHandle levelAreaHandle = new SNOHandle(SNOGroup.LevelArea, la);
@ -2270,7 +2270,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
{
var handle = new SNOHandle(207706);
if (handle == null || gizmoLocations.Count == 0) continue;
LazyLoadActor(handle, gizmoLocations.PickRandom(), world, ((DiIiS_NA.Core.MPQ.FileFormats.Actor)handle.Target).TagMap);
LazyLoadActor(handle, gizmoLocations.PickRandom(), world, ((DiIiS_NA.Core.MPQ.FileFormats.ActorData)handle.Target).TagMap);
}
else
foreach (var location in gizmoLocations)
@ -2290,7 +2290,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
seed -= pair.Value;
}
if (gizmoHandle == null) continue;
LazyLoadActor(gizmoHandle, location, world, ((DiIiS_NA.Core.MPQ.FileFormats.Actor)gizmoHandle.Target).TagMap);
LazyLoadActor(gizmoHandle, location, world, ((DiIiS_NA.Core.MPQ.FileFormats.ActorData)gizmoHandle.Target).TagMap);
}
}
@ -2298,7 +2298,7 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
{
var handleChest = new SNOHandle(96993); //leg chest
if (handleChest == null) continue;
var goldenChest = LoadActor(handleChest, gizmoLocations.PickRandom(), world, ((DiIiS_NA.Core.MPQ.FileFormats.Actor)handleChest.Target).TagMap);
var goldenChest = LoadActor(handleChest, gizmoLocations.PickRandom(), world, ((DiIiS_NA.Core.MPQ.FileFormats.ActorData)handleChest.Target).TagMap);
if (goldenChest > 0)
(world.GetActorByGlobalId(goldenChest) as LegendaryChest).ChestActive = true;
}
@ -2657,43 +2657,55 @@ namespace DiIiS_NA.GameServer.GSSystem.GeneratorsSystem
//TODO: Move this out as loading actors can happen even after world was generated
public uint LoadActor(SNOHandle actorHandle, PRTransform location, World world, TagMap tagMap, MonsterType monsterType = MonsterType.Default, int groupId = 0)
{
var actorSno = (ActorSno)actorHandle.Id; // TODO: maybe we can replace SNOHandle
if (world.QuadTree.Query<Waypoint>(new Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 60f)).Count > 0 ||
world.QuadTree.Query<Portal>(new Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 5f)).Count > 0)
try
{
Logger.Debug("Load actor {0} ignored - waypoint nearby.", actorSno);
var actorSno = (ActorSno)actorHandle.Id; // TODO: maybe we can replace SNOHandle
if (world.QuadTree
.Query<Waypoint>(new Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 60f))
.Count > 0 ||
world.QuadTree
.Query<Portal>(new Core.Types.Misc.Circle(location.Vector3D.X, location.Vector3D.Y, 5f)).Count >
0)
{
Logger.Debug("Load actor {0} ignored - waypoint nearby.", actorSno);
return 0;
}
var actor = ActorFactory.Create(world, actorSno, tagMap);
switch (monsterType)
{
case MonsterType.Champion:
actor = new Champion(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
case MonsterType.Elite:
actor = new Rare(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
case MonsterType.EliteMinion:
actor = new RareMinion(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
}
if (actor == null)
{
if (actorSno != ActorSno.__NONE)
Logger.Warn("ActorFactory did not load actor {0}", actorHandle);
return 0;
}
actor.RotationW = location.Quaternion.W;
actor.RotationAxis = location.Quaternion.Vector3D;
actor.EnterWorld(location.Vector3D);
return actor.GlobalID;
}
catch (Exception ex)
{
Logger.Error("Error loading actor {0} at {1}", actorHandle.Id, location);
return 0;
}
var actor = ActorFactory.Create(world, actorSno, tagMap);
switch (monsterType)
{
case MonsterType.Champion:
actor = new Champion(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
case MonsterType.Elite:
actor = new Rare(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
case MonsterType.EliteMinion:
actor = new RareMinion(world, actorSno, tagMap);
actor.GroupId = groupId;
break;
}
if (actor == null)
{
if (actorSno != ActorSno.__NONE)
Logger.Warn("ActorFactory did not load actor {0}", actorHandle);
return 0;
}
actor.RotationW = location.Quaternion.W;
actor.RotationAxis = location.Quaternion.Vector3D;
actor.EnterWorld(location.Vector3D);
return actor.GlobalID;
}
public void LazyLoadActor(SNOHandle actorHandle, PRTransform location, World world, TagMap tagMap, MonsterType monsterType = MonsterType.Default)

View File

@ -14,7 +14,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem.Implementations
public Book(MapSystem.World world, DiIiS_NA.Core.MPQ.FileFormats.GameBalance.ItemTable definition, int cork = -1, bool cork2 = false, int cork3 = -1)
: base(world, definition)
{
var actorData = ActorSNO.Target as DiIiS_NA.Core.MPQ.FileFormats.Actor;
var actorData = ActorSNO.Target as DiIiS_NA.Core.MPQ.FileFormats.ActorData;
if (actorData.TagMap.ContainsKey(ActorKeys.Lore))
{

View File

@ -443,7 +443,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ItemsSystem
{
foreach (var asset in MPQStorage.Data.Assets[SNOGroup.Actor].Values)
{
Actor data = asset.Data as Actor;
ActorData data = asset.Data as ActorData;
if (data != null && data.TagMap.ContainsKey(ActorKeys.Lore))
{
if (Lore.ContainsKey(data.TagMap[ActorKeys.Lore].Id)) continue;

View File

@ -14,13 +14,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ObjectsSystem
/// </summary>
public uint GlobalID
{
get
{
if (GlobalIDOverride > 0)
return GlobalIDOverride;
else
return _globalID;
}
get => GlobalIDOverride > 0 ? GlobalIDOverride : _globalID;
private set
{ }
}

View File

@ -1680,7 +1680,7 @@ public class Player : Actor, IMessageConsumer, IUpdateable
public void OnHirelingSwapAgreeMessage()
{
Hireling hireling = null;
DiIiS_NA.Core.MPQ.FileFormats.Actor Data = null;
DiIiS_NA.Core.MPQ.FileFormats.ActorData Data = null;
if (World.Game.Players.Count > 1) return;
@ -1688,20 +1688,20 @@ public class Player : Actor, IMessageConsumer, IUpdateable
{
case 72061:
//Templar
Data = (DiIiS_NA.Core.MPQ.FileFormats.Actor)MPQStorage.Data.Assets[SNOGroup.Actor][52693].Data;
Data = (DiIiS_NA.Core.MPQ.FileFormats.ActorData)MPQStorage.Data.Assets[SNOGroup.Actor][52693].Data;
hireling = new Templar(World, ActorSno._hireling_templar, Data.TagMap);
hireling.GBHandle.GBID = StringHashHelper.HashItemName("Templar");
break;
case 72738:
//Scoundrel
Data = (DiIiS_NA.Core.MPQ.FileFormats.Actor)MPQStorage.Data.Assets[SNOGroup.Actor][52694].Data;
Data = (DiIiS_NA.Core.MPQ.FileFormats.ActorData)MPQStorage.Data.Assets[SNOGroup.Actor][52694].Data;
hireling = new Templar(World, ActorSno._hireling_scoundrel, Data.TagMap);
hireling.GBHandle.GBID = StringHashHelper.HashItemName("Scoundrel");
break;
case 0:
//Enchantress
Data = (DiIiS_NA.Core.MPQ.FileFormats.Actor)MPQStorage.Data.Assets[SNOGroup.Actor][4482].Data;
Data = (DiIiS_NA.Core.MPQ.FileFormats.ActorData)MPQStorage.Data.Assets[SNOGroup.Actor][4482].Data;
hireling = new Templar(World, ActorSno._hireling_enchantress, Data.TagMap);
hireling.GBHandle.GBID = StringHashHelper.HashItemName("Enchantress");
break;

View File

@ -1426,13 +1426,14 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
Completed = false,
Saveable = true,
NextStep = 14,
Objectives = new List<Objective> { Objective.Default(), Objective.Default() },
Objectives = new List<Objective> { Objective.WithLimit(2) },
OnAdvance = () =>
{ //find 2 Orbs
DestroyFollower(ActorSno._leah);
AddFollower(Game.GetWorld(WorldSno.trout_town), ActorSno._leah);
var world = Game.GetWorld(WorldSno.trout_town);
AddFollower(world, ActorSno._leah);
ListenInteract(ActorSno._a1dun_caves_nephalem_altar_a_chest_03, 1, new CompleteObjective(0));
ListenInteract(ActorSno._a1dun_caves_nephalem_altar_a_chest_03_b, 1, new CompleteObjective(1));
ListenInteract(ActorSno._a1dun_caves_nephalem_altar_a_chest_03_b, 1, new CompleteObjective(0));
}
});
@ -1441,7 +1442,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
Completed = false,
Saveable = true,
NextStep = 30,
Objectives = new List<Objective> { new Objective { Limit = 2, Counter = 0 } },
Objectives = new List<Objective> { Objective.WithLimit(2) },
OnAdvance = () =>
{ //use 2 stones
var world = Game.GetWorld(WorldSno.trout_town);

View File

@ -68,7 +68,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem.QuestEvents.Implementations
{
var counter = 0;
var monsterSNOHandle = new Core.Types.SNO.SNOHandle(SnoId);
var monsterActor = monsterSNOHandle.Target as DiIiS_NA.Core.MPQ.FileFormats.Actor;
var monsterActor = monsterSNOHandle.Target as DiIiS_NA.Core.MPQ.FileFormats.ActorData;
foreach (Vector3D coords in Coordinates)
{

View File

@ -18,7 +18,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem.QuestEvents.Implementations
//Logger.Trace("SpawnSnakemans event started");
var point = new Vector3D { X = 835.331f, Y = 410.121f, Z = 161.842f };
var snakeManHandle = new Core.Types.SNO.SNOHandle((int)ActorSno._khamsin_snakeman_melee);
var snakeManActor = snakeManHandle.Target as DiIiS_NA.Core.MPQ.FileFormats.Actor;
var snakeManActor = snakeManHandle.Target as DiIiS_NA.Core.MPQ.FileFormats.ActorData;
try
{
var caldeumGuard = world.FindActorAt(ActorSno._caldeumguard_cleaver_a, point, 20.0f);

View File

@ -55,6 +55,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
public int Counter;
public static Objective Default() => new () { Limit = 1, Counter = 0 };
public static Objective WithLimit(int limit) => new () { Limit = limit, Counter = 0 };
}
// key can be ActorSno (also multiplied), DestLevelAreaSno, ConversationSno