From 43281da714802d6ebdeaa6a89f2cc16699953df9 Mon Sep 17 00:00:00 2001 From: Noe Caratini <caratinin@gmail.com> Date: Sun, 1 May 2022 18:46:48 +0100 Subject: [PATCH] refactor(quest): Simplified Q00372_LegacyOfInsolence and aligned with retail --- pom.xml | 11 +- .../Q00372_LegacyOfInsolence.java | 591 +++++------------- .../Q00372LegacyOfInsolenceTest.java | 546 ++++++++++++++++ 3 files changed, 727 insertions(+), 421 deletions(-) create mode 100644 src/test/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372LegacyOfInsolenceTest.java diff --git a/pom.xml b/pom.xml index 525ed4fda0..e2f1874fe5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.l2jserver</groupId> - <artifactId>l2j-server-datapack</artifactId> + <artifactId>l2j-server-datapack</artifactId> <version>2.6.3.0-SNAPSHOT</version> <name>L2J DataPack</name> <properties> @@ -14,7 +14,8 @@ <l2j-server-game.version>2.6.3.0-SNAPSHOT</l2j-server-game.version> <!-- Test --> <junit-jupiter.version>5.8.0</junit-jupiter.version> - <mockito.version>3.12.4</mockito.version> + <mockito.version>4.5.1</mockito.version> + <assertj-core.version>3.22.0</assertj-core.version> <!-- Plugins --> <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version> <maven-jar-plugin.version>3.2.0</maven-jar-plugin.version> @@ -62,6 +63,12 @@ <version>${mockito.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>${assertj-core.version}</version> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/src/main/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372_LegacyOfInsolence.java b/src/main/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372_LegacyOfInsolence.java index 9e48f5dd4a..02b573648e 100644 --- a/src/main/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372_LegacyOfInsolence.java +++ b/src/main/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372_LegacyOfInsolence.java @@ -18,395 +18,182 @@ */ package com.l2jserver.datapack.quests.Q00372_LegacyOfInsolence; -import com.l2jserver.gameserver.enums.audio.Sound; import com.l2jserver.gameserver.model.actor.L2Npc; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; -import com.l2jserver.gameserver.model.holders.ItemChanceHolder; import com.l2jserver.gameserver.model.quest.Quest; +import com.l2jserver.gameserver.model.quest.QuestDroplist; import com.l2jserver.gameserver.model.quest.QuestState; -import com.l2jserver.gameserver.util.Util; -import java.util.HashMap; import java.util.Map; /** * Legacy Of Insolence (372) * @author ivantotov + * @author Noé Caratini aka Kita */ public final class Q00372_LegacyOfInsolence extends Quest { + // Misc + private static final int MIN_LEVEL = 59; // NPCs private static final int TRADER_HOLLY = 30839; private static final int WAREHOUSE_KEEPER_WALDERAL = 30844; private static final int MAGISTER_DESMOND = 30855; private static final int ANTIQUE_DEALER_PATRIN = 30929; private static final int CLAUDIA_ATHEBALDT = 31001; + // Monsters + private static final int CORRUPT_SAGE = 20817; + private static final int ERIN_EDIUNCE = 20821; + private static final int HALLATES_INSPECTOR = 20825; + private static final int PLATINUM_TRIBE_OVERLORD = 20829; + private static final int MESSENGER_ANGEL = 21062; + private static final int PLATINUM_GUARDIAN_PREFECT = 21069; // Items private static final int ANCIENT_RED_PAPYRUS = 5966; private static final int ANCIENT_BLUE_PAPYRUS = 5967; private static final int ANCIENT_BLACK_PAPYRUS = 5968; private static final int ANCIENT_WHITE_PAPYRUS = 5969; - private static final int REVELATION_OF_THE_SEALS_CHAPTER_OF_AVARICE = 5972; - private static final int REVELATION_OF_THE_SEALS_CHAPTER_OF_GNOSIS = 5973; - private static final int REVELATION_OF_THE_SEALS_CHAPTER_OF_STRIFE = 5974; - private static final int REVELATION_OF_THE_SEALS_CHAPTER_OF_VENGEANCE = 5975; - private static final int REVELATION_OF_THE_SEALS_CHAPTER_OF_AWEKENING = 5976; - private static final int REVELATION_OF_THE_SEALS_CHAPTER_OF_CALAMITY = 5977; - private static final int REVELATION_OF_THE_SEALS_CHAPTER_OF_DESCENT = 5978; - private static final int ANCIENT_EPIC_CHAPTER_1 = 5979; - private static final int ANCIENT_EPIC_CHAPTER_2 = 5980; - private static final int ANCIENT_EPIC_CHAPTER_3 = 5981; - private static final int ANCIENT_EPIC_CHAPTER_4 = 5982; - private static final int ANCIENT_EPIC_CHAPTER_5 = 5983; - private static final int IMPERIAL_GENEALOGY_1 = 5984; - private static final int IMPERIAL_GENEALOGY_2 = 5985; - private static final int IMPERIAL_GENEALOGY_3 = 5986; - private static final int IMPERIAL_GENEALOGY_4 = 5987; - private static final int IMPERIAL_GENEALOGY_5 = 5988; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR = 5989; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR = 5990; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR = 5991; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR = 5992; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR = 5993; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR = 5994; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR = 5995; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR = 5996; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR = 5997; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR = 5998; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR = 5999; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR = 6000; - private static final int BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR = 6001; + private static final int[] REVELATION_OF_THE_SEALS = {5972, 5973, 5974, 5975, 5976, 5977, 5978}; + private static final int[] ANCIENT_EPIC = {5979, 5980, 5981, 5982, 5983}; + private static final int[] IMPERIAL_GENEALOGY = {5984, 5985, 5986, 5987, 5988}; + private static final int[] BLUEPRINTS = {5989, 5990, 5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999, 6000, 6001}; + // Droplist + private static final QuestDroplist DROPLIST = QuestDroplist.builder() + .addSingleDrop(CORRUPT_SAGE, ANCIENT_RED_PAPYRUS, 30.2) + .addSingleDrop(ERIN_EDIUNCE, ANCIENT_RED_PAPYRUS, 41.0) + .addSingleDrop(HALLATES_INSPECTOR, ANCIENT_RED_PAPYRUS, 44.7) + .addSingleDrop(PLATINUM_TRIBE_OVERLORD, ANCIENT_BLUE_PAPYRUS, 45.1) + .addSingleDrop(MESSENGER_ANGEL, ANCIENT_WHITE_PAPYRUS, 29.0) + .addSingleDrop(PLATINUM_GUARDIAN_PREFECT, ANCIENT_BLACK_PAPYRUS, 28.0) + .build(); + private static final Map<Integer, Integer> QS_KILLER_CHANCE = Map.of( + CORRUPT_SAGE, 1, + ERIN_EDIUNCE, 1, + HALLATES_INSPECTOR, 3, + PLATINUM_TRIBE_OVERLORD, 3, + MESSENGER_ANGEL, 1, + PLATINUM_GUARDIAN_PREFECT, 1 + ); // Rewards - private static final int RECIPE_SEALED_DARK_CRYSTAL_BOOTS_60 = 5368; - private static final int RECIPE_SEALED_TALLUM_BOOTS_60 = 5370; - private static final int RECIPE_SEALED_BOOTS_OF_NIGHTMARE_60 = 5380; - private static final int RECIPE_SEALED_MAJESTIC_BOOTS_60 = 5382; - private static final int RECIPE_SEALED_DARK_CRYSTAL_GLOVES_60 = 5392; - private static final int RECIPE_SEALED_TALLUM_GLOVES_60 = 5394; - private static final int RECIPE_SEALED_GAUNTLETS_OF_NIGHTMARE_60 = 5404; - private static final int RECIPE_SEALED_MAJESTIC_GAUNTLETS_60 = 5406; - private static final int RECIPE_SEALED_DARK_CRYSTAL_HELMET_60 = 5426; - private static final int RECIPE_SEALED_TALLUM_HELMET_60 = 5428; - private static final int RECIPE_SEALED_HELM_OF_NIGHTMARE_60 = 5430; - private static final int RECIPE_SEALED_MAJESTIC_CIRCLET_60 = 5432; - private static final int SEALED_DARK_CRYSTAL_BOOTS_LINING = 5496; - private static final int SEALED_TALLUM_BOOTS_LINING = 5497; - private static final int SEALED_BOOTS_OF_NIGHTMARE_LINING = 5502; - private static final int SEALED_MAJESTIC_BOOTS_LINING = 5503; - private static final int SEALED_DARK_CRYSTAL_GLOVES_DESIGN = 5508; - private static final int SEALED_TALLUM_GLOVES_DESIGN = 5509; - private static final int SEALED_GAUNTLETS_OF_NIGHTMARE_DESIGN = 5514; - private static final int SEALED_MAJESTIC_GAUNTLETS_DESIGN = 5515; - private static final int SEALED_DARK_CRYSTAL_HELMET_DESIGN = 5525; - private static final int SEALED_TALLUM_HELM_DESIGN = 5526; - private static final int SEALED_HELM_OF_NIGHTMARE_DESIGN = 5527; - private static final int SEALED_MAJESTIC_CIRCLET_DESIGN = 5528; - // Monsters - private static final int HALLATES_INSPECTOR = 20825; - private static final Map<Integer, ItemChanceHolder> MONSTER_REWARDS = new HashMap<>(); - - static { - MONSTER_REWARDS.put(20817, new ItemChanceHolder(ANCIENT_RED_PAPYRUS, 302, 1)); - MONSTER_REWARDS.put(20821, new ItemChanceHolder(ANCIENT_RED_PAPYRUS, 410, 1)); - MONSTER_REWARDS.put(HALLATES_INSPECTOR, new ItemChanceHolder(ANCIENT_RED_PAPYRUS, 1, 447)); - MONSTER_REWARDS.put(20829, new ItemChanceHolder(ANCIENT_BLUE_PAPYRUS, 451, 1)); - MONSTER_REWARDS.put(21062, new ItemChanceHolder(ANCIENT_WHITE_PAPYRUS, 290, 1)); - MONSTER_REWARDS.put(21069, new ItemChanceHolder(ANCIENT_BLACK_PAPYRUS, 280, 1)); - } - - // Misc - private static final int MIN_LEVEL = 59; + private static final RewardsGroup REWARDS_DARK_CRYSTAL = new RewardsGroup( + 5496, // Sealed Dark Crystal Boots Lining + 5508, // Sealed Dark Crystal Gloves Design + 5525, // Sealed Dark Crystal Helmet Design + 5368, // Recipe: Sealed Dark Crystal Boots(60%) + 5392, // Recipe: Sealed Dark Crystal Gloves(60%) + 5426 // Recipe: Sealed Dark Crystal Helmet(60%) + ); + private static final RewardsGroup REWARDS_TALLUM = new RewardsGroup( + 5497, // Sealed Tallum Boots Lining + 5509, // Sealed Tallum Gloves Design + 5526, // Sealed Tallum Helm Design + 5370, // Recipe: Sealed Tallum Boots(60%) + 5394, // Recipe: Sealed Tallum Gloves(60%) + 5428 // Recipe: Sealed Tallum Helmet(60%) + ); + private static final RewardsGroup REWARDS_NIGHTMARE = new RewardsGroup( + 5502, // Sealed Boots of Nightmare Lining + 5514, // Sealed Gauntlets of Nightmare Design + 5527, // Sealed Helm of Nightmare Design + 5380, // Recipe: Sealed Boots of Nightmare(60%) + 5404, // Recipe: Sealed Gauntlets of Nightmare(60%) + 5430 // Recipe: Sealed Helm of Nightmare(60%) + ); + private static final RewardsGroup REWARDS_MAJESTIC = new RewardsGroup( + 5503, // Sealed Majestic Boots Lining + 5515, // Sealed Majestic Gauntlets Design + 5528, // Sealed Majestic Circlet Design + 5382, // Recipe: Sealed Majestic Boots(60%) + 5406, // Recipe: Sealed Majestic Gauntlets(60%) + 5432 // Recipe: Sealed Majestic Circlet (60%) + ); + private static final int[] WALDERAL_CHANCES_LOW_A = {10, 20, 30, 40, 51, 62, 79, 100}; + private static final int[] WALDERAL_CHANCES_HIGH_A = {17, 34, 49, 58, 70, 82, 92, 100}; + private static final int[] OTHER_CHANCES_LOW_A = {30, 60, 80, 90, 100}; + private static final int[] OTHER_CHANCES_HIGH_A = {31, 62, 75, 83, 100}; public Q00372_LegacyOfInsolence() { super(372, Q00372_LegacyOfInsolence.class.getSimpleName(), "Legacy Of Insolence"); addStartNpc(WAREHOUSE_KEEPER_WALDERAL); addTalkId(WAREHOUSE_KEEPER_WALDERAL, TRADER_HOLLY, MAGISTER_DESMOND, ANTIQUE_DEALER_PATRIN, CLAUDIA_ATHEBALDT); - addKillId(MONSTER_REWARDS.keySet()); + addKillId(DROPLIST.getNpcIds()); } @Override public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) { final QuestState qs = getQuestState(player, false); - final int chance = getRandom(100); - if (qs == null) { return super.onAdvEvent(event, npc, player); } - String htmltext = null; switch (event) { - case "30844-04.htm": { + case "30844-04.htm" -> { if (qs.isCreated()) { qs.startQuest(); - htmltext = event; - } - break; - } - case "30844-07.html": { - if (hasQuestItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR)) { - htmltext = event; } else { - htmltext = "30844-06.html"; + return null; } - break; } - case "30844-09.html": { - qs.exitQuest(true, true); - htmltext = event; - break; + case "30844-05b.html" -> qs.setCond(2); + case "30844-07.html" -> { + if (!hasQuestItems(player, BLUEPRINTS)) { + return "30844-06.html"; + } } - case "30844-07a.html": { - if (hasQuestItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR)) { - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR, 1); - - if (chance < 10) { - giveItems(player, SEALED_DARK_CRYSTAL_BOOTS_LINING, 1); - } else if (chance < 20) { - giveItems(player, SEALED_DARK_CRYSTAL_GLOVES_DESIGN, 1); - } else if (chance < 30) { - giveItems(player, SEALED_DARK_CRYSTAL_HELMET_DESIGN, 1); - } else if (chance < 40) { - giveItems(player, SEALED_DARK_CRYSTAL_BOOTS_LINING, 1); - giveItems(player, SEALED_DARK_CRYSTAL_GLOVES_DESIGN, 1); - giveItems(player, SEALED_DARK_CRYSTAL_HELMET_DESIGN, 1); - } else if (chance < 51) { - giveItems(player, RECIPE_SEALED_DARK_CRYSTAL_BOOTS_60, 1); - } else if (chance < 62) { - giveItems(player, RECIPE_SEALED_DARK_CRYSTAL_GLOVES_60, 1); - } else if (chance < 79) { - giveItems(player, RECIPE_SEALED_DARK_CRYSTAL_HELMET_60, 1); - } else if (chance < 100) { - giveItems(player, RECIPE_SEALED_DARK_CRYSTAL_BOOTS_60, 1); - giveItems(player, RECIPE_SEALED_DARK_CRYSTAL_GLOVES_60, 1); - giveItems(player, RECIPE_SEALED_DARK_CRYSTAL_HELMET_60, 1); - } - htmltext = event; + case "30844-07a.html" -> { + if (hasQuestItems(player, BLUEPRINTS)) { + takeItems(player, 1, BLUEPRINTS); + walderalGiveRewards(player, REWARDS_DARK_CRYSTAL, WALDERAL_CHANCES_LOW_A); } else { - htmltext = "30844-07e.html"; + return "30844-07e.html"; } - break; } - case "30844-07b.html": { - if (hasQuestItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR)) { - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR, 1); - - if (chance < 10) { - giveItems(player, SEALED_TALLUM_BOOTS_LINING, 1); - } else if (chance < 20) { - giveItems(player, SEALED_TALLUM_GLOVES_DESIGN, 1); - } else if (chance < 30) { - giveItems(player, SEALED_TALLUM_HELM_DESIGN, 1); - } else if (chance < 40) { - giveItems(player, SEALED_TALLUM_BOOTS_LINING, 1); - giveItems(player, SEALED_TALLUM_GLOVES_DESIGN, 1); - giveItems(player, SEALED_TALLUM_HELM_DESIGN, 1); - } else if (chance < 51) { - giveItems(player, RECIPE_SEALED_TALLUM_BOOTS_60, 1); - } else if (chance < 62) { - giveItems(player, RECIPE_SEALED_TALLUM_GLOVES_60, 1); - } else if (chance < 79) { - giveItems(player, RECIPE_SEALED_TALLUM_HELMET_60, 1); - } else if (chance < 100) { - giveItems(player, RECIPE_SEALED_TALLUM_BOOTS_60, 1); - giveItems(player, RECIPE_SEALED_TALLUM_GLOVES_60, 1); - giveItems(player, RECIPE_SEALED_TALLUM_HELMET_60, 1); - } - htmltext = event; + case "30844-07b.html" -> { + if (hasQuestItems(player, BLUEPRINTS)) { + takeItems(player, 1, BLUEPRINTS); + walderalGiveRewards(player, REWARDS_TALLUM, WALDERAL_CHANCES_LOW_A); } else { - htmltext = "30844-07e.html"; + return "30844-07e.html"; } - break; } - case "30844-07c.html": { - if (hasQuestItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR)) { - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR, 1); - - if (chance < 17) { - giveItems(player, SEALED_BOOTS_OF_NIGHTMARE_LINING, 1); - } else if (chance < 34) { - giveItems(player, SEALED_GAUNTLETS_OF_NIGHTMARE_DESIGN, 1); - } else if (chance < 49) { - giveItems(player, SEALED_HELM_OF_NIGHTMARE_DESIGN, 1); - } else if (chance < 58) { - giveItems(player, SEALED_BOOTS_OF_NIGHTMARE_LINING, 1); - giveItems(player, SEALED_GAUNTLETS_OF_NIGHTMARE_DESIGN, 1); - giveItems(player, SEALED_HELM_OF_NIGHTMARE_DESIGN, 1); - } else if (chance < 70) { - giveItems(player, RECIPE_SEALED_BOOTS_OF_NIGHTMARE_60, 1); - } else if (chance < 82) { - giveItems(player, RECIPE_SEALED_GAUNTLETS_OF_NIGHTMARE_60, 1); - } else if (chance < 92) { - giveItems(player, RECIPE_SEALED_HELM_OF_NIGHTMARE_60, 1); - } else if (chance < 100) { - giveItems(player, RECIPE_SEALED_BOOTS_OF_NIGHTMARE_60, 1); - giveItems(player, RECIPE_SEALED_GAUNTLETS_OF_NIGHTMARE_60, 1); - giveItems(player, RECIPE_SEALED_HELM_OF_NIGHTMARE_60, 1); - } - htmltext = event; + case "30844-07c.html" -> { + if (hasQuestItems(player, BLUEPRINTS)) { + takeItems(player, 1, BLUEPRINTS); + walderalGiveRewards(player, REWARDS_NIGHTMARE, WALDERAL_CHANCES_HIGH_A); } else { - htmltext = "30844-07e.html"; + return "30844-07e.html"; } - break; } - case "30844-07d.html": { - if (hasQuestItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, // - BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR)) { - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_1ST_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_2ND_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_3RD_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_4TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_5TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_6TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_7TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_8TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_9TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_10TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_11TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_12TH_FLOOR, 1); - takeItems(player, BLUEPRINT_TOWER_OF_INSOLENCE_13TH_FLOOR, 1); - - if (chance < 17) { - giveItems(player, SEALED_MAJESTIC_BOOTS_LINING, 1); - } else if (chance < 34) { - giveItems(player, SEALED_MAJESTIC_GAUNTLETS_DESIGN, 1); - } else if (chance < 49) { - giveItems(player, SEALED_MAJESTIC_CIRCLET_DESIGN, 1); - } else if (chance < 58) { - giveItems(player, SEALED_MAJESTIC_BOOTS_LINING, 1); - giveItems(player, SEALED_MAJESTIC_GAUNTLETS_DESIGN, 1); - giveItems(player, SEALED_MAJESTIC_CIRCLET_DESIGN, 1); - } else if (chance < 70) { - giveItems(player, RECIPE_SEALED_MAJESTIC_BOOTS_60, 1); - } else if (chance < 82) { - giveItems(player, RECIPE_SEALED_MAJESTIC_GAUNTLETS_60, 1); - } else if (chance < 92) { - giveItems(player, RECIPE_SEALED_MAJESTIC_CIRCLET_60, 1); - } else if (chance < 100) { - giveItems(player, RECIPE_SEALED_MAJESTIC_BOOTS_60, 1); - giveItems(player, RECIPE_SEALED_MAJESTIC_GAUNTLETS_60, 1); - giveItems(player, RECIPE_SEALED_MAJESTIC_CIRCLET_60, 1); - } - htmltext = event; + case "30844-07d.html" -> { + if (hasQuestItems(player, BLUEPRINTS)) { + takeItems(player, 1, BLUEPRINTS); + walderalGiveRewards(player, REWARDS_MAJESTIC, WALDERAL_CHANCES_HIGH_A); } else { - htmltext = "30844-07e.html"; + return "30844-07e.html"; } - break; } - case "30844-05b.html": { - qs.setCond(2); - htmltext = event; - break; + case "30844-09.html" -> qs.exitQuest(true, true); + case "30844-03.htm", "30844-05.html", "30844-05a.html", "30844-08.html", "30844-10.html", "30844-11.html" -> { + return event; } - case "30844-03.htm": - case "30844-05.html": - case "30844-05a.html": - case "30844-08.html": - case "30844-10.html": - case "30844-11.html": { - htmltext = event; - break; + default -> { + return null; } } - return htmltext; + return event; } @Override public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon) { - final ItemChanceHolder item = MONSTER_REWARDS.get(npc.getId()); - if (npc.getId() == HALLATES_INSPECTOR) { - if (getRandom(1000) < item.getChance()) { - final QuestState qs = getRandomPartyMemberState(killer, -1, 3, npc); - if (qs != null) { - giveItems(qs.getPlayer(), item.getId(), item.getCount()); - playSound(qs.getPlayer(), Sound.ITEMSOUND_QUEST_ITEMGET); - } - } - return super.onKill(npc, killer, isSummon); + final QuestState qs = getRandomPartyMemberState(killer, -1, QS_KILLER_CHANCE.get(npc.getId()), npc); + if (qs != null) { + giveItemRandomly(qs.getPlayer(), npc, DROPLIST.get(npc), true); } - - if (Util.checkIfInRange(1500, npc, killer, true) && (getRandom(1000) < item.getChance())) { - L2PcInstance rewardedPlayer = null; - if (!killer.isInParty()) { - final QuestState qs = getQuestState(killer, false); - if ((qs != null) && qs.isStarted()) { - rewardedPlayer = killer; - } - } else { - int chance = 0; - for (L2PcInstance partyMember : killer.getParty().getMembers()) { - final QuestState partyMemberQuestState = getQuestState(partyMember, false); - if ((partyMemberQuestState != null) && partyMemberQuestState.isStarted()) { - final int chance2 = getRandom(1000); - if (chance < chance2) { - chance = chance2; - rewardedPlayer = partyMember; - } - } - } - } - - if ((rewardedPlayer != null) && Util.checkIfInRange(1500, npc, rewardedPlayer, true)) { - giveItems(rewardedPlayer, item.getId(), item.getCount()); - playSound(rewardedPlayer, Sound.ITEMSOUND_QUEST_ITEMGET); - } - } - return super.onKill(npc, killer, isSummon); } @Override public String onTalk(L2Npc npc, L2PcInstance player) { final QuestState qs = getQuestState(player, true); - final int chance = getRandom(100); String htmltext = getNoQuestMsg(player); if (qs.isCreated()) { if (npc.getId() == WAREHOUSE_KEEPER_WALDERAL) { @@ -418,128 +205,94 @@ public final class Q00372_LegacyOfInsolence extends Quest { } } else if (qs.isStarted()) { switch (npc.getId()) { - case WAREHOUSE_KEEPER_WALDERAL: { - htmltext = "30844-05.html"; - break; - } - case TRADER_HOLLY: { - if (hasQuestItems(player, IMPERIAL_GENEALOGY_1, IMPERIAL_GENEALOGY_2, IMPERIAL_GENEALOGY_3, IMPERIAL_GENEALOGY_4, IMPERIAL_GENEALOGY_5)) { - takeItems(player, IMPERIAL_GENEALOGY_1, 1); - takeItems(player, IMPERIAL_GENEALOGY_2, 1); - takeItems(player, IMPERIAL_GENEALOGY_3, 1); - takeItems(player, IMPERIAL_GENEALOGY_4, 1); - takeItems(player, IMPERIAL_GENEALOGY_5, 1); - - if (chance < 30) { - giveItems(player, SEALED_DARK_CRYSTAL_BOOTS_LINING, 1); - } else if (chance < 60) { - giveItems(player, SEALED_DARK_CRYSTAL_GLOVES_DESIGN, 1); - } else if (chance < 80) { - giveItems(player, SEALED_DARK_CRYSTAL_HELMET_DESIGN, 1); - } else if (chance < 90) { - giveItems(player, SEALED_DARK_CRYSTAL_BOOTS_LINING, 1); - giveItems(player, SEALED_DARK_CRYSTAL_GLOVES_DESIGN, 1); - giveItems(player, SEALED_DARK_CRYSTAL_HELMET_DESIGN, 1); - } else if (chance < 100) { - giveAdena(player, 4000, true); - } + case WAREHOUSE_KEEPER_WALDERAL -> htmltext = "30844-05.html"; + case TRADER_HOLLY -> { + if (hasQuestItems(player, IMPERIAL_GENEALOGY)) { + takeItems(player, 1, IMPERIAL_GENEALOGY); + otherGiveRewards(player, REWARDS_DARK_CRYSTAL, OTHER_CHANCES_LOW_A); htmltext = "30839-02.html"; } else { htmltext = "30839-01.html"; } - break; } - case MAGISTER_DESMOND: { - if (hasQuestItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_AVARICE, REVELATION_OF_THE_SEALS_CHAPTER_OF_GNOSIS, REVELATION_OF_THE_SEALS_CHAPTER_OF_STRIFE, // - REVELATION_OF_THE_SEALS_CHAPTER_OF_VENGEANCE, REVELATION_OF_THE_SEALS_CHAPTER_OF_AWEKENING, REVELATION_OF_THE_SEALS_CHAPTER_OF_CALAMITY, // - REVELATION_OF_THE_SEALS_CHAPTER_OF_DESCENT)) { - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_AVARICE, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_GNOSIS, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_STRIFE, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_VENGEANCE, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_AWEKENING, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_CALAMITY, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_DESCENT, 1); - - if (chance < 31) { - giveItems(player, SEALED_MAJESTIC_BOOTS_LINING, 1); - } else if (chance < 62) { - giveItems(player, SEALED_MAJESTIC_GAUNTLETS_DESIGN, 1); - } else if (chance < 75) { - giveItems(player, SEALED_MAJESTIC_CIRCLET_DESIGN, 1); - } else if (chance < 83) { - giveItems(player, SEALED_MAJESTIC_BOOTS_LINING, 1); - giveItems(player, SEALED_MAJESTIC_GAUNTLETS_DESIGN, 1); - giveItems(player, SEALED_MAJESTIC_CIRCLET_DESIGN, 1); - } else if (chance < 100) { - giveAdena(player, 4000, true); - } + case MAGISTER_DESMOND -> { + if (hasQuestItems(player, REVELATION_OF_THE_SEALS)) { + takeItems(player, 1, REVELATION_OF_THE_SEALS); + otherGiveRewards(player, REWARDS_MAJESTIC, OTHER_CHANCES_HIGH_A); htmltext = "30855-02.html"; } else { htmltext = "30855-01.html"; } - break; } - case ANTIQUE_DEALER_PATRIN: { - if (hasQuestItems(player, ANCIENT_EPIC_CHAPTER_1, ANCIENT_EPIC_CHAPTER_2, ANCIENT_EPIC_CHAPTER_3, ANCIENT_EPIC_CHAPTER_4, ANCIENT_EPIC_CHAPTER_5)) { - takeItems(player, ANCIENT_EPIC_CHAPTER_1, 1); - takeItems(player, ANCIENT_EPIC_CHAPTER_2, 1); - takeItems(player, ANCIENT_EPIC_CHAPTER_3, 1); - takeItems(player, ANCIENT_EPIC_CHAPTER_4, 1); - takeItems(player, ANCIENT_EPIC_CHAPTER_5, 1); - - if (chance < 30) { - giveItems(player, SEALED_TALLUM_BOOTS_LINING, 1); - } else if (chance < 60) { - giveItems(player, SEALED_TALLUM_GLOVES_DESIGN, 1); - } else if (chance < 80) { - giveItems(player, SEALED_TALLUM_HELM_DESIGN, 1); - } else if (chance < 90) { - giveItems(player, SEALED_TALLUM_BOOTS_LINING, 1); - giveItems(player, SEALED_TALLUM_GLOVES_DESIGN, 1); - giveItems(player, SEALED_TALLUM_HELM_DESIGN, 1); - } else if (chance < 100) { - giveAdena(player, 4000, true); - } + case ANTIQUE_DEALER_PATRIN -> { + if (hasQuestItems(player, ANCIENT_EPIC)) { + takeItems(player, 1, ANCIENT_EPIC); + otherGiveRewards(player, REWARDS_TALLUM, OTHER_CHANCES_LOW_A); htmltext = "30929-02.html"; } else { - htmltext = "30929-02.html"; + htmltext = "30929-01.html"; } - break; } - case CLAUDIA_ATHEBALDT: { - if (hasQuestItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_AVARICE, REVELATION_OF_THE_SEALS_CHAPTER_OF_GNOSIS, REVELATION_OF_THE_SEALS_CHAPTER_OF_STRIFE, // - REVELATION_OF_THE_SEALS_CHAPTER_OF_VENGEANCE, REVELATION_OF_THE_SEALS_CHAPTER_OF_AWEKENING, REVELATION_OF_THE_SEALS_CHAPTER_OF_CALAMITY, // - REVELATION_OF_THE_SEALS_CHAPTER_OF_DESCENT)) { - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_AVARICE, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_GNOSIS, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_STRIFE, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_VENGEANCE, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_AWEKENING, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_CALAMITY, 1); - takeItems(player, REVELATION_OF_THE_SEALS_CHAPTER_OF_DESCENT, 1); - - if (chance < 31) { - giveItems(player, SEALED_BOOTS_OF_NIGHTMARE_LINING, 1); - } else if (chance < 62) { - giveItems(player, SEALED_GAUNTLETS_OF_NIGHTMARE_DESIGN, 1); - } else if (chance < 75) { - giveItems(player, SEALED_HELM_OF_NIGHTMARE_DESIGN, 1); - } else if (chance < 83) { - giveItems(player, SEALED_BOOTS_OF_NIGHTMARE_LINING, 1); - giveItems(player, SEALED_GAUNTLETS_OF_NIGHTMARE_DESIGN, 1); - giveItems(player, SEALED_HELM_OF_NIGHTMARE_DESIGN, 1); - } else if (chance < 100) { - giveAdena(player, 4000, true); - } + case CLAUDIA_ATHEBALDT -> { + if (hasQuestItems(player, REVELATION_OF_THE_SEALS)) { + takeItems(player, 1, REVELATION_OF_THE_SEALS); + otherGiveRewards(player, REWARDS_NIGHTMARE, OTHER_CHANCES_HIGH_A); htmltext = "31001-02.html"; } else { htmltext = "31001-01.html"; } - break; } } } return htmltext; } + + private void walderalGiveRewards(L2PcInstance player, RewardsGroup rewardsGroup, int[] chances) { + final int chance = getRandom(100); + + if (chance < chances[0]) { + giveItems(player, rewardsGroup.partBoots, 1); + } else if (chance < chances[1]) { + giveItems(player, rewardsGroup.partGloves, 1); + } else if (chance < chances[2]) { + giveItems(player, rewardsGroup.partHelmet, 1); + } else if (chance < chances[3]) { + giveItems(player, rewardsGroup.partBoots, 1); + giveItems(player, rewardsGroup.partGloves, 1); + giveItems(player, rewardsGroup.partHelmet, 1); + } else if (chance < chances[4]) { + giveItems(player, rewardsGroup.recipeBoots, 1); + } else if (chance < chances[5]) { + giveItems(player, rewardsGroup.recipeGloves, 1); + } else if (chance < chances[6]) { + giveItems(player, rewardsGroup.recipeHelmet, 1); + } else if (chance < chances[7]) { + giveItems(player, rewardsGroup.recipeBoots, 1); + giveItems(player, rewardsGroup.recipeGloves, 1); + giveItems(player, rewardsGroup.recipeHelmet, 1); + } + } + + private void otherGiveRewards(L2PcInstance player, RewardsGroup rewardsGroup, int[] chances) { + final int chance = getRandom(100); + + if (chance < chances[0]) { + giveItems(player, rewardsGroup.partBoots, 1); + } else if (chance < chances[1]) { + giveItems(player, rewardsGroup.partGloves, 1); + } else if (chance < chances[2]) { + giveItems(player, rewardsGroup.partHelmet, 1); + } else if (chance < chances[3]) { + giveItems(player, rewardsGroup.partBoots, 1); + giveItems(player, rewardsGroup.partGloves, 1); + giveItems(player, rewardsGroup.partHelmet, 1); + } else if (chance < chances[4]) { + giveAdena(player, 4000, true); + } + } + + private record RewardsGroup( + int partBoots, int partGloves, int partHelmet, + int recipeBoots, int recipeGloves, int recipeHelmet + ) {} } diff --git a/src/test/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372LegacyOfInsolenceTest.java b/src/test/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372LegacyOfInsolenceTest.java new file mode 100644 index 0000000000..b5d44f933a --- /dev/null +++ b/src/test/java/com/l2jserver/datapack/quests/Q00372_LegacyOfInsolence/Q00372LegacyOfInsolenceTest.java @@ -0,0 +1,546 @@ +/* + * Copyright © 2004-2021 L2J DataPack + * + * This file is part of L2J DataPack. + * + * L2J DataPack is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J DataPack is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package com.l2jserver.datapack.quests.Q00372_LegacyOfInsolence; + +import com.l2jserver.gameserver.model.actor.L2Npc; +import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; +import com.l2jserver.gameserver.model.events.ListenerRegisterType; +import com.l2jserver.gameserver.model.itemcontainer.PcInventory; +import com.l2jserver.gameserver.model.items.instance.L2ItemInstance; +import com.l2jserver.gameserver.model.quest.Quest; +import com.l2jserver.gameserver.model.quest.QuestState; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * TODO: Check NPC rewards (need to be able to stub AbstractScript#getRandom()) + * TODO: Check Mob drops (need to be able to stub AbstractScript#giveItemRandomly()) + * @author Noé Caratini aka Kita + */ +@ExtendWith(MockitoExtension.class) +public class Q00372LegacyOfInsolenceTest { + private static final String QUEST_NAME = Q00372_LegacyOfInsolence.class.getSimpleName(); + // Misc + private static final int MIN_LEVEL = 59; + // NPCs + private static final int WRONG_NPC = 1; + private static final int TRADER_HOLLY = 30839; + private static final int WAREHOUSE_KEEPER_WALDERAL = 30844; + private static final int MAGISTER_DESMOND = 30855; + private static final int ANTIQUE_DEALER_PATRIN = 30929; + private static final int CLAUDIA_ATHEBALDT = 31001; + // Monsters + private static final int CORRUPT_SAGE = 20817; + private static final int ERIN_EDIUNCE = 20821; + private static final int HALLATES_INSPECTOR = 20825; + private static final int PLATINUM_TRIBE_OVERLORD = 20829; + private static final int MESSENGER_ANGEL = 21062; + private static final int PLATINUM_GUARDIAN_PREFECT = 21069; + // Items + private static final List<Integer> REVELATION_OF_THE_SEALS = List.of(5972, 5973, 5974, 5975, 5976, 5977, 5978); + private static final List<Integer> ANCIENT_EPIC = List.of(5979, 5980, 5981, 5982, 5983); + private static final List<Integer> IMPERIAL_GENEALOGY = List.of(5984, 5985, 5986, 5987, 5988); + private static final List<Integer> BLUEPRINTS = List.of(5989, 5990, 5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999, 6000, 6001); + + @Mock + private L2PcInstance player; + @Mock + private L2Npc npc; + @Mock + private PcInventory inventory; + @Mock + private QuestState qs; + + @Spy + private Quest quest = new Q00372_LegacyOfInsolence(); + + @BeforeEach + void setUp() { + lenient().when(player.getQuestState(QUEST_NAME)).thenReturn(qs); + lenient().when(player.getInventory()).thenReturn(inventory); + } + + @Test + public void shouldInitQuestCorrectly() { + assertThat(quest.getId()).isEqualTo(372); + assertThat(quest.getRegisteredIds(ListenerRegisterType.NPC)).containsExactlyInAnyOrder( + TRADER_HOLLY, + WAREHOUSE_KEEPER_WALDERAL, + MAGISTER_DESMOND, + ANTIQUE_DEALER_PATRIN, + CLAUDIA_ATHEBALDT, + CORRUPT_SAGE, + ERIN_EDIUNCE, + HALLATES_INSPECTOR, + PLATINUM_TRIBE_OVERLORD, + MESSENGER_ANGEL, + PLATINUM_GUARDIAN_PREFECT + ); + } + + @Test + public void onAdvEventWithNoQuestStateShouldReturnNull() { + when(player.getQuestState(QUEST_NAME)).thenReturn(null); + + String result = quest.onAdvEvent("30844-04.htm", npc, player); + + assertThat(result).isNull(); + } + + @Test + public void onAdvEventWithUnsupportedEventShouldReturnNull() { + String event = "00001-01.htm"; + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isNull(); + } + + @Test + public void onAdvEventWalderalStartQuest() { + String event = "30844-04.htm"; + when(qs.isCreated()).thenReturn(true); + + String result = quest.onAdvEvent(event, npc, player); + + verify(qs).startQuest(); + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventWalderalQuestAlreadyStarted() { + String event = "30844-04.htm"; + when(qs.isCreated()).thenReturn(false); + + String result = quest.onAdvEvent(event, npc, player); + + verify(qs, never()).startQuest(); + assertThat(result).isNull(); + } + + @Test + public void onAdvEventWalderalOtherBooks() { + String event = "30844-05b.html"; + + String result = quest.onAdvEvent(event, npc, player); + + verify(qs).setCond(2); + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventWalderalNotAllBlueprints() { + String event = "30844-07.html"; + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo("30844-06.html"); + } + + @Test + public void onAdvEventWalderalAllBlueprints() { + String event = "30844-07.html"; + L2ItemInstance item = mock(L2ItemInstance.class); + BLUEPRINTS.forEach(itemId -> when(inventory.getItemByItemId(itemId)).thenReturn(item)); + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventWalderalDarkCrystalAllBlueprints() { + String event = "30844-07a.html"; + BLUEPRINTS.forEach(this::stubInventoryItem); + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventWalderalDarkCrystalNotAllBlueprints() { + String event = "30844-07a.html"; + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo("30844-07e.html"); + } + + @Test + public void onAdvEventWalderalTallumAllBlueprints() { + String event = "30844-07b.html"; + BLUEPRINTS.forEach(this::stubInventoryItem); + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventWalderalTallumNotAllBlueprints() { + String event = "30844-07b.html"; + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo("30844-07e.html"); + } + + @Test + public void onAdvEventWalderalNightmareAllBlueprints() { + String event = "30844-07c.html"; + BLUEPRINTS.forEach(this::stubInventoryItem); + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventWalderalNightmareNotAllBlueprints() { + String event = "30844-07c.html"; + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo("30844-07e.html"); + } + + @Test + public void onAdvEventWalderalMajesticAllBlueprints() { + String event = "30844-07c.html"; + BLUEPRINTS.forEach(this::stubInventoryItem); + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventWalderalMajesticNotAllBlueprints() { + String event = "30844-07c.html"; + + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo("30844-07e.html"); + } + + @Test + public void onAdvEventWalderalAbortQuest() { + String event = "30844-09.html"; + + String result = quest.onAdvEvent(event, npc, player); + + verify(qs).exitQuest(true, true); + assertThat(result).isEqualTo(event); + } + + @Test + public void onAdvEventOtherSupportedEvents() { + List.of("30844-03.htm", "30844-05.html", "30844-05a.html", "30844-08.html", "30844-10.html", "30844-11.html") + .forEach(event -> { + String result = quest.onAdvEvent(event, npc, player); + + assertThat(result).isEqualTo(event); + }); + } + + @Test + public void onTalkShouldInitQuestStateForPlayer() { + when(player.getQuestState(QUEST_NAME)).thenReturn(null); + + quest.onTalk(npc, player); + + verify(quest).newQuestState(player); + } + + @Test + public void onTalkToWrongNpcWithStateCreated() { + when(qs.isCreated()).thenReturn(true); + when(npc.getId()).thenReturn(WRONG_NPC); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(Quest.getNoQuestMsg(player)); + } + + @Test + public void onTalkToWalderalWithStateCreatedAndLevelTooLow() { + when(qs.isCreated()).thenReturn(true); + when(npc.getId()).thenReturn(WAREHOUSE_KEEPER_WALDERAL); + when(player.getLevel()).thenReturn(MIN_LEVEL - 1); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(WAREHOUSE_KEEPER_WALDERAL + "-01.htm"); + } + + @Test + public void onTalkToWalderalWithStateCreated() { + when(qs.isCreated()).thenReturn(true); + when(npc.getId()).thenReturn(WAREHOUSE_KEEPER_WALDERAL); + when(player.getLevel()).thenReturn(MIN_LEVEL); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(WAREHOUSE_KEEPER_WALDERAL + "-02.htm"); + } + + @Test + public void onTalkToHollyWithStateCreated() { + when(qs.isCreated()).thenReturn(true); + when(npc.getId()).thenReturn(TRADER_HOLLY); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(Quest.getNoQuestMsg(player)); + } + + @Test + public void onTalkToDesmondWithStateCreated() { + when(qs.isCreated()).thenReturn(true); + when(npc.getId()).thenReturn(MAGISTER_DESMOND); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(Quest.getNoQuestMsg(player)); + } + + @Test + public void onTalkToPatrinWithStateCreated() { + when(qs.isCreated()).thenReturn(true); + when(npc.getId()).thenReturn(ANTIQUE_DEALER_PATRIN); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(Quest.getNoQuestMsg(player)); + } + + @Test + public void onTalkToClaudiaWithStateCreated() { + when(qs.isCreated()).thenReturn(true); + when(npc.getId()).thenReturn(CLAUDIA_ATHEBALDT); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(Quest.getNoQuestMsg(player)); + } + + @Test + public void onTalkToWrongNpcWithStateStarted() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(WRONG_NPC); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(Quest.getNoQuestMsg(player)); + } + + @Test + public void onTalkToWalderalWithStateStarted() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(WAREHOUSE_KEEPER_WALDERAL); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(WAREHOUSE_KEEPER_WALDERAL + "-05.html"); + } + + @Test + public void onTalkToHollyWithStateStarted() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(TRADER_HOLLY); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(TRADER_HOLLY + "-01.html"); + } + + @Test + public void onTalkToHollyWithStateStartedAndAllItems() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(TRADER_HOLLY); + IMPERIAL_GENEALOGY.forEach(this::stubInventoryItem); + + String result = quest.onTalk(npc, player); + + List<Integer> removedItemIds = verifyItemsRemoved(player, IMPERIAL_GENEALOGY); + assertThat(removedItemIds).containsExactlyInAnyOrderElementsOf(IMPERIAL_GENEALOGY); + assertThat(result).isEqualTo(TRADER_HOLLY + "-02.html"); + } + + @Test + public void onTalkToDesmondWithStateStarted() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(MAGISTER_DESMOND); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(MAGISTER_DESMOND + "-01.html"); + } + + @Test + public void onTalkToDesmondWithStateStartedAndAllItems() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(MAGISTER_DESMOND); + REVELATION_OF_THE_SEALS.forEach(this::stubInventoryItem); + + String result = quest.onTalk(npc, player); + + List<Integer> removedItemIds = verifyItemsRemoved(player, REVELATION_OF_THE_SEALS); + assertThat(removedItemIds).containsExactlyInAnyOrderElementsOf(REVELATION_OF_THE_SEALS); + assertThat(result).isEqualTo(MAGISTER_DESMOND + "-02.html"); + } + + @Test + public void onTalkToPatrinWithStateStarted() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(ANTIQUE_DEALER_PATRIN); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(ANTIQUE_DEALER_PATRIN + "-01.html"); + } + + @Test + public void onTalkToPatrinWithStateStartedAndAllItems() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(ANTIQUE_DEALER_PATRIN); + ANCIENT_EPIC.forEach(this::stubInventoryItem); + + String result = quest.onTalk(npc, player); + + List<Integer> removedItemIds = verifyItemsRemoved(player, ANCIENT_EPIC); + assertThat(removedItemIds).containsExactlyInAnyOrderElementsOf(ANCIENT_EPIC); + assertThat(result).isEqualTo(ANTIQUE_DEALER_PATRIN + "-02.html"); + } + + @Test + public void onTalkToClaudiaWithStateStarted() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(CLAUDIA_ATHEBALDT); + + String result = quest.onTalk(npc, player); + + assertThat(result).isEqualTo(CLAUDIA_ATHEBALDT + "-01.html"); + } + + @Test + public void onTalkToClaudiaWithStateStartedAndAllItems() { + when(qs.isStarted()).thenReturn(true); + when(npc.getId()).thenReturn(CLAUDIA_ATHEBALDT); + REVELATION_OF_THE_SEALS.forEach(this::stubInventoryItem); + + String result = quest.onTalk(npc, player); + + List<Integer> removedItemIds = verifyItemsRemoved(player, REVELATION_OF_THE_SEALS); + assertThat(removedItemIds).containsExactlyInAnyOrderElementsOf(REVELATION_OF_THE_SEALS); + assertThat(result).isEqualTo(CLAUDIA_ATHEBALDT + "-02.html"); + } + + @Test + public void onKillCorruptSageShouldGetQuestStateWithCorrectPlayerChance() { + when(npc.getId()).thenReturn(CORRUPT_SAGE); + + quest.onKill(npc, player, false); + + verify(quest).getRandomPartyMemberState(player, -1, 1, npc); + } + + @Test + public void onKillErinEdiunceShouldGetQuestStateWithCorrectPlayerChance() { + when(npc.getId()).thenReturn(ERIN_EDIUNCE); + + quest.onKill(npc, player, false); + + verify(quest).getRandomPartyMemberState(player, -1, 1, npc); + } + + @Test + public void onKillHallatesInspectorShouldGetQuestStateWithCorrectPlayerChance() { + when(npc.getId()).thenReturn(HALLATES_INSPECTOR); + + quest.onKill(npc, player, false); + + verify(quest).getRandomPartyMemberState(player, -1, 3, npc); + } + + @Test + public void onKillPlatinumOverlordShouldGetQuestStateWithCorrectPlayerChance() { + when(npc.getId()).thenReturn(PLATINUM_TRIBE_OVERLORD); + + quest.onKill(npc, player, false); + + verify(quest).getRandomPartyMemberState(player, -1, 3, npc); + } + + @Test + public void onKillMessengerAngelShouldGetQuestStateWithCorrectPlayerChance() { + when(npc.getId()).thenReturn(MESSENGER_ANGEL); + + quest.onKill(npc, player, false); + + verify(quest).getRandomPartyMemberState(player, -1, 1, npc); + } + + @Test + public void onKillPlatinumPrefectShouldGetQuestStateWithCorrectPlayerChance() { + when(npc.getId()).thenReturn(PLATINUM_GUARDIAN_PREFECT); + + quest.onKill(npc, player, false); + + verify(quest).getRandomPartyMemberState(player, -1, 1, npc); + } + + private void stubInventoryItem(Integer itemId) { + L2ItemInstance item = mock(L2ItemInstance.class); + when(item.getId()).thenReturn(itemId); + when(item.getCount()).thenReturn(2L); + when(inventory.getItemByItemId(itemId)).thenReturn(item); + when(inventory.getItemsByItemId(itemId)).thenReturn(List.of(item)); + } + + private List<Integer> verifyItemsRemoved(L2PcInstance player, List<Integer> itemIds) { + ArgumentCaptor<Integer> intCaptor = ArgumentCaptor.forClass(Integer.class); + verify(player, times(itemIds.size())).destroyItemByItemId( + eq("Quest"), + intCaptor.capture(), + eq(1L), + any(), + anyBoolean()); + return intCaptor.getAllValues(); + } +} -- GitLab