Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quest Completions Tracking #704

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions quests_without_completions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

The following quests do not support tracking number of completions:
- adventure_island (Adventure Island)
- dragon_lair (Dragon Lair)
- easter_gifts_[year] (Easter Gifts for Children)
- find_rat_kids (Find Rat Children)
- fishsoup_for_hughie (Fish Soup for Hughie)
- fishsoup_maker (Fish Soup)
- fix_emerald_ring (The Ring Maker)
- fruits_coralia (Fruits for Coralia)
- goodies_rudolph (Goodies for Rudolph)
- guess_kills (The Guessing Game)
- kill_all_spiders (Kill Spiders)
- kill_dhohr_nuggetcutter (Kill Dhohr Nuggetcutter)
- koboldish_torcibud (Koboldish Torcibud)
- meet_bunny_[year] (Meet Easter Bunny)
- meet_santa_[seasonyear] (Meet Santa)
- paper_chase_20[year] (Paper Chase) ???
- reverse_arrow (Reverse Arrow)
- snowballs (Snowballs for Mr. Yeti)
- soup_maker (Soup)
- the_pied_piper (The Pied Piper)
- zoo_food (Zoo Food)
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
14 changes: 0 additions & 14 deletions src/games/stendhal/server/entity/player/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -3024,20 +3024,6 @@ protected void handleLeaveZone(int nx, final int ny) {
}
}

/**
* Gets the number of repetitions in a substate of quest slot
*
* @param questname
* The quest's name
* @param index
* the index of the sub state to get (separated by ";")
* @return the integer value in the index of the quest slot, used to
* represent a number of repetitions
*/
public int getNumberOfRepetitions(final String questname, final int index) {
return quests.getNumberOfRepetitions(questname, index);
}

/**
* gets the timestmap this client sent the last action
*
Expand Down
21 changes: 1 addition & 20 deletions src/games/stendhal/server/entity/player/PlayerQuests.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***************************************************************************
* (C) Copyright 2003-2020 - Stendhal *
* (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
Expand Down Expand Up @@ -277,23 +277,4 @@ public int getRequiredItemQuantity(final String name, final int index) {
return amount;

}

/**
* Gets the number of repetitions in a substate of quest slot
*
* @param name
* The quest's name
* @param index
* the index of the sub state to get (separated by ";")
* @return the integer value in the index of the quest slot, used to represent a number of repetitions
*/
public int getNumberOfRepetitions(final String name, final int index) {
if (!player.hasQuest(name)) {
logger.error(player.getName() + " does not have quest " + name);
return 0;
}
String questState = player.getQuest(name, index);
return MathHelper.parseIntDefault(questState, 0);
}

}
14 changes: 14 additions & 0 deletions 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 @@ -673,6 +674,19 @@ public static void updateQuests(final Player player) {
player.setQuest(questSlot, 1, Long.toString(System.currentTimeMillis()
- (TimeUtil.MINUTES_IN_HALF_YEAR / 2 * TimeUtil.MILLISECONDS_IN_MINUTE)));
}

// 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;
}
if ("eating".equals(player.getQuest(slot, 0)) && "".equals(player.getQuest(slot, 2))) {
player.setQuest(slot, 2, "1");
}
}

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


Expand Down
47 changes: 29 additions & 18 deletions src/games/stendhal/server/maps/quests/AbstractQuest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import java.util.ArrayList;
import java.util.List;

import games.stendhal.common.MathHelper;
import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.entity.npc.NPCList;
import games.stendhal.server.entity.player.Player;
Expand Down Expand Up @@ -146,25 +145,37 @@ public boolean isCompleted(final Player player) {
&& player.isQuestCompleted(getSlotName());
}

@Override
public boolean hasCompleted(final Player player) {
return getCompletions(player) > 0;
}

/**
* Retrieves number of times player has completed quest.
*
* @param player
* Player for whom quest is being checked.
* @return
* Number of completions.
*/
@Override
public int getCompletions(final Player player) {
return isCompleted(player) ? 1 : 0;
}

