Skip to content

Commit

Permalink
Change Find Rat Children quest state string to format more...
Browse files Browse the repository at this point in the history
...suited for completions tracking
  • Loading branch information
AntumDeluge committed Jul 9, 2024
1 parent 440ec64 commit 6d7157b
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 77 deletions.
39 changes: 15 additions & 24 deletions src/games/stendhal/server/entity/npc/RatKidsNPCBase.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
* (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
Expand All @@ -12,12 +12,13 @@
***************************************************************************/
package games.stendhal.server.entity.npc;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import games.stendhal.common.parser.Sentence;
import games.stendhal.server.entity.npc.condition.GreetingMatchesNameCondition;
import games.stendhal.server.entity.player.Player;
import games.stendhal.server.maps.quests.FindRatChildren;

// import org.apache.log4j.Logger;

Expand Down Expand Up @@ -58,30 +59,20 @@ protected void createDialog() {
private static class RatKidGreetingAction implements ChatAction {
@Override
public void fire(final Player player, final Sentence sentence, final EventRaiser npc) {
if (!player.hasQuest(QUEST_SLOT) || player.isQuestInState(QUEST_SLOT, "rejected")) {
if (!player.hasQuest(QUEST_SLOT) || player.isQuestInState(QUEST_SLOT, 0, "rejected")) {
npc.say("Mother says I mustn't talk to strangers.");
} else {
final String npcQuestText = player.getQuest(QUEST_SLOT);
final String[] npcDoneText = npcQuestText.split(":");

final String lookStr;
final String saidStr;
if (npcDoneText.length > 1) {
lookStr = npcDoneText[0].toLowerCase();
saidStr = npcDoneText[1].toLowerCase();

final List<String> list = Arrays.asList(lookStr.split(";"));
String npcName = npc.getName().toLowerCase();
if (list.contains(npcName) || player.isQuestCompleted(QUEST_SLOT)) {
npc.say("Oh hello again.");
} else if ( npcDoneText.length > 1) {
player.setQuest(QUEST_SLOT, lookStr + ";" + npcName
+ ":" + saidStr);//
npc.say("Hello my name is " + npc.getName() + ". Please tell mother that I am ok.");
player.addXP(500);
} else {
npc.say("Mother says I mustn't talk to strangers.");
}
final List<String> found = FindRatChildren.getFoundNames(player);
String npcName = npc.getName().toLowerCase(Locale.ENGLISH);
final boolean questCompleted = player.isQuestCompleted(QUEST_SLOT);
if (questCompleted || found.contains(npcName)) {
npc.say("Oh hello again.");
} else if (!questCompleted) {
FindRatChildren.addFoundName(player, npcName);
npc.say("Hello my name is " + npc.getName() + ". Please tell mother that I am ok.");
player.addXP(500);
} else {
npc.say("Mother says I mustn't talk to strangers.");
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/games/stendhal/server/entity/player/UpdateConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import games.stendhal.server.entity.slot.EntitySlot;
import games.stendhal.server.entity.slot.KeyedSlot;
import games.stendhal.server.entity.slot.PlayerSlot;
import games.stendhal.server.maps.quests.FindRatChildren;
import games.stendhal.server.util.TimeUtil;
import marauroa.common.Pair;
import marauroa.common.game.RPObject;
Expand Down Expand Up @@ -674,7 +675,7 @@ public static void updateQuests(final Player player) {
- (TimeUtil.MINUTES_IN_HALF_YEAR / 2 * TimeUtil.MILLISECONDS_IN_MINUTE)));
}

// 1.47: support completions tracking
// 1.48: support completions tracking in Chocolate for Elisabeth & Ice Cream for Annie
for (String slot: Arrays.asList("chocolate_for_elisabeth", "icecream_for_annie")) {
if (!player.hasQuest(slot)) {
continue;
Expand All @@ -683,6 +684,9 @@ public static void updateQuests(final Player player) {
player.setQuest(slot, 2, "1");
}
}

// update Find Rat Children
FindRatChildren.checkPlayerUpdate(player);
}


Expand Down
203 changes: 161 additions & 42 deletions src/games/stendhal/server/maps/quests/FindRatChildren.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;
import java.util.Locale;

import games.stendhal.common.grammar.Grammar;
import games.stendhal.common.parser.Sentence;
Expand All @@ -26,6 +25,7 @@
import games.stendhal.server.entity.npc.ConversationStates;
import games.stendhal.server.entity.npc.EventRaiser;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.action.MultipleActions;
import games.stendhal.server.entity.npc.action.SetQuestAction;
import games.stendhal.server.entity.npc.action.SetQuestAndModifyKarmaAction;
import games.stendhal.server.entity.npc.condition.AndCondition;
Expand Down Expand Up @@ -71,8 +71,6 @@
*/
public class FindRatChildren extends AbstractQuest {

private static Logger logger = Logger.getLogger(FindRatChildren.class);

private static final String QUEST_SLOT = "find_rat_kids";

// twenty four hours
Expand All @@ -88,36 +86,172 @@ public String getSlotName() {
return QUEST_SLOT;
}

private List<String> missingNames(final Player player) {
/**
* Retrieves names of children player still needs to find and report.
*
* @param player
* Player doing quest.
* @return
* Missing children's names.
*/
private static List<String> missingNames(final Player player) {
if (!player.hasQuest(QUEST_SLOT)) {
return NEEDED_KIDS;
}
/*
* the format of the list quest slot is
* "looking;name;name;...:said;name;name;..."
* "found=name,name,...;said=name,name,..."
*/
// put the children name to lower case so we can match it, however the player wrote the name
final String npcDoneText = player.getQuest(QUEST_SLOT).toLowerCase();
final String[] doneAndFound = npcDoneText.split(":");
final String[] tmp = player.getQuest(QUEST_SLOT, 1).toLowerCase(Locale.ENGLISH).split("=");
if (tmp.length < 2) {
return NEEDED_KIDS;
}
final List<String> said = Arrays.asList(tmp[1].split(","));
final List<String> result = new LinkedList<String>();
if (doneAndFound.length > 1) {
final String[] done = doneAndFound[1].split(";");
final List<String> doneList = Arrays.asList(done);
for (final String name : NEEDED_KIDS) {
if (!doneList.contains(name)) {
result.add(name);
}
for (final String name: NEEDED_KIDS) {
if (!said.contains(name)) {
result.add(name);
}
}
return result;
}

/**
* Checks if quest state is active.
*
* @param player
* Player doing quest.
* @return
* {@code true} if player has quest and is in active state.
*/
private static boolean lookingForKids(final Player player) {
return new QuestActiveCondition(QUEST_SLOT).fire(player, null, null);
}

/**
* Adds a name to player's quest state when NPC is found.
*
* @param player
* Player doing quest.
* @param name
* Name of found child.
*/
public static void addFoundName(final Player player, final String name) {
if (!lookingForKids(player)) {
return;
}
String found = player.getQuest(QUEST_SLOT, 0);
if (found.length() > "found=".length()) {
found += ",";
}
found += name;
player.setQuest(QUEST_SLOT, 0, found);
}

/**
* Adds a name to player's quest state when reported to Agnus.
*
* @param player
* Player doing quest.
* @param name
* Name of found child.
*/
private static void addSaidName(final Player player, final String name) {
if (!lookingForKids(player)) {
return;
}
String said = player.getQuest(QUEST_SLOT, 1);
if (said.length() > "said=".length()) {
said += ",";
}
said += name;
player.setQuest(QUEST_SLOT, 1, said);
}

/**
* Retrieves names of rat children player has talked to.
*
* @param player
* Player doing quest.
* @return
* List of names of children player has talked to.
*/
public static List<String> getFoundNames(final Player player) {
final List<String> names = new ArrayList<>();
if (!lookingForKids(player)) {
return names;
}
final String[] tmp = player.getQuest(QUEST_SLOT, 0).toLowerCase(Locale.ENGLISH).split("=");
if (tmp.length < 2) {
return names;
}
names.addAll(Arrays.asList(tmp[1].split(",")));
return names;
}

/**
* Retrieves names of rat children player has reported to Agnus.
*
* @param player
* Player doing quest.
* @return
* List of names of children player has reported.
*/
public static List<String> getSaidNames(final Player player) {
final List<String> names = new ArrayList<>();
if (!lookingForKids(player)) {
return names;
}
final String[] tmp = player.getQuest(QUEST_SLOT, 1).toLowerCase(Locale.ENGLISH).split("=");
if (tmp.length < 2) {
return names;
}
names.addAll(Arrays.asList(tmp[1].split(",")));
return names;
}

/**
* Updates formatting of player's quest state string.
*
* @param player
* Player being updated.
*/
public static void checkPlayerUpdate(final Player player) {
final String state = player.getQuest(QUEST_SLOT);
// 1.48: support completions tracking in Find Rat Children
if (!player.hasQuest(QUEST_SLOT) || !state.startsWith("looking")) {
return;
}
final List<String> found = new ArrayList<>();
final List<String> said = new ArrayList<>();
final String[] tmp = state.split(":");
if (tmp.length > 0) {
for (final String name: tmp[0].split(";")) {
if ("looking".equals(name)) {
continue;
}
found.add(name);
}
}
if (tmp.length > 1) {
for (final String name: tmp[1].split(";")) {
if ("said".equals(name)) {
continue;
}
said.add(name);
}
}
player.setQuest(QUEST_SLOT, "found=" + String.join(",", found) + ";said="
+ String.join(",", said));
}

private void askingStep() {
final SpeakerNPC npc = npcs.get("Agnus");

npc.add(ConversationStates.ATTENDING,
ConversationPhrases.QUEST_MESSAGES,
new OrCondition(new QuestNotStartedCondition(QUEST_SLOT), new QuestInStateCondition(QUEST_SLOT, "rejected")),
new OrCondition(new QuestNotStartedCondition(QUEST_SLOT), new QuestInStateCondition(QUEST_SLOT, 0, "rejected")),
ConversationStates.QUEST_OFFERED,
"I feel so worried. If I only knew my #children were safe I would feel better.",
null);
Expand Down Expand Up @@ -151,15 +285,17 @@ private void askingStep() {
null,
ConversationStates.ATTENDING,
"That's so nice of you. Good luck searching for them.",
new SetQuestAction(QUEST_SLOT, "looking:said"));
new MultipleActions(
new SetQuestAction(QUEST_SLOT, 0, "found="),
new SetQuestAction(QUEST_SLOT, 1, "said=")));

npc.add(
ConversationStates.QUEST_OFFERED,
ConversationPhrases.NO_MESSAGES,
null,
ConversationStates.ATTENDING,
"Oh. Never mind. I'm sure someone else would be glad to help me.",
new SetQuestAndModifyKarmaAction(QUEST_SLOT, "rejected", -15.0));
new SetQuestAndModifyKarmaAction(QUEST_SLOT, 0, "rejected", -15.0));

npc.add(
ConversationStates.QUEST_OFFERED,
Expand Down Expand Up @@ -197,35 +333,17 @@ private void retrievingStep() {
new ChatAction() {
@Override
public void fire(final Player player, final Sentence sentence, final EventRaiser npc) {
final String npcQuestText = player.getQuest(QUEST_SLOT).toLowerCase();
final String[] npcDoneText = npcQuestText.split(":");
final String lookingStr;
final String saidStr;
if (npcDoneText.length > 1) {
lookingStr = npcDoneText[0];
saidStr = npcDoneText[1];
} else {
// compatibility with broken quests - should never happen
logger.warn("Player " + player.getTitle() + " found with find_rat_kids quest slot in state " + player.getQuest(QUEST_SLOT) + " - now setting this to done.");
player.setQuest(QUEST_SLOT, "done");
npc.say("Sorry, it looks like you have already found them after all. I got confused.");
player.notifyWorldAboutChanges();
npc.setCurrentState(ConversationStates.ATTENDING);
return;
}

final List<String> looking = Arrays.asList(lookingStr.split(";"));
final List<String> said = Arrays.asList(saidStr.split(";"));
final List<String> found = getFoundNames(player);
final List<String> said = getSaidNames(player);
String reply = "";
List<String> missing = missingNames(player);
final boolean isMissing = missing.contains(name);

if (isMissing && looking.contains(name) && !said.contains(name)) {
if (isMissing && found.contains(name) && !said.contains(name)) {
// we haven't said the name yet so we add it to the list
player.setQuest(QUEST_SLOT, lookingStr
+ ":" + saidStr + ";" + name);
addSaidName(player, name);
reply = "Thank you.";
} else if (!looking.contains(name)) {
} else if (!found.contains(name)) {
// we have said it was a valid name but haven't seen them
reply = "I don't think you actually checked if they were ok.";
} else if (!isMissing && said.contains(name)) {
Expand All @@ -246,7 +364,8 @@ public void fire(final Player player, final Sentence sentence, final EventRaiser
player.addKarma(15);
reply += " Now that I know my kids are safe, I can set my mind at rest.";
npc.say(reply);
player.setQuest(QUEST_SLOT, "done;" + System.currentTimeMillis());
player.setQuest(QUEST_SLOT, 0, "done");
player.setQuest(QUEST_SLOT, 1, String.valueOf(System.currentTimeMillis()));
player.notifyWorldAboutChanges();
npc.setCurrentState(ConversationStates.ATTENDING);
}
Expand Down
Loading

0 comments on commit 6d7157b

Please sign in to comment.