diff --git a/Maple2.File.Parser/Maple2.File.Parser.csproj b/Maple2.File.Parser/Maple2.File.Parser.csproj
index ab4ad23..5917e98 100644
--- a/Maple2.File.Parser/Maple2.File.Parser.csproj
+++ b/Maple2.File.Parser/Maple2.File.Parser.csproj
@@ -13,7 +13,7 @@
MapleStory2, File, Parser, m2d, xml
true
- 2.4.33
+ 2.4.34
net8.0
README.md
enable
diff --git a/Maple2.File.Parser/ServerTableParser.cs b/Maple2.File.Parser/ServerTableParser.cs
index 2a1e101..c959bd0 100644
--- a/Maple2.File.Parser/ServerTableParser.cs
+++ b/Maple2.File.Parser/ServerTableParser.cs
@@ -44,6 +44,7 @@ public class ServerTableParser {
private readonly XmlSerializer spawnInteractObjectSerializer;
private readonly XmlSerializer groupSpawnSerializer;
private readonly XmlSerializer shadowExpeditionDropSerializer;
+ private readonly XmlSerializer additionalEffectGroupSerializer;
private readonly XmlSerializer fishSerializer;
private readonly XmlSerializer fishingSpotSerializer;
private readonly XmlSerializer fishLureSerializer;
@@ -93,6 +94,7 @@ public ServerTableParser(M2dReader xmlReader) {
spawnInteractObjectSerializer = new XmlSerializer(typeof(SpawnInteractObjectRoot));
groupSpawnSerializer = new XmlSerializer(typeof(GroupSpawnRoot));
shadowExpeditionDropSerializer = new XmlSerializer(typeof(ShadowExpeditionDropRoot));
+ additionalEffectGroupSerializer = new XmlSerializer(typeof(AdditionalEffectGroupRoot));
fishSerializer = new XmlSerializer(typeof(FishRoot));
fishingSpotSerializer = new XmlSerializer(typeof(FishingSpotRoot));
fishLureSerializer = new XmlSerializer(typeof(FishLureRoot));
@@ -524,6 +526,17 @@ public IEnumerable ParseShadowExpeditionDrop() {
}
}
+ public IEnumerable<(int Id, AdditionalEffectGroup Group)> ParseAdditionalEffectGroup() {
+ string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry("table/Server/additionalEffectGroup.xml")));
+ var reader = XmlReader.Create(new StringReader(xml));
+ var data = additionalEffectGroupSerializer.Deserialize(reader) as AdditionalEffectGroupRoot;
+ Debug.Assert(data != null);
+
+ foreach (AdditionalEffectGroup group in data.group) {
+ yield return (group.groupId, group);
+ }
+ }
+
public IEnumerable<(int Id, Fish Fish)> ParseFish() {
string xml = Sanitizer.RemoveEmpty(xmlReader.GetString(xmlReader.GetEntry("table/Server/fish.xml")));
var reader = XmlReader.Create(new StringReader(xml));
diff --git a/Maple2.File.Parser/Xml/Npc/AdditionalEffect.cs b/Maple2.File.Parser/Xml/Npc/AdditionalEffect.cs
index d550322..77acf1d 100644
--- a/Maple2.File.Parser/Xml/Npc/AdditionalEffect.cs
+++ b/Maple2.File.Parser/Xml/Npc/AdditionalEffect.cs
@@ -5,7 +5,7 @@ namespace Maple2.File.Parser.Xml.Npc;
public partial class AdditionalEffect {
[M2dArray] public int[] codes = Array.Empty();
[M2dArray] public short[] levels = Array.Empty();
- [M2dArray(Delimiter = ':')] public string[] group = Array.Empty();
+ [M2dArray] public int[] group = Array.Empty();
[M2dArray] public int[] rewardCodes = Array.Empty();
[M2dArray] public short[] rewardLevels = Array.Empty();
}
diff --git a/Maple2.File.Parser/Xml/Table/Server/AdditionalEffectGroup.cs b/Maple2.File.Parser/Xml/Table/Server/AdditionalEffectGroup.cs
new file mode 100644
index 0000000..ee868a3
--- /dev/null
+++ b/Maple2.File.Parser/Xml/Table/Server/AdditionalEffectGroup.cs
@@ -0,0 +1,22 @@
+using System.Xml.Serialization;
+using M2dXmlGenerator;
+
+namespace Maple2.File.Parser.Xml.Table.Server;
+
+// ./data/server/table/Server/additionalEffectGroup.xml
+// An npc's names group G and how many of its rows to roll.
+[XmlRoot("ms2")]
+public class AdditionalEffectGroupRoot {
+ [XmlElement] public List group;
+}
+
+public partial class AdditionalEffectGroup {
+ [XmlAttribute] public int groupId;
+ [XmlElement] public List value;
+
+ // One row is one buff. Two ids are a visible effect plus its hidden driver or splash helper.
+ public partial class Value {
+ [M2dArray] public int[] effectId = Array.Empty();
+ [M2dArray] public short[] effectLevel = Array.Empty();
+ }
+}
diff --git a/Maple2.File.Tests/NpcParserTest.cs b/Maple2.File.Tests/NpcParserTest.cs
index 919f7dd..6bcb523 100644
--- a/Maple2.File.Tests/NpcParserTest.cs
+++ b/Maple2.File.Tests/NpcParserTest.cs
@@ -29,6 +29,22 @@ public void TestNpcParser() {
Assert.AreEqual(7535, count);
}
+ [TestMethod]
+ public void TestNpcAdditionalEffectGroup() {
+ var locale = Locale.NA;
+ Filter.Load(TestUtils.XmlReader, locale.ToString(), "Live");
+ var parser = new NpcParser(TestUtils.XmlReader, "en");
+
+ // npc 49300001 (Destroyer), ShadowExpedition:
+ // npc 21000001 (Orange Mushroom): group=""
+ Dictionary npcs = parser.Parse()
+ .Where(entry => entry.Id is 49300001 or 21000001)
+ .ToDictionary(entry => entry.Id, entry => entry.Data);
+ CollectionAssert.AreEqual(new[] { 92900999 }, npcs[49300001].additionalEffect.codes);
+ CollectionAssert.AreEqual(new[] { 101, 2 }, npcs[49300001].additionalEffect.group);
+ Assert.AreEqual(0, npcs[21000001].additionalEffect.group.Length);
+ }
+
[TestMethod]
public void TestNpcParserNew() {
var locale = Locale.KR;
diff --git a/Maple2.File.Tests/ServerTableParserTest.cs b/Maple2.File.Tests/ServerTableParserTest.cs
index 979f80e..a037be6 100644
--- a/Maple2.File.Tests/ServerTableParserTest.cs
+++ b/Maple2.File.Tests/ServerTableParserTest.cs
@@ -289,6 +289,26 @@ public void TestShadowExpeditionDrop() {
CollectionAssert.AreEqual(new[] { 920001002, 920006034, 920000034, 820000034 }, last.dropBoxId);
}
+ [TestMethod]
+ public void TestAdditionalEffectGroup() {
+ var parser = new ServerTableParser(TestUtils.ServerReader);
+
+ Dictionary groups = parser.ParseAdditionalEffectGroup()
+ .ToDictionary(entry => entry.Id, entry => entry.Group);
+ CollectionAssert.AreEquivalent(new[] { 1, 101, 999 }, groups.Keys.ToArray());
+ Assert.AreEqual(9, groups[1].value.Count);
+ Assert.AreEqual(7, groups[101].value.Count);
+ Assert.AreEqual(1, groups[999].value.Count);
+
+ // group 101, first row:
+ CollectionAssert.AreEqual(new[] { 60125001, 60125002 }, groups[101].value[0].effectId);
+ CollectionAssert.AreEqual(new short[] { 1, 1 }, groups[101].value[0].effectLevel);
+
+ // group 1, fourth row:
+ CollectionAssert.AreEqual(new[] { 60128001 }, groups[1].value[3].effectId);
+ CollectionAssert.AreEqual(new short[] { 2 }, groups[1].value[3].effectLevel);
+ }
+
[TestMethod]
public void TestSpawnInteractObject() {
var parser = new ServerTableParser(TestUtils.ServerReader);