stendhal/tests/scripts/quest/LostEngagementRingTest.java
2023-03-04 09:25:35 -08:00

662 lines
22 KiB
Java

/***************************************************************************
* (C) Copyright 2003-2022 - 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 scripts.quest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static utilities.SpeakerNPCTestHelper.getReply;
import java.util.Arrays;
import org.junit.After;
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.core.events.TurnListener;
import games.stendhal.server.core.rule.EntityManager;
import games.stendhal.server.entity.Entity;
import games.stendhal.server.entity.item.Item;
import games.stendhal.server.entity.item.MetalDetector;
import games.stendhal.server.entity.npc.ConversationStates;
import games.stendhal.server.entity.npc.NPCList;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.fsm.Engine;
import utilities.LuaTestHelper;
public class LostEngagementRingTest extends LuaTestHelper {
private static final EntityManager entityMan = SingletonRepository.getEntityManager();
private SpeakerNPC ari;
private SpeakerNPC emma;
private SpeakerNPC sawyer;
private StendhalRPZone fado;
private StendhalRPZone athor;
private StendhalRPZone pawnShop;
private final String slot = "lost_engagement_ring";
@Before
public void setUp() {
setUpZone("0_fado_city");
world.addRPZone("dummy", new StendhalRPZone("0_athor_island"));
world.addRPZone("dummy", new StendhalRPZone("int_deniran_pawn_shop"));
load("data/script/region/fado/city/EngagedCouple.lua");
load("data/script/quest/LostEngagementRing.lua");
load("data/script/region/deniran/city/interior/pawn_shop/BrokerNPC.lua");
load("data/script/region/deniran/city/interior/pawn_shop/ItemsOnShelf.lua");
}
@After
@Override
public void tearDown() {
super.tearDown();
pawnShop.remove(sawyer);
// fado is handled in super method
world.removeZone(athor);
world.removeZone(pawnShop);
}
@Test
public void init() {
initZones();
initEntities();
testWithoutQuestLoaded();
testWithQuestLoaded();
}
private void initZones() {
fado = world.getZone("0_fado_city");
athor = world.getZone("0_athor_island");
pawnShop = world.getZone("int_deniran_pawn_shop");
assertNotNull(fado);
assertNotNull(athor);
assertNotNull(pawnShop);
}
private void initEntities() {
final NPCList npcs = SingletonRepository.getNPCList();
ari = npcs.get("Ari");
emma = npcs.get("Emma");
sawyer = npcs.get("Sawyer");
assertNotNull(ari);
assertEquals("0_fado_city", ari.getZone().getName());
assertEquals(74, ari.getX());
assertEquals(56, ari.getY());
assertNotNull(emma);
assertEquals("0_fado_city", emma.getZone().getName());
assertEquals(75, emma.getX());
assertEquals(56, emma.getY());
assertNotNull(sawyer);
assertEquals("int_deniran_pawn_shop", sawyer.getZone().getName());
assertEquals(18, sawyer.getX());
assertEquals(5, sawyer.getY());
addPlayerToWorld();
assertNotNull(player);
assertEquals("0_fado_city", player.getZone().getName());
assertFalse(player.hasQuest(slot));
}
private void leaveCurrentZone() {
final StendhalRPZone currentZone = player.getZone();
if (currentZone != null) {
currentZone.remove(player);
}
// reset player's position
player.setPosition(0, 0);
}
private void gotoFado() {
leaveCurrentZone();
fado.add(player);
assertEquals("0_fado_city", player.getZone().getName());
}
private void gotoPawnShop() {
leaveCurrentZone();
pawnShop.add(player);
assertEquals("int_deniran_pawn_shop", player.getZone().getName());
}
private void gotoAthor() {
leaveCurrentZone();
athor.add(player);
assertEquals("0_athor_island", player.getZone().getName());
}
private void testWithoutQuestLoaded() {
Engine en;
for (final SpeakerNPC npc: Arrays.asList(ari, emma)) {
assertEquals("love", npc.getIdea());
en = npc.getEngine();
assertEquals(ConversationStates.IDLE, en.getCurrentState());
en.step(player, "hi");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
}
en = sawyer.getEngine();
en.step(player, "hi");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("Welcome to the Deniran Pawn Shop.", getReply(sawyer));
en.step(player, "offer");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals(
"Please check the blackboard for a list of items that I buy.",
getReply(sawyer));
en.step(player, "bye");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals("Bye.", getReply(sawyer));
}
private void testWithQuestLoaded() {
loadCachedQuests();
// make sure Sawyer & metal detector are working
getMetalDetector();
final Engine en = ari.getEngine();
assertEquals(0, player.getLevel());
assertFalse(player.hasFeature("keyring"));
//assertFalse(player.hasVisitedZone("0_athor_island"));
assertFalse(player.hasVisitedZone(athor));
assertEquals(ConversationStates.IDLE, en.getCurrentState());
en.step(player, "hi");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("Hi there!", getReply(ari));
en.step(player, "quest");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals(
"I don't think you have the experience to help me. Come back when"
+ " you are stronger.",
getReply(ari));
player.setLevel(50);
assertEquals(50, player.getLevel());
en.step(player, "quest");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals(
"I don't think you have the experience to help me. Maybe if you knew"
+ " more about keyrings.",
getReply(ari));
player.setFeature("keyring", "2 4");
assertTrue(player.hasFeature("keyring"));
assertEquals("2 4", player.getFeature("keyring"));
en.step(player, "quest");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals(
"I don't think you have the experience to help me. Maybe if you were"
+ " more familiar with Athor island.",
getReply(ari));
en.step(player, "bye");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals("Bye.", getReply(ari));
gotoAthor();
gotoFado();
assertTrue(player.hasVisitedZone("0_athor_island"));
int karma = (int) player.getKarma();
en.step(player, "hi");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals(
"Hey! You look like an experienced adventurer. Perhaps you could help me with a #task.",
getReply(ari));
en.step(player, "quest");
assertEquals(ConversationStates.QUEST_OFFERED, en.getCurrentState());
assertEquals(
"I have lost my engagement ring, and I am too embarrassed to tell "
+ emma.getName() + ". Would you help me?",
getReply(ari));
en.step(player, "no");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals(
"I don't want to leave " + emma.getName()
+ "'s side. I hope I can find someone to help me.",
getReply(ari));
assertEquals(karma - 15, (int) player.getKarma());
karma = (int) player.getKarma();
en.step(player, "hi");
en.step(player, "quest");
en.step(player, "yes");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals(
"Thank you so much! I lost my ring while visiting Athor Island."
+ " Please let me know when you find it. And don't say anything to "
+ emma.getName() + ".",
getReply(ari));
assertTrue(player.hasQuest(slot));
//~ assertEquals(karma + 15, (int) player.getKarma());
karma = (int) player.getKarma();
en.step(player, "hi");
assertEquals(ConversationStates.QUESTION_1, en.getCurrentState());
assertEquals(
"Did you find my ring? If there is something I can do to #help, please let me know.",
getReply(ari));
// player does not have ring
en.step(player, "no");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals("Please keep looking.", getReply(ari));
en.step(player, "hi");
en.step(player, "yes");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals("You don't have my ring. Please, keep looking.", getReply(ari));
en.step(player, "hi");
en.step(player, "help");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals(
"I may have dropped it while walking along the beach. If that is the case,"
+ " you may need something to dig in the sand or something that can"
+ " detect metal. Maybe a local pawn shop has a tool you could use.",
getReply(ari));
// try to give Ari a fake ring
final Item fakeRing = entityMan.getItem("engagement ring");
player.equip("bag", fakeRing);
assertEquals(1, player.getAllEquipped("engagement ring").size());
en.step(player, "hi");
en.step(player, "yes");
assertEquals("You don't have my ring. Please, keep looking.", getReply(ari));
assertEquals(ConversationStates.IDLE, en.getCurrentState());
player.drop("engagement ring");
assertFalse(player.isEquipped("engagement ring"));
// ATTENDING state does not occur in game while quest is active
en.step(player, "hi");
en.setCurrentState(ConversationStates.ATTENDING);
en.step(player, "quest");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("You are already helping me find my engagement ring.", getReply(ari));
en.step(player, "bye");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
final String[] coords = player.getQuest(slot).split(";");
// get ring
searchForRing();
// have ring but tell Ari is lost
en.step(player, "hi");
en.step(player, "lost");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals(
"You lost my lost engagement ring? That's kind of ironic."
+ " I bet you're teasing me.",
getReply(ari));
assertEquals("found_ring", player.getQuest(slot, 0));
// truly lost ring
player.dropWithInfostring("engagement ring", "Ari's ring");
assertFalse(player.isEquipped("engagement ring"));
en.step(player, "hi");
en.step(player, "lost");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals(
"You lost my lost engagement ring? That's kind of ironic."
+ " I bet you dropped it near where you found it."
+ " Check there again.",
getReply(ari));
// quest slot should have been reset to same position
assertEquals(coords[0], player.getQuest(slot, 0));
assertEquals(coords[1], player.getQuest(slot, 1));
// get ring again
searchForRing();
// finish quest
en.step(player, "hi");
en.step(player, "yes");
//en.step(player, "done");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals(
"Thank you so much! As a reward, I will give you this keyring. It is larger than the one you have.",
getReply(ari));
assertEquals("done", player.getQuest(slot, 0));
assertFalse(player.isEquipped("engagement ring"));
assertEquals(karma + 50, (int) player.getKarma());
assertEquals("3 4", player.getFeature("keyring"));
}
private void searchForRing() {
gotoAthor();
assertNotEquals("found_ring", player.getQuest(slot, 0));
final MetalDetector detector = (MetalDetector) player.getFirstEquipped("metal detector");
assertNotNull(detector);
assertEquals(0, player.getX());
assertEquals(0, player.getY());
// did not find ring
detector.onUsed(player);
assertFalse(player.isEquipped("engagement ring"));
assertNotEquals("found_ring", player.getQuest(slot, 0));
// go to coordinates where ring can be found
player.setPosition(
Integer.parseInt(player.getQuest(slot, 0)),
Integer.parseInt(player.getQuest(slot, 1)));
// found ring
detector.onUsed(player);
assertTrue(player.isEquipped("engagement ring"));
assertEquals("found_ring", player.getQuest(slot, 0));
final Item ring = player.getFirstEquipped("engagement ring");
assertEquals(player.getName(), ring.getBoundTo());
assertEquals("Ari's ring", ring.getInfoString());
// put player back in Fado City
gotoFado();
}
private void checkMetalDetectorNotOnShelf() {
assertNull(pawnShop.getEntityAt(19, 5));
}
private void checkMetalDetectorOnShelf() {
final Entity itemOnShelf = pawnShop.getEntityAt(19, 5);
assertNotNull(itemOnShelf);
assertTrue(itemOnShelf instanceof MetalDetector);
assertEquals(sawyer.getName(), ((MetalDetector) itemOnShelf).getBoundTo());
}
private void removeMetalDetectorFromShelf() {
final Entity itemOnShelf = pawnShop.getEntityAt(19, 5);
if (itemOnShelf != null) {
pawnShop.remove(itemOnShelf);
}
checkMetalDetectorNotOnShelf();
}
private void getMetalDetector() {
gotoPawnShop();
final Engine en = sawyer.getEngine();
assertEquals(ConversationStates.IDLE, en.getCurrentState());
final String pawnSlot = "sawyer_metal_detector";
assertFalse(player.hasQuest(pawnSlot));
assertFalse(player.isEquipped("metal detector"));
assertFalse(player.isEquipped("mithril legs"));
en.step(player, "hi");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("Welcome to the Deniran Pawn Shop.", getReply(sawyer));
en.step(player, "help");
assertEquals(
"If you want to pawn something, check my blackboard for a list of what I buy.",
getReply(sawyer));
en.step(player, "offer");
assertEquals(
"Please check the blackboard for a list of items that I buy."
+ " I also have some items that I don't mind #loaning out.",
getReply(sawyer));
en.step(player, "return");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("Return what? I haven't loaned anything to you.", getReply(sawyer));
en.step(player, "borrow");
assertEquals(ConversationStates.QUESTION_1, en.getCurrentState());
assertEquals(
"So, you want to borrow my metal detector? Well, I don't lend things out"
+ " without some form of collateral. What would you like to leave"
+ " behind?",
getReply(sawyer));
en.step(player, "no");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("Okay then. What else can I help you with?", getReply(sawyer));
en.step(player, "borrow");
en.step(player, "cheese");
assertEquals(ConversationStates.QUESTION_1, en.getCurrentState());
assertEquals("Hmmm, I'm not interested in that. What else you got?", getReply(sawyer));
en.step(player, "mithril legs");
assertEquals(ConversationStates.QUESTION_1, en.getCurrentState());
assertEquals(
"You're not even carrying one of those. Come on, what do you have?",
getReply(sawyer));
// test borrowing when detector is on shelf
borrowFromShelf(en, pawnSlot);
// test borrowing when detector not on shelf
borrowExtra(en, pawnSlot);
// put player back in Fado City
gotoFado();
}
/**
* Tests borrowing metal detector from Sawyer when item
* is still on shelf.
*/
private void borrowFromShelf(final Engine en, final String pawnSlot) {
assertFalse(player.hasQuest(pawnSlot));
assertFalse(player.isEquipped("metal detector"));
// check that metal detector is on shelf
checkMetalDetectorOnShelf();
final String legsInfo = "foo bar";
final Item legs = entityMan.getItem("mithril legs");
legs.setBoundTo(player.getName());
legs.setInfoString(legsInfo);
player.equip("bag", legs);
assertEquals(1, player.getAllEquipped("mithril legs").size());
en.step(player, "mithril legs");
// player walked away
assertNull(sawyer.getAttending());
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertEquals(
"Where did you go? Oh well, guess I'll just put this back on the shelf.",
getReply(sawyer));
en.step(player, "hi");
sawyer.setAttending(player);
assertEquals(player, sawyer.getAttending());
en.step(player, "borrow");
en.step(player, "mithril legs");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals(
"Okay, here you go. My metal detector for your mithril legs"
+ ". Be careful with it. If it gets lost, you won't be able to"
+ " #return it and I will keep your mithril legs. Anything"
+ " else I can help you with?",
getReply(sawyer));
en.step(player, "bye");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
sawyer.setAttending(null);
assertNull(sawyer.getAttending());
assertFalse(player.isEquipped("mithril legs"));
assertEquals(1, player.getAllEquipped("metal detector").size());
// make sure bound & infostring data are stored in quest slot
assertEquals("mithril legs", player.getQuest(pawnSlot, 0));
assertEquals(player.getName(), player.getQuest(pawnSlot, 1));
assertEquals(legsInfo, player.getQuest(pawnSlot, 2));
// check that detector was removed from shelf
checkMetalDetectorNotOnShelf();
final MetalDetector detector = (MetalDetector) player.getFirstEquipped("metal detector");
assertNotNull(detector);
assertEquals(player.getName(), detector.getBoundTo());
// make sure bound & infostring data are stored in item infostring
final String[] dinfo = detector.getInfoString().split(";");
assertEquals(sawyer.getName(), dinfo[0]);
assertEquals("mithril legs", dinfo[1]);
assertEquals(player.getName(), dinfo[2]);
assertEquals(legsInfo, dinfo[3]);
// returning metal detector
en.step(player, "hi");
en.step(player, "return");
assertEquals(ConversationStates.QUESTION_1, en.getCurrentState());
assertEquals("You want to return my metal detector?", getReply(sawyer));
en.step(player, "no");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("Okay. What else can I help you with?", getReply(sawyer));
// try to return metal detector when not equipped
player.drop(detector);
assertFalse(player.isEquipped("metal detector"));
en.step(player, "return");
en.step(player, "yes");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("You aren't even carryng a metal detector.", getReply(sawyer));
// try to return a metal detector that doesn't belong to Sawyer
final Item fakeDetector = entityMan.getItem("metal detector");
player.equip("bag", fakeDetector);
assertEquals(1, player.getAllEquipped("metal detector").size());
en.step(player, "return");
en.step(player, "yes");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals("This isn't mine. Take it back. I want MY metal detector.", getReply(sawyer));
player.drop(fakeDetector);
assertFalse(player.isEquipped("metal detector"));
// return the real metal detector
player.equip("bag", detector);
en.step(player, "return");
en.step(player, "yes");
assertEquals(ConversationStates.ATTENDING, en.getCurrentState());
assertEquals(
"Okay. Here is your mithril legs. Good as new. Is there"
+ " anything else I can help you with?",
getReply(sawyer));
en.step(player, "bye");
assertEquals(ConversationStates.IDLE, en.getCurrentState());
assertFalse(player.isEquipped("metal detector"));
assertFalse(player.hasQuest(pawnSlot));
// check that metal detector was returned to shelf
checkMetalDetectorOnShelf();
// make sure returned item retains bound & infostring information
final Item returnedLegs = player.getFirstEquipped("mithril legs");
assertNotNull(returnedLegs);
assertEquals(player.getName(), returnedLegs.getBoundTo());
assertEquals(legsInfo, returnedLegs.getInfoString());
}
/**
* Tests borrowing metal detector from Sawyer when item
* has been previously borrowed by another player.
*/
private void borrowExtra(final Engine en, final String pawnSlot) {
assertFalse(player.hasQuest(pawnSlot));
assertFalse(player.isEquipped("metal detector"));
// make sure metal detector was removed from shelf
removeMetalDetectorFromShelf();
player.equip("head", entityMan.getItem("black helmet"));
assertEquals(1, player.getAllEquipped("black helmet").size());
en.step(player, "hi");
en.step(player, "borrow");
// clear replies cache
getReply(sawyer);
// FIXME: how do we simulate waiting for Sawyer to finish thinking?
// equip with metal detector so rest of test doesn't fail
player.equip("bag", entityMan.getItem("metal detector"));
/*
en.step(player, "black helmet");
assertEquals(ConversationStates.BUSY, en.getCurrentState());
List<String> replies = getOrderedReplies(sawyer);
assertEquals(2, replies.size());
assertEquals("Hmmmm. I guess I forgot that I already loaned it out...", replies.get(0));
assertEquals("!me is thinking.", replies.get(1));
SingletonRepository.getTurnNotifier().notifyInTurns(0, new TurnListener() {
public void onTurnReached(final int currentTurn) {
en.step(player, "black helmet");
assertEquals(ConversationStates.BUSY, en.getCurrentState());
final List<String> replies = getOrderedReplies(sawyer);
assertEquals(2, replies.size());
assertEquals("Hmmmm. I guess I forgot that I already loaned it out...", replies.get(0));
assertEquals("!me is thinking.", replies.get(1));
}
});
final long startTime = System.currentTimeMillis();
int reports = 0;
int elapsed = 0;
System.out.println("Sawyer is thinking ...");
while (elapsed < 16) {
// wait for Sawyer to finish thinking
if (elapsed >= 5 && reports == 0) {
System.out.println("Sawyer is still thinking ...");
reports++;
} else if (elapsed >= 10 && reports == 1) {
System.out.println("Sawyer is almost done thinking ...");
reports++;
}
elapsed = (int) ((System.currentTimeMillis() - startTime) / 1000);
}
final List<String> replies = getOrderedReplies(sawyer);
assertEquals(2, replies.size());
assertEquals("Oh! That's right, I keep a spare just in case.", replies.get(0));
assertEquals(
"Okay, here you go. My metal detector for your black helmet."
+ " Be careful with it. If it gets lost, you won't be able to"
+ " #return it and I will keep your black helmet. Anything"
+ " else I can help you with?",
replies.get(1));
*/
// TODO: player dropped item while Sawyer was thinking
}
}