/**
* Retrieves number of times player has completed quest.
*
* @param player
* Player for whom quest is being checked.
* @return
* Number of completions.
* @deprecated
*/
@Deprecated
@Override
public int getCompletedCount(final Player player) {
final String questSlot = getSlotName();
final boolean completed = isCompleted(player);
if (player.hasQuest(questSlot)) {
final String[] state = player.getQuest(questSlot).split(";");
final Pair<Integer, Integer> completionsIndexes = questInfo.getCompletionsIndexes();
Integer stateIndex = null;
if (completed) {
stateIndex = completionsIndexes.second();
} else {
stateIndex = completionsIndexes.first();
}
if (stateIndex != null && state.length > stateIndex && !"".equals(state[stateIndex])) {
return MathHelper.parseIntDefault(state[stateIndex], completed ? 1 : 0);
}
}
// default is to return 1 if quest is in complete state and 0 otherwise
return completed ? 1 : 0;
return getCompletions(player);
}

@Override
Expand Down
39 changes: 20 additions & 19 deletions src/games/stendhal/server/maps/quests/ChocolateForElisabeth.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2023 - Stendhal *
* (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
Expand Down Expand Up @@ -86,7 +86,7 @@
* <li>Every 60 minutes</li>
* </ul>
*/
public class ChocolateForElisabeth extends AbstractQuest {
public class ChocolateForElisabeth extends CompletionsTrackingQuest {

// constants
private static final String QUEST_SLOT = "chocolate_for_elisabeth";
Expand All @@ -104,7 +104,7 @@ private void chocolateStep() {
npc.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
new QuestNotStartedCondition(QUEST_SLOT), new QuestNotInStateCondition(QUEST_SLOT, "rejected")),
new QuestNotStartedCondition(QUEST_SLOT), new QuestNotInStateCondition(QUEST_SLOT, 0, "rejected")),
ConversationStates.ATTENDING,
"I can't remember when I smelt the good taste of #chocolate the last time...",
null);
Expand All @@ -117,7 +117,7 @@ private void chocolateStep() {
npc.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
new QuestInStateCondition(QUEST_SLOT, "start"), new PlayerHasItemWithHimCondition("chocolate bar")),
new QuestInStateCondition(QUEST_SLOT, 0, "start"), new PlayerHasItemWithHimCondition("chocolate bar")),
ConversationStates.IDLE,
"My mum wants to know who I was asking for chocolate from now :(",
null);
Expand All @@ -126,7 +126,7 @@ private void chocolateStep() {
npc.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
new QuestInStateCondition(QUEST_SLOT, "start"), new NotCondition(new PlayerHasItemWithHimCondition("chocolate bar"))),
new QuestInStateCondition(QUEST_SLOT, 0, "start"), new NotCondition(new PlayerHasItemWithHimCondition("chocolate bar"))),
ConversationStates.ATTENDING,
"I hope that someone will bring me some chocolate soon...:(",
null);
Expand All @@ -135,7 +135,7 @@ private void chocolateStep() {
npc.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
new QuestInStateCondition(QUEST_SLOT, "mummy"), new PlayerHasItemWithHimCondition("chocolate bar")),
new QuestInStateCondition(QUEST_SLOT, 0, "mummy"), new PlayerHasItemWithHimCondition("chocolate bar")),
ConversationStates.QUESTION_1,
"Awesome! Is that chocolate for me?",
null);
Expand All @@ -144,7 +144,7 @@ private void chocolateStep() {
npc.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
new QuestInStateCondition(QUEST_SLOT, "mummy"), new NotCondition(new PlayerHasItemWithHimCondition("chocolate bar"))),
new QuestInStateCondition(QUEST_SLOT, 0, "mummy"), new NotCondition(new PlayerHasItemWithHimCondition("chocolate bar"))),
ConversationStates.ATTENDING,
"I hope that someone will bring me some chocolate soon...:(",
null);
Expand All @@ -153,7 +153,7 @@ private void chocolateStep() {
npc.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
new QuestStartedCondition(QUEST_SLOT), new QuestNotInStateCondition(QUEST_SLOT, "start"), new QuestNotInStateCondition(QUEST_SLOT, "mummy")),
new QuestStartedCondition(QUEST_SLOT), new QuestNotInStateCondition(QUEST_SLOT, 0, "start"), new QuestNotInStateCondition(QUEST_SLOT, 0, "mummy")),
ConversationStates.ATTENDING,
"Hello.",
null);
Expand All @@ -162,7 +162,7 @@ private void chocolateStep() {
npc.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(npc.getName()),
new QuestInStateCondition(QUEST_SLOT, "rejected")),
new QuestInStateCondition(QUEST_SLOT, 0, "rejected")),
ConversationStates.ATTENDING,
"Hello.",
null);
Expand Down Expand Up @@ -213,15 +213,15 @@ private void chocolateStep() {
null,
ConversationStates.ATTENDING,
"Thank you!",
new SetQuestAction(QUEST_SLOT, "start"));
new SetQuestAction(QUEST_SLOT, 0, "start"));

