diff --git a/data/conf/zones/deniran.xml b/data/conf/zones/deniran.xml index ab5423f454..1b3d20fa14 100644 --- a/data/conf/zones/deniran.xml +++ b/data/conf/zones/deniran.xml @@ -1033,6 +1033,7 @@ Entrance fee is 10 money + diff --git a/data/script/region/atlantis/city/exterior/ZelanNPC.lua b/data/script/region/atlantis/city/exterior/ZelanNPC.lua deleted file mode 100644 index e2525440a0..0000000000 --- a/data/script/region/atlantis/city/exterior/ZelanNPC.lua +++ /dev/null @@ -1,63 +0,0 @@ ---[[ - *************************************************************************** - * Copyright © 2020 - Arianne * - *************************************************************************** - *************************************************************************** - * * - * This program 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 2 of the License, or * - * (at your option) any later version. * - * * - *************************************************************************** -]] - - -local zoneName = "-7_deniran_atlantis" - -if game:setZone(zoneName) then - local zelan = entities:createSpeakerNPC("Zelan") - - -- NPC appearance & behavior - zelan:setEntityClass("atlantismale01npc") - zelan:setCollisionAction(CollisionAction.STOP) - - -- NPC location & path - local nodes = { - {63, 66}, - {75, 66}, - } - zelan:setPathAndPosition(nodes, true) - - -- NPC dialog - zelan:addGreeting() - zelan:addGoodbye() - - -- add Zelan to the world - game:add(zelan) - - - -- quest - local quest = quests.simple:create("unicorn_horns_for_zelan", "Unicorn Horns for Zelan", "Zelan") - quest:setDescription("Zelan needs help gathering unicorn horns.") - - quest:setReply(quests.simple.ID_REQUEST, - "Hello! I'm in need of some unicorn horns to make some daggers." - .. " It is really dangerous in the woods surrounding Atlantis. If you are a brave sort" - .. " I could really use some help gathering unicorn horns. Will you help me?") - quest:setReply(quests.simple.ID_ACCEPT, - "Great! Be careful out there lots of large monsters, and those centaurs are really nasty") - quest:setReply(quests.simple.ID_REWARD, "Thanks a bunch!") - quest:setReply(quests.simple.ID_REJECT, "Thats ok, I will find someone else to help me.") - - quest:setItemToCollect("unicorn horn", 10) - quest:setXPReward(50000) - quest:setKarmaReward(5.0) - quest:addItemReward("soup", 3) - quest:addItemReward("money", 20000) - quest:setRegion(Region.ATLANTIS) - - quests:register(quest) -else - logger:error("Could not set zone: " .. zoneName) -end diff --git a/src/games/stendhal/server/core/rp/StendhalQuestSystem.java b/src/games/stendhal/server/core/rp/StendhalQuestSystem.java index ab6fdb8be5..cf1adfd696 100644 --- a/src/games/stendhal/server/core/rp/StendhalQuestSystem.java +++ b/src/games/stendhal/server/core/rp/StendhalQuestSystem.java @@ -186,6 +186,7 @@ public class StendhalQuestSystem { loadQuest(new TrapsForKlaas()); //loadQuest(new TutorialIsland()); loadQuest(new UltimateCollector()); + loadQuest(new UnicornHornsForZelan()); loadQuest(new VampireSword()); loadQuest(new WaterForXhiphin()); loadQuest(new WeaponsCollector()); diff --git a/src/games/stendhal/server/entity/player/UpdateConverter.java b/src/games/stendhal/server/entity/player/UpdateConverter.java index 739e211162..df3620475e 100644 --- a/src/games/stendhal/server/entity/player/UpdateConverter.java +++ b/src/games/stendhal/server/entity/player/UpdateConverter.java @@ -552,6 +552,15 @@ public abstract class UpdateConverter { } } + // 1.43: Unicorn Horns for Zelan converted to QuestManuscript + final String zelanQName = "unicorn_horns_for_zelan"; + if (player.hasQuest(zelanQName)) { + final String[] zelanSlots = player.getQuest(zelanQName).split(";"); + if (zelanSlots.length == 2) { + player.setQuest(zelanQName, zelanSlots[0] + ";;" + zelanSlots[1]); + } + } + // fix quest slots for kills quests. fixKillQuestsSlots(player); diff --git a/src/games/stendhal/server/maps/atlantis/cityoutside/ZelanNPC.java b/src/games/stendhal/server/maps/atlantis/cityoutside/ZelanNPC.java new file mode 100644 index 0000000000..79a012d466 --- /dev/null +++ b/src/games/stendhal/server/maps/atlantis/cityoutside/ZelanNPC.java @@ -0,0 +1,49 @@ +/*************************************************************************** + * (C) Copyright 2003-2022 - Stendhal * + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Affero General Public License as * + * published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + ***************************************************************************/ +package games.stendhal.server.maps.atlantis.cityoutside; + +import java.util.Arrays; +import java.util.Map; + +import games.stendhal.server.core.config.ZoneConfigurator; +import games.stendhal.server.core.engine.StendhalRPZone; +import games.stendhal.server.core.pathfinder.FixedPath; +import games.stendhal.server.core.pathfinder.Node; +import games.stendhal.server.entity.CollisionAction; +import games.stendhal.server.entity.npc.SpeakerNPC; + + +public class ZelanNPC implements ZoneConfigurator { + + @Override + public void configureZone(final StendhalRPZone zone, final Map attributes) { + zone.add(buildNPC()); + } + + private SpeakerNPC buildNPC() { + final SpeakerNPC zelan = new SpeakerNPC("Zelan"); + + // appearance & behavior + zelan.setEntityClass("atlantismale01npc"); + zelan.setCollisionAction(CollisionAction.STOP); + + // location & path + zelan.setPathAndPosition(new FixedPath(Arrays.asList( + new Node(63, 66), + new Node(75, 66)), true)); + + // dialog + zelan.addGreeting(); + zelan.addGoodbye(); + + return zelan; + } +} diff --git a/src/games/stendhal/server/maps/quests/UnicornHornsForZelan.java b/src/games/stendhal/server/maps/quests/UnicornHornsForZelan.java new file mode 100644 index 0000000000..f141a74873 --- /dev/null +++ b/src/games/stendhal/server/maps/quests/UnicornHornsForZelan.java @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright © 2003-2023 - Arianne * + *************************************************************************** + *************************************************************************** + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +package games.stendhal.server.maps.quests; + +import games.stendhal.server.entity.npc.action.EquipItemAction; +import games.stendhal.server.entity.npc.action.IncreaseKarmaAction; +import games.stendhal.server.entity.npc.action.IncreaseXPAction; +import games.stendhal.server.entity.npc.quest.BringItemTask; +import games.stendhal.server.entity.npc.quest.QuestBuilder; +import games.stendhal.server.entity.npc.quest.QuestManuscript; +import games.stendhal.server.maps.Region; + + +/** + * QUEST: Unicorn Horns for Zelan + * + * PARTICIPANTS: + *
    + *
  • Zelan
  • + *
+ * + * STEPS: + *
    + *
  • Zelan needs 10 unicorn horns.
  • + *
  • Bring the unicorn horns to him for a reward.
  • + *
+ * + * REWARD: + *
    + *
  • 50000 xp
  • + *
  • 5 karma
  • + *
  • 3 soup
  • + *
  • 20000 money
  • + *
+ * + * REPETITIONS: + *
    + *
  • never
  • + *
+ */ +public class UnicornHornsForZelan implements QuestManuscript { + + @Override + public QuestBuilder story() { + QuestBuilder quest = new QuestBuilder<>(new BringItemTask()); + + final String npcName = "Zelan"; + final int quantity = 10; + final String itemName = "unicorn horn"; + final String plItemName = itemName + "s"; + final int rewardSoup = 3; + final int rewardMoney = 20000; + + quest.info() + .name("Unicorn Horns for Zelan") + .internalName("unicorn_horns_for_zelan") + .description("Zelan needs help gathering unicorn horns.") + .region(Region.ATLANTIS) + .questGiverNpc(npcName) + .notRepeatable(); + + quest.history() + .whenNpcWasMet(npcName + " asked me to get " + quantity + + " " + plItemName + ".") + .whenQuestWasRejected("I do not want to help " + npcName + ".") + .whenQuestWasAccepted("I have not found what I am looking for yet.") + .whenTaskWasCompleted("I have what " + npcName + " asked for.") + .whenQuestWasCompleted("I found " + quantity + + " " + plItemName + " for " + npcName + "."); + + quest.offer() + .respondToRequest("Hello! I'm in need of some unicorn horns to" + + " make some daggers. It is really dangerous in the woods" + + " surrounding Atlantis. If you are a brave sort I could" + + " really use some help gathering unicorn horns. Will you" + + " help me?") + .respondToUnrepeatableRequest("Thanks, but I don't need any more" + + " help.") + .respondToAccept("Great! Be careful out there lots of large" + + " monsters, and those centaurs are really nasty.") + .respondToReject("Thats ok, I will find someone else to help me.") + .rejectionKarmaPenalty(0) + //~ .remind("I have already asked you to get " + quantity + //~ + " " + plItemName + ". Are you #done?"); + .remind("I asked you to bring me " + quantity + " " + plItemName + + "."); + + quest.task() + .requestItem(quantity, itemName); + + quest.complete() + .greet("Did you find the " + plItemName + "?") + .respondToReject("I asked you to bring me " + quantity + " " + + plItemName + ".") + .respondToAccept("Thanks a bunch! As a reward I will give you " + + rewardSoup + " soups and " + rewardMoney + " money.") + .rewardWith(new IncreaseXPAction(50000)) + .rewardWith(new IncreaseKarmaAction(5.0)) + .rewardWith(new EquipItemAction("soup", rewardSoup)) + .rewardWith(new EquipItemAction("money", rewardMoney)); + + return quest; + } +} diff --git a/tests/scripts/quest/UnicornHornsForZelanTest.java b/tests/games/stendhal/server/maps/quests/UnicornHornsForZelanTest.java similarity index 70% rename from tests/scripts/quest/UnicornHornsForZelanTest.java rename to tests/games/stendhal/server/maps/quests/UnicornHornsForZelanTest.java index c08a5e294d..2492416f2f 100644 --- a/tests/scripts/quest/UnicornHornsForZelanTest.java +++ b/tests/games/stendhal/server/maps/quests/UnicornHornsForZelanTest.java @@ -1,5 +1,5 @@ /*************************************************************************** - * (C) Copyright 2003-2022 - Arianne * + * Copyright © 2003-2023 - Arianne * *************************************************************************** *************************************************************************** * * @@ -9,7 +9,7 @@ * (at your option) any later version. * * * ***************************************************************************/ -package scripts.quest; +package games.stendhal.server.maps.quests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -21,28 +21,31 @@ import org.junit.Before; import org.junit.Test; import games.stendhal.server.core.engine.SingletonRepository; +import games.stendhal.server.core.engine.StendhalRPZone; import games.stendhal.server.entity.npc.ConversationStates; import games.stendhal.server.entity.npc.SpeakerNPC; import games.stendhal.server.entity.npc.fsm.Engine; -import utilities.LuaTestHelper; -import utilities.PlayerTestHelper; +import games.stendhal.server.entity.player.Player; +import games.stendhal.server.maps.atlantis.cityoutside.ZelanNPC; +import utilities.QuestHelper; -public class UnicornHornsForZelanTest extends LuaTestHelper { +public class UnicornHornsForZelanTest extends QuestHelper { private SpeakerNPC zelan; + private Player player; private final String slot = "unicorn_horns_for_zelan"; @Before public void setUp() { - setUpZone("-7_deniran_atlantis"); - load("data/script/region/atlantis/city/exterior/ZelanNPC.lua"); - loadCachedQuests(); - - addPlayerToWorld(); + player = createPlayer("tester"); + // load Zelan + new ZelanNPC().configureZone(new StendhalRPZone("testzone"), null); zelan = SingletonRepository.getNPCList().get("Zelan"); + // load quest + quests.loadQuest(new UnicornHornsForZelan()); } @Test @@ -57,6 +60,8 @@ public class UnicornHornsForZelanTest extends LuaTestHelper { } private void testQuest() { + assertTrue(quests.isLoaded(quests.getQuestFromSlot(slot))); + final Engine en = zelan.getEngine(); assertFalse(player.hasQuest(slot)); @@ -72,11 +77,13 @@ public class UnicornHornsForZelanTest extends LuaTestHelper { assertEquals(ConversationStates.ATTENDING, en.getCurrentState()); en.step(player, "quest"); - assertEquals(ConversationStates.QUEST_OFFERED, en.getCurrentState()); + assertEquals(ConversationStates.QUEST_OFFERED, + en.getCurrentState()); assertEquals( "Hello! I'm in need of some unicorn horns to make some daggers." - + " It is really dangerous in the woods surrounding Atlantis. If you are a brave sort" - + " I could really use some help gathering unicorn horns. Will you help me?", + + " It is really dangerous in the woods surrounding Atlantis. If" + + " you are a brave sort I could really use some help gathering" + + " unicorn horns. Will you help me?", getReply(zelan)); en.step(player, "no"); assertEquals(ConversationStates.ATTENDING, en.getCurrentState()); @@ -90,36 +97,52 @@ public class UnicornHornsForZelanTest extends LuaTestHelper { en.step(player, "yes"); assertEquals(ConversationStates.ATTENDING, en.getCurrentState()); assertEquals( - "Great! Be careful out there lots of large monsters, and those centaurs are really nasty", + "Great! Be careful out there lots of large monsters, and those" + + " centaurs are really nasty.", getReply(zelan)); assertEquals("start", player.getQuest(slot, 0)); assertTrue(player.getKarma() == playerKarma); en.step(player, "bye"); assertEquals(ConversationStates.IDLE, en.getCurrentState()); - PlayerTestHelper.equipWithStackableItem(player, "unicorn horn", 9); + equipWithStackableItem(player, "unicorn horn", 9); en.step(player, "hi"); assertEquals(ConversationStates.ATTENDING, en.getCurrentState()); en.step(player, "done"); - assertEquals("I asked you to bring me 10 unicorn horns.", getReply(zelan)); + assertEquals( + "I asked you to bring me 10 unicorn horns.", + getReply(zelan)); en.step(player, "bye"); - PlayerTestHelper.equipWithStackableItem(player, "unicorn horn", 1); + equipWithStackableItem(player, "unicorn horn", 1); en.step(player, "hi"); - en.step(player, "done"); + assertEquals(ConversationStates.QUEST_ITEM_BROUGHT, + en.getCurrentState()); + assertEquals("Did you find the unicorn horns?", getReply(zelan)); + en.step(player, "yes"); assertEquals( - "Thanks a bunch! As a reward I will give you 3 soups and 20000 money.", + "Thanks a bunch! As a reward I will give you 3 soups and 20000" + + " money.", getReply(zelan)); en.step(player, "bye"); assertEquals(ConversationStates.IDLE, en.getCurrentState()); assertEquals("done", player.getQuest(slot, 0)); + assertEquals("1", player.getQuest(slot, 2)); assertTrue(player.getKarma() == playerKarma + 5); assertEquals(playerXP + 50000, player.getXP()); assertEquals(0, player.getNumberOfEquipped("unicorn horn")); assertEquals(3, player.getNumberOfEquipped("soup")); assertEquals(20000, player.getNumberOfEquipped("money")); + + en.step(player, "hi"); + en.step(player, "quest"); + assertEquals(ConversationStates.ATTENDING, en.getCurrentState()); + assertEquals( + "Thanks, but I don't need any more help.", + getReply(zelan)); + en.step(player, "bye"); } }