Forráskód Böngészése

feat(questdroplist): Added support for required items

This allows to add a list of required items for a particular drop entry, removing the need to create a separate map.
Noe Caratini 3 éve
szülő
commit
7802cc3bca

+ 48 - 4
src/main/java/com/l2jserver/gameserver/model/quest/QuestDroplist.java

@@ -34,8 +34,10 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @author Noé Caratini aka Kita
@@ -127,13 +129,20 @@ public class QuestDroplist {
 
     public static class QuestDropListBuilder {
         private final Map<Integer, List<QuestDropInfo>> dropList = new HashMap<>();
+        private Map.Entry<Integer, QuestDropInfo> lastAdded = null;
 
-        public QuestDropListBuilder addSingleDrop(int npcId, QuestItemChanceHolder questItem, long minAmount, long maxAmount, double chance) {
+        public QuestDropListBuilder addSingleDrop(int npcId, QuestItemChanceHolder questItem, long minAmount, long maxAmount, double chance, int[] requiredItemIds) {
             List<QuestDropInfo> dropsForMob = dropList.computeIfAbsent(npcId, ArrayList::new);
-            dropsForMob.add(new QuestDropInfo(questItem, singleDropItem(questItem.getId(), minAmount, maxAmount, chance)));
+            QuestDropInfo dropInfo = new QuestDropInfo(questItem, singleDropItem(questItem.getId(), minAmount, maxAmount, chance), requiredItemIds);
+            dropsForMob.add(dropInfo);
+            updateLastAdded(npcId, dropInfo);
             return this;
         }
 
+        public QuestDropListBuilder addSingleDrop(int npcId, QuestItemChanceHolder questItem, long minAmount, long maxAmount, double chance) {
+            return addSingleDrop(npcId, questItem, minAmount, maxAmount, chance, null);
+        }
+
         public QuestDropListBuilder addSingleDrop(int npcId, QuestItemChanceHolder questItem) {
             return addSingleDrop(npcId, questItem, questItem.getCount(), questItem.getCount(), questItem.getChance());
         }
@@ -173,6 +182,25 @@ public class QuestDroplist {
                     new QuestItemChanceHolder(itemId, chance, amount, 0));
         }
 
+        public QuestDropListBuilder withRequiredItems(int... itemIds) {
+            if (lastAdded == null) {
+                throw new IllegalStateException("Cannot add required items without adding a drop first.");
+            }
+
+            int[] uniqueItemIds = Optional.ofNullable(itemIds)
+                    .map(ids -> Arrays.stream(ids).distinct().toArray())
+                    .orElse(null);
+
+            QuestDropInfo oldDropInfo = lastAdded.getValue();
+            QuestDropInfo newDropInfo = new QuestDropInfo(oldDropInfo.item(), oldDropInfo.drop(), uniqueItemIds);
+
+            List<QuestDropInfo> dropsForNpc = dropList.get(lastAdded.getKey());
+            dropsForNpc.remove(oldDropInfo);
+            dropsForNpc.add(newDropInfo);
+            updateLastAdded(lastAdded.getKey(), newDropInfo);
+            return this;
+        }
+
         public SingleDropBuilder bulkAddSingleDrop(QuestItemChanceHolder questItem) {
             return new SingleDropBuilder(this, questItem);
         }
@@ -188,6 +216,7 @@ public class QuestDroplist {
         private QuestDropListBuilder addGroupedDrop(int npcId, QuestDropInfo dropInfo) {
             List<QuestDropInfo> dropsForMob = dropList.computeIfAbsent(npcId, ArrayList::new);
             dropsForMob.add(dropInfo);
+            updateLastAdded(npcId, dropInfo);
             return this;
         }
 
@@ -199,6 +228,10 @@ public class QuestDroplist {
             return new GroupedDropForSingleItemBuilder(this, npcId, questItem, chanceForGroup);
         }
 
+        private void updateLastAdded(int npcId, QuestDropInfo dropInfo) {
+            lastAdded = Map.entry(npcId, dropInfo);
+        }
+
         public QuestDroplist build() {
             return new QuestDroplist(this);
         }
@@ -208,6 +241,7 @@ public class QuestDroplist {
             private final QuestItemChanceHolder item;
 
             private final Set<Integer> npcIds = new HashSet<>();
+            private int[] requiredItems = null;
 
             public SingleDropBuilder(QuestDropListBuilder parentBuilder, QuestItemChanceHolder item) {
                 this.parentBuilder = parentBuilder;
@@ -223,8 +257,13 @@ public class QuestDroplist {
                 return withNpcs(Arrays.stream(npcIds).boxed().collect(Collectors.toSet()));
             }
 
+            public SingleDropBuilder withRequiredItems(int... itemIds) {
+                requiredItems = itemIds;
+                return this;
+            }
+
             public QuestDropListBuilder build() {
-                npcIds.forEach(npcId -> parentBuilder.addSingleDrop(npcId, item));
+                npcIds.forEach(npcId -> parentBuilder.addSingleDrop(npcId, item).withRequiredItems(requiredItems));
                 return parentBuilder;
             }
         }
@@ -300,7 +339,12 @@ public class QuestDroplist {
         }
     }
 
-    public record QuestDropInfo(QuestItemChanceHolder item, IDropItem drop) {
+    public record QuestDropInfo(QuestItemChanceHolder item, IDropItem drop, int[] requiredItems) {
+
+        public QuestDropInfo(QuestItemChanceHolder item, IDropItem drop) {
+            this(item, drop, null);
+        }
+
         public long getLimit() {
             return item.getLimit();
         }

+ 86 - 0
src/test/java/com/l2jserver/gameserver/model/quest/QuestDroplistTest.java

@@ -15,6 +15,7 @@ import java.util.Set;
 import java.util.stream.IntStream;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
@@ -174,6 +175,59 @@ public class QuestDroplistTest {
         assertThat(dropInfo.item().getLimit()).isEqualTo(0);
     }
 
+    @Test
+    public void shouldAddSingleDropWithRequiredItems() {
+        int[] requiredItemIds = {10, 11};
+
+        QuestDroplist dropList = QuestDroplist.builder()
+                .addSingleDrop(1, QUEST_ITEM_1).withRequiredItems(requiredItemIds)
+                .build();
+
+        QuestDropInfo dropInfo = dropList.get(1);
+        assertThat(dropInfo).isNotNull();
+        assertThat(dropInfo.item()).isEqualTo(QUEST_ITEM_1);
+        assertThat(dropInfo.getLimit()).isEqualTo(QUEST_ITEM_1.getLimit());
+        assertThat(dropInfo.requiredItems()).isEqualTo(requiredItemIds);
+    }
+
+    @Test
+    public void shouldAddRequiredItemsWithoutDuplicates() {
+        int[] requiredItemIds = {10, 11};
+
+        QuestDroplist dropList = QuestDroplist.builder()
+                .addSingleDrop(1, QUEST_ITEM_1).withRequiredItems(10, 11, 11)
+                .build();
+
+        QuestDropInfo dropInfo = dropList.get(1);
+        assertThat(dropInfo).isNotNull();
+        assertThat(dropInfo.item()).isEqualTo(QUEST_ITEM_1);
+        assertThat(dropInfo.getLimit()).isEqualTo(QUEST_ITEM_1.getLimit());
+        assertThat(dropInfo.requiredItems()).isEqualTo(requiredItemIds);
+    }
+
+    @Test
+    public void shouldThrowExceptionWhenAddingRequiredItemsWithoutDrop() {
+        assertThatIllegalStateException().isThrownBy(() ->
+                QuestDroplist.builder()
+                        .withRequiredItems(1, 2)
+                        .build());
+    }
+
+    @Test
+    public void shouldOverwriteRequiredItemsIfCalledTwice() {
+        int[] requiredItemIds = {2, 3};
+
+        QuestDroplist dropList = QuestDroplist.builder()
+                .addSingleDrop(1, QUEST_ITEM_1).withRequiredItems(1, 2).withRequiredItems(requiredItemIds)
+                .build();
+
+        QuestDropInfo dropInfo = dropList.get(1);
+        assertThat(dropInfo).isNotNull();
+        assertThat(dropInfo.item()).isEqualTo(QUEST_ITEM_1);
+        assertThat(dropInfo.getLimit()).isEqualTo(QUEST_ITEM_1.getLimit());
+        assertThat(dropInfo.requiredItems()).isEqualTo(requiredItemIds);
+    }
+
     @Test
     public void shouldBulkAddSingleDrop() {
         QuestDroplist dropList = QuestDroplist.builder()
@@ -243,6 +297,23 @@ public class QuestDroplistTest {
         });
     }
 
+    @Test
+    public void shouldBulkAddSingleDropWithRequiredItems() {
+        int[] requiredItemIds = {10, 11, 12};
+
+        QuestDroplist dropList = QuestDroplist.builder()
+                .addSingleDrop(1, QUEST_ITEM_1)
+                .bulkAddSingleDrop(QUEST_ITEM_1).withNpcs(2, 3, 4).withRequiredItems(requiredItemIds).build()
+                .build();
+
+        IntStream.range(2, 5).forEach(npcId -> {
+            QuestDropInfo dropInfo = dropList.get(npcId);
+            assertThat(dropInfo).isNotNull();
+            assertThat(dropInfo.item()).isEqualTo(QUEST_ITEM_1);
+            assertThat(dropInfo.requiredItems()).isEqualTo(requiredItemIds);
+        });
+    }
+
     @Test
     public void shouldAddGroupedDrop() {
         QuestDroplist dropList = QuestDroplist.builder()
@@ -406,6 +477,21 @@ public class QuestDroplistTest {
         });
     }
 
+    @Test
+    public void shouldAddGroupedDropWithRequiredItems() {
+        int[] requiredItemIds = {10, 11, 12};
+
+        QuestDroplist dropList = QuestDroplist.builder()
+                .addSingleDrop(1, QUEST_ITEM_1)
+                .addGroupedDrop(2, 100.0).withDropItem(QUEST_ITEM_2).withDropItem(QUEST_ITEM_3)
+                .build().withRequiredItems(requiredItemIds)
+                .build();
+
+        QuestDropInfo dropInfo = dropList.get(2);
+        assertThat(dropInfo).isNotNull();
+        assertThat(dropInfo.requiredItems()).isEqualTo(requiredItemIds);
+    }
+
     @Test
     public void shouldAddGroupedDropForSingleItem() {
         long amount1 = 3;