// Player says no, they've lost karma
npc.add(ConversationStates.QUEST_OFFERED,
ConversationPhrases.NO_MESSAGES,
null,
ConversationStates.IDLE,
"Ok, I'll wait till mommy finds some helpers...",
new SetQuestAndModifyKarmaAction(QUEST_SLOT, "rejected", -5.0));
new SetQuestAndModifyKarmaAction(QUEST_SLOT, 0, "rejected", -5.0));

// Player has got chocolate bar and spoken to mummy
final List<ChatAction> reward = new LinkedList<ChatAction>();
Expand All @@ -239,8 +239,9 @@ public void fire(final Player player, final Sentence sentence, final EventRaiser
}
});
reward.add(new IncreaseXPAction(500));
reward.add(new SetQuestAction(QUEST_SLOT, "eating;"));
reward.add(new SetQuestToTimeStampAction(QUEST_SLOT,1));
reward.add(new SetQuestAction(QUEST_SLOT, 0, "eating"));
reward.add(new SetQuestToTimeStampAction(QUEST_SLOT, 1));
reward.add(incrementCompletionsAction());
reward.add(new IncreaseKarmaAction(10.0));
reward.add(new InflictStatusOnNPCAction("chocolate bar"));

Expand Down Expand Up @@ -284,10 +285,10 @@ private void meetMummyStep() {
mummyNPC.add(ConversationStates.IDLE,
ConversationPhrases.GREETING_MESSAGES,
new AndCondition(new GreetingMatchesNameCondition(mummyNPC.getName()),
new QuestInStateCondition(QUEST_SLOT, "start")),
new QuestInStateCondition(QUEST_SLOT, 0, "start")),
ConversationStates.ATTENDING,
"Oh you met my daughter Elisabeth already. You seem like a nice person so it would be really kind, if you can bring her a chocolate bar because I'm not #strong enough for that.",
new SetQuestAction(QUEST_SLOT, "mummy"));
new SetQuestAction(QUEST_SLOT, 0, "mummy"));

mummyNPC.addReply("strong", "I tried to get some chocolate for Elisabeth a few times, but I couldn't make my way through the assassins and bandits running around #there.");

Expand All @@ -305,7 +306,7 @@ public void addToWorld() {
fillQuestInfo(
"Chocolate for Elisabeth",
"Sweet, sweet chocolate! No one can live without it! And Elisabeth loooves to have some...",
true);
true, 2);
chocolateStep();
meetMummyStep();
}
Expand All @@ -318,14 +319,14 @@ public List<String> getHistory(final Player player) {
return res;
}
res.add("Elisabeth is a sweet little girl who lives in Kirdneh together with her family.");
final String questState = player.getQuest(QUEST_SLOT);
final String questState = player.getQuest(QUEST_SLOT, 0);
if ("rejected".equals(questState)) {
res.add("I don't like sweet little girls.");
}
if (player.isQuestInState(QUEST_SLOT, "start","mummy") || isCompleted(player)) {
if (player.isQuestInState(QUEST_SLOT, 0, "start","mummy") || isCompleted(player)) {
res.add("Little Elisabeth wants a chocolate bar.");
}
if (player.isQuestInState(QUEST_SLOT, "start","mummy") && player.isEquipped("chocolate bar") || isCompleted(player)) {
if (player.isQuestInState(QUEST_SLOT, 0, "start","mummy") && player.isEquipped("chocolate bar") || isCompleted(player)) {
res.add("I found a tasty chocolate bar for Elisabeth.");
}
if ("mummy".equals(questState) || isCompleted(player)) {
Expand Down
Loading
Loading