diff --git a/app/android/client/build.gradle b/app/android/client/build.gradle
index a3c3c643c4..bb7529abc2 100644
--- a/app/android/client/build.gradle
+++ b/app/android/client/build.gradle
@@ -10,8 +10,8 @@ android {
applicationId namespace
minSdk 21
targetSdk 32
- versionCode 1046005
- versionName "1.46.5"
+ versionCode 1047000
+ versionName "1.47"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
targetSdkVersion 32
minSdkVersion 21
diff --git a/app/android/client/src/main/java/org/stendhalgame/client/DownloadHandler.java b/app/android/client/src/main/java/org/stendhalgame/client/DownloadHandler.java
index 4144ed8515..b8d9bd8144 100644
--- a/app/android/client/src/main/java/org/stendhalgame/client/DownloadHandler.java
+++ b/app/android/client/src/main/java/org/stendhalgame/client/DownloadHandler.java
@@ -13,6 +13,8 @@ package org.stendhalgame.client;
import java.io.File;
import java.io.FileOutputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -26,24 +28,108 @@ import android.util.Base64;
* created by the web client page.
*/
public class DownloadHandler {
- private boolean result = false;
- private String message = null;;
+ private static enum DownloadType {
+ IMAGE_PNG("image/png"),
+ TEXT_PLAIN("text/plain"),
+ UNSUPPORTED(null);
+
+ private String value;
+
+ private DownloadType(final String value) {
+ this.value = value;
+ }
+
+ public static DownloadType fromString(final String value) {
+ for (final DownloadType v: DownloadType.values()) {
+ if (v.value != null && v.value.equals(value)) {
+ return v;
+ }
+ }
+ return DownloadType.UNSUPPORTED;
+ }
+ }
+
+ private boolean result = false;
+ private String message = null;
+
+
+ /**
+ * Checks for a supported MIME type.
+ *
+ * @param url
+ * File or data URL.
+ * @param mimetype
+ * Detected MIME type.
+ * @return
+ * Download type or unsupported.
+ */
+ private DownloadType checkMimeType(final String url, final String mimetype) {
+ final DownloadType dtype = DownloadType.fromString(mimetype);
+ if (DownloadType.UNSUPPORTED.equals(dtype) && url.startsWith("data:image/png;base64,")) {
+ return DownloadType.IMAGE_PNG;
+ }
+ return dtype;
+ }
+
+ /**
+ * Writes file data to device storage.
+ *
+ * @param dir
+ * Directory where new file is to be created.
+ * @param basename
+ * Filename of new file.
+ * @param data
+ * File contents to be written to storage.
+ */
+ private void downloadInternal(final File dir, final String basename, final byte[] data) {
+ String stacktrace = null;
+ try {
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ final FileOutputStream fos = new FileOutputStream(new File(dir, basename));
+ fos.write(data);
+ fos.close();
+ this.result = true;
+ } catch (final java.lang.NoClassDefFoundError e) {
+ this.message = "an error occurred while decoding data (see debug log for more info)";
+ stacktrace = stackTraceToString(e);
+ } catch (java.io.IOException e) {
+ this.message = "an error occurred while attempting to write file (see debug log for more info)";
+ stacktrace = stackTraceToString(e);
+ }
+
+ if (stacktrace != null) {
+ Logger.error(stacktrace.toString());
+ }
+ }
+
+ /**
+ * Writes file data to device storage.
+ *
+ * @param url
+ * A data URL.
+ * @param mimetype
+ * Detected MIME type.
+ */
public void download(final String url, final String mimetype) {
final Uri uri = Uri.parse(url);
final String scheme = uri.getScheme();
final String storageState = Environment.getExternalStorageState();
+ final DownloadType dtype = checkMimeType(url, mimetype);
if (!MainActivity.get().getActiveClientView().isGameActive()) {
this.message = "downloading from this page not supported";
} else if (!"data".equals(scheme)) {
+ // only data URL supported
this.message = "download type \"" + scheme + "\" not supported";
- } else if (!"image/png".equals(mimetype) || !url.startsWith("data:image/png;base64,")) {
+ } else if (DownloadType.UNSUPPORTED.equals(dtype)) {
this.message = "mimetype not supported: " + mimetype;
} else if (!Environment.MEDIA_MOUNTED.equals(storageState)) {
this.message = "storage not available for writing (state: " + storageState + ")";
- } else {
+ } else if (DownloadType.IMAGE_PNG.equals(dtype)) {
final File targetDir = new File(Environment.getExternalStorageDirectory()
+ "/Pictures/Screenshots");
final String targetName = "stendhal_"
@@ -52,32 +138,43 @@ public class DownloadHandler {
Logger.debug("Saving screenshot: " + targetDir.getPath()
+ "/" + targetName + " (" + mimetype + ")");
- String msg;
- String stacktrace = null;
- try {
- if (!targetDir.exists()) {
- targetDir.mkdirs();
+ final byte[] data = Base64.decode(url.split("base64,")[1], Base64.DEFAULT);
+ downloadInternal(targetDir, targetName, data);
+ if (this.result) {
+ this.message = "saved screenshot to " + targetDir.getPath() + "/" + targetName;
+ }
+ } else if (DownloadType.TEXT_PLAIN.equals(dtype)) {
+ // `Environment.DIRECTORY_DOWNLOADS` fails on newer Android versions
+ //final File targetDir = new File(Environment.DIRECTORY_DOWNLOADS);
+ final File targetDir = new File(Environment.getExternalStorageDirectory() + "/Download");
+ // default filename
+ final String targetName = "stendhal_" + new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")
+ .format(new Date()) + ".txt";
+
+ Logger.debug("Saving file: " + targetDir.getPath()
+ + "/" + targetName + " (" + mimetype + ")");
+
+ final String[] parts = url.split(",");
+ byte[] data;
+ if (parts[0].endsWith(";base64")) {
+ data = Base64.decode(parts[1], Base64.DEFAULT);
+ } else {
+ try {
+ data = URLDecoder.decode(parts[1], StandardCharsets.UTF_8.name())
+ .getBytes(StandardCharsets.UTF_8);
+ } catch (final java.io.UnsupportedEncodingException e) {
+ this.message = "an error occurred while attempting to decode data URL (see debug log for more info)";
+ Logger.error(stackTraceToString(e));
+ return;
}
-
- final byte[] data = Base64.decode(url.split("base64,")[1], Base64.DEFAULT);
- final FileOutputStream fos = new FileOutputStream(new File(targetDir, targetName));
- fos.write(data);
- fos.close();
-
- this.result = true;
- msg = "saved screenshot to " + targetDir.getPath() + "/" + targetName;
- } catch (final java.lang.NoClassDefFoundError e) {
- msg = "an error occurred while decoding data (see debug log for more info)";
- stacktrace = stackTraceToString(e);
- } catch (java.io.IOException e) {
- msg = "an error occurred while attempting to write file (see debug log for more info)";
- stacktrace = stackTraceToString(e);
}
- this.message = msg;
- if (stacktrace != null) {
- Logger.error(stacktrace.toString());
+ downloadInternal(targetDir, targetName, data);
+ if (this.result) {
+ this.message = "file saved to " + targetDir.getPath() + "/" + targetName;
}
+ } else {
+ this.message = "an unknown error occurred";
}
}
diff --git a/app/android/client/src/main/play/listings/pt/full-description.txt b/app/android/client/src/main/play/listings/pt/full-description.temp.txt
similarity index 100%
rename from app/android/client/src/main/play/listings/pt/full-description.txt
rename to app/android/client/src/main/play/listings/pt/full-description.temp.txt
diff --git a/app/android/client/src/main/play/release-notes/en-US/default.txt b/app/android/client/src/main/play/release-notes/en-US/default.txt
index e0547dac4e..a2fc8271aa 100644
--- a/app/android/client/src/main/play/release-notes/en-US/default.txt
+++ b/app/android/client/src/main/play/release-notes/en-US/default.txt
@@ -1,65 +1,9 @@
+Pizza is a popular meal of choice. With growing demand, Leander is looking to hire reliable workers to transport his hot and delicious cuisine to patrons. Couriers with reputations of on-time deliveries are being recognized for their work ethic.
-1.46
+Some adventurers may be distressed and feel that their quest for the title of "Ultimate Collector" is in vain. Well fret no more, as Balduin is offering a ray of hope. Requests to bring him a different item are now accepted afer some time has passed.
-*world*
-- renamed items:
- - "courgette" to "zucchini"
- - "iron" to "iron bar"
- - "salad" to "lettuce"
-- fixed many NPCs not responding to certain chat options
-- normalized spelling of some words to American English in most NPC dialogues
- - "colour" -> "color"
- - "defence" -> "defense"
- - "favour" -> "favor"
- - "favourite" -> "favorite"
- - "fulfil" -> "fulfill"
- - "organise" -> "organize"
- - "recognise" -> "rocognize"
-- Orchiwald will stop after entity collision instead of reversing path
-- foghorn sounds plays when ferry arrives at mainland & island
-- added commerce sound to more NPCs when exchanging money for items/services
-- seeds can be used from inventory
+Speaking of weapons, some creatures have once again taken up arms. For example the angel and dark angel have new swords.
-*graphics*
-- redrawn placeholder tiles in Oni Palace
-- fixed some outfit errors
-- disabled unfinished weapon-style attack sprites
+Last but not least: We released an official Android App, which is available in the download section of our website or on F-Droid.
-*web client*
-- improved movement handling with on-screen joystick & direction pad
-- alternate "floating" menu style
-- alternate "floating" chat panel style
-- software keyboard is automatically hidden after sending chat message
-- optional activity indicator for corpses & some signs
-- immediate configuration changes affect only the active client/browser tab
-- application menu dialog doesn't close when clicking on background
-- correct NPC title is displayed in chat options dialog
-- disabled highlighting joystick/d-pad button on mouse double-click & drag
-- joystick/d-pad isn't shown until user interface is ready
-- character name in stats panel uses default font size
-- fixed chest default open/close behavior (clicking on open chest opens inventory window instead of closing)
-- doesn't attempt to open corpse/chest inventory windows when character not in range
-- fixed chat history duplicates
-- chat options dialog remains open until NPC is no longer attending or player closes
-- fixed continuous movement state not always updated at startup
-- supports displaying members' HP status in group panel
-- fixed group panel not always showing membership after login
-- added support for touch drag-and-drop
-- fixed weather drawing to not appear to move with player
-- fixed subsequent single clicks on items to not count as double after double click
-- fixed deathmatch scrying orbs
-- fixed portal default action when on a collision tile
-- added autocomplete support
-- fixed positioning of door sprites (-2_orril_lich_palace 84 108)
-- optional click/touch indicator
-- fixed difficult to move small floating windows
-- supports chat commands tab completion
-- supports text highlighting in speech bubbles
-- fixed opening chat log context menu with touch
-- supports continued zone music when changed zone matches
-
-*Android*
-- added option to clear WebView cache
-- added option to lock orientation
-- fixes for using the correct software keyboard
-- app ID changed to conform with F-Droid standards
+Please see the complete change log for further details: http://localhost/game/stendhal.html#changes
\ No newline at end of file
diff --git a/app/android/client/src/main/res/values/strings.xml b/app/android/client/src/main/res/values/strings.xml
index a12f4b2d12..9839219d78 100644
--- a/app/android/client/src/main/res/values/strings.xml
+++ b/app/android/client/src/main/res/values/strings.xml
@@ -5,6 +5,6 @@
Stendhal
stendhalprod8gps5y99pu
prod
- 1.46.5
+ 1.47
diff --git a/app/neutralinojs/neutralino.config.json b/app/neutralinojs/neutralino.config.json
index e351797b8e..847299877e 100644
--- a/app/neutralinojs/neutralino.config.json
+++ b/app/neutralinojs/neutralino.config.json
@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/neutralinojs/neutralinojs/main/schemas/neutralino.config.schema.json",
"applicationId": "org.stendhalgame.client",
- "version": "1.46.5",
+ "version": "1.47",
"defaultMode": "window",
"port": 0,
"documentRoot": "/resources/",
diff --git a/bin/runserver.bat b/bin/runserver.bat
index 629f6ec30d..f133537bad 100644
--- a/bin/runserver.bat
+++ b/bin/runserver.bat
@@ -1,6 +1,6 @@
@echo off
-set STENDHAL_VERSION=1.46.5
+set STENDHAL_VERSION=1.47
set SERVER_JAR=stendhal-server-%STENDHAL_VERSION%.jar
:: change to server directory
diff --git a/bin/runserver.sh b/bin/runserver.sh
old mode 100755
new mode 100644
index 8b299080bb..376aa4d108
--- a/bin/runserver.sh
+++ b/bin/runserver.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-STENDHAL_VERSION="1.46.5"
+STENDHAL_VERSION="1.47"
SERVER_JAR="stendhal-server-${STENDHAL_VERSION}.jar"
# change to server directory
diff --git a/build.ant.properties b/build.ant.properties
index 8e9d19467f..c370737223 100644
--- a/build.ant.properties
+++ b/build.ant.properties
@@ -92,9 +92,9 @@ version_server = http://arianne.sourceforge.net/stendhal.version
# current version of stendhal
version.old = 1.46
-version = 1.46.5
+version = 1.47
# FIXME: dynamic method to set this property?
-version.android = 1046005
+version.android = 1047000
# javac options
javac.deprecation = true
diff --git a/buildtools/mkdocs/mkdocs.yml b/buildtools/mkdocs/mkdocs.yml
index af0e0e0f3a..d65346d1ae 100644
--- a/buildtools/mkdocs/mkdocs.yml
+++ b/buildtools/mkdocs/mkdocs.yml
@@ -1,4 +1,4 @@
-site_name: Stendhal 1.46.5 Reference Documentation
+site_name: Stendhal 1.47 Reference Documentation
site_description: A fun, friendly, & free multiplayer online adventure game.
copyright: Copyright © 2003-2024 Stendhal
site_url: https://stendhalgame.org/
diff --git a/doc/CHANGES.txt b/doc/CHANGES.txt
index 51a39be1f5..d82a906879 100644
--- a/doc/CHANGES.txt
+++ b/doc/CHANGES.txt
@@ -13,15 +13,17 @@ Changelog
*web client*
- fixed text extending past edge of notification bubbles
- added support for saving chat log to file
-- bigger buttons for small touch enabled devices
+- larger buttons for touch-only devices
- travel log displays while waiting for response from server
- fixed infinite request loop when travel log items technically empty
- supports optional tab placement above panel contents
- travel log tabs match theme
- added basic lighting effects support
+- added sound tab to settings dialog
*server fixes*
- fixed Seven Cherubs not showing up as completed
+- fixed unable to start deathmatch after logout while in arena
1.46
diff --git a/src/games/stendhal/common/Debug.java b/src/games/stendhal/common/Debug.java
index 7b8468604c..329a126c67 100644
--- a/src/games/stendhal/common/Debug.java
+++ b/src/games/stendhal/common/Debug.java
@@ -26,7 +26,7 @@ public class Debug {
/** version. */
// Note: This line is updated by build.xml using a regexp so be sure to adjust it in case you modify this line.
- public static final String VERSION = "1.46.5";
+ public static final String VERSION = "1.47";
/** pre release suffix */
// Note: This line is updated by build.xml using a regexp so be sure to adjust it in case you modify this line.
diff --git a/src/games/stendhal/server/entity/npc/quest/BuiltQuest.java b/src/games/stendhal/server/entity/npc/quest/BuiltQuest.java
index 2eef1a713c..4b6c2aa4a2 100644
--- a/src/games/stendhal/server/entity/npc/quest/BuiltQuest.java
+++ b/src/games/stendhal/server/entity/npc/quest/BuiltQuest.java
@@ -86,6 +86,7 @@ public class BuiltQuest extends AbstractQuest {
res.add(completionsShown);
}
}
+ history.applyOtherResults(player, res);
return res;
}
diff --git a/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java b/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java
index d8d45a3d49..42803e309b 100644
--- a/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java
+++ b/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java
@@ -1,5 +1,5 @@
/***************************************************************************
- * (C) Copyright 2003-2023 - Stendhal *
+ * (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
@@ -16,6 +16,8 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import org.apache.log4j.Logger;
+
import games.stendhal.common.Rand;
import games.stendhal.common.grammar.Grammar;
import games.stendhal.common.parser.Sentence;
@@ -103,19 +105,24 @@ public class DeliverItemTask extends QuestTaskBuilder {
* time, or if he doesn't have a delivery to do currently.
*/
boolean isDeliveryTooLate(final Player player, String questSlot) {
- if (player.hasQuest(questSlot) && !player.isQuestCompleted(questSlot)) {
- final String[] questData = player.getQuest(questSlot).split(";");
- final String customerName = questData[0];
- final DeliverItemOrder customerData = orders.get(customerName);
- final long bakeTime = Long.parseLong(questData[1]);
- final long expectedTimeOfDelivery = bakeTime
- + (long) 60 * 1000 * customerData.getExpectedMinutes();
- if (System.currentTimeMillis() > expectedTimeOfDelivery) {
- return true;
+ try {
+ if (player.hasQuest(questSlot) && !player.isQuestCompleted(questSlot)) {
+ final String[] questData = player.getQuest(questSlot).split(";");
+ final String customerName = questData[0];
+ final DeliverItemOrder customerData = orders.get(customerName);
+ final long bakeTime = Long.parseLong(questData[1]);
+ final long expectedTimeOfDelivery = bakeTime
+ + (long) 60 * 1000 * customerData.getExpectedMinutes();
+ if (System.currentTimeMillis() > expectedTimeOfDelivery) {
+ return true;
+ } else {
+ return false;
+ }
}
+ } catch (final NumberFormatException | ArrayIndexOutOfBoundsException e) {
+ Logger.getLogger(DeliverItemTask.class).error(e);
}
- return false;
-
+ return true;
}
/** Takes away the player's uniform, if the he is wearing it.
diff --git a/src/games/stendhal/server/entity/npc/quest/QuestHistoryBuilder.java b/src/games/stendhal/server/entity/npc/quest/QuestHistoryBuilder.java
index 58e8eda3b8..03b8df07a6 100644
--- a/src/games/stendhal/server/entity/npc/quest/QuestHistoryBuilder.java
+++ b/src/games/stendhal/server/entity/npc/quest/QuestHistoryBuilder.java
@@ -1,5 +1,5 @@
/***************************************************************************
- * (C) Copyright 2022 - Faiumoni e.V. *
+ * (C) Copyright 2022-2024 - Faiumoni e.V. *
***************************************************************************
***************************************************************************
* *
@@ -11,6 +11,12 @@
***************************************************************************/
package games.stendhal.server.entity.npc.quest;
+import java.util.LinkedList;
+import java.util.List;
+
+import games.stendhal.server.entity.player.Player;
+
+
/**
* defines the "history" of player progress as shown in the travel log
*
@@ -25,9 +31,13 @@ public class QuestHistoryBuilder {
private String whenQuestCanBeRepeated;
private String whenCompletionsShown;
+ private List otherResults;
+
+
// hide constructor
QuestHistoryBuilder() {
super();
+ otherResults = new LinkedList<>();
}
public QuestHistoryBuilder whenNpcWasMet(String whenNpcWasMet) {
@@ -72,6 +82,16 @@ public class QuestHistoryBuilder {
return this;
}
+ /**
+ * Adds a custom conditional result to history.
+ *
+ * @param result
+ * History result object to be called when history is requested.
+ */
+ public void addResult(final QuestHistoryResult result) {
+ otherResults.add(result);
+ }
+
String getWhenNpcWasMet() {
return whenNpcWasMet;
}
@@ -100,4 +120,17 @@ public class QuestHistoryBuilder {
return this.whenCompletionsShown;
}
+ /**
+ * Calls results objects to update history items list.
+ *
+ * @param player
+ * Player for which history is requested.
+ * @param res
+ * History items.
+ */
+ void applyOtherResults(final Player player, List res) {
+ for (final QuestHistoryResult result: otherResults) {
+ result.apply(player, res);
+ }
+ }
}
diff --git a/src/games/stendhal/server/entity/npc/quest/QuestHistoryResult.java b/src/games/stendhal/server/entity/npc/quest/QuestHistoryResult.java
new file mode 100644
index 0000000000..e3ca29df14
--- /dev/null
+++ b/src/games/stendhal/server/entity/npc/quest/QuestHistoryResult.java
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * Copyright © 2024 - Faiumoni e. V. *
+ ***************************************************************************
+ ***************************************************************************
+ * *
+ * 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.entity.npc.quest;
+
+import java.util.List;
+
+import games.stendhal.server.entity.player.Player;
+
+
+/**
+ * Class for adding a customized result to BuiltQuest history.
+ */
+public interface QuestHistoryResult {
+
+ /**
+ * Called when history is requested.
+ *
+ * @param player
+ * Player for which history is requested.
+ * @param res
+ * History items.
+ */
+ abstract void apply(Player player, List res);
+}
diff --git a/src/games/stendhal/server/maps/deathmatch/DeathmatchArea.java b/src/games/stendhal/server/maps/deathmatch/DeathmatchArea.java
index 49c7dada70..800c7ba684 100644
--- a/src/games/stendhal/server/maps/deathmatch/DeathmatchArea.java
+++ b/src/games/stendhal/server/maps/deathmatch/DeathmatchArea.java
@@ -1,6 +1,6 @@
/* $Id$ */
/***************************************************************************
- * (C) Copyright 2003-2010 - Stendhal *
+ * (C) Copyright 2003-2024 - Stendhal *
***************************************************************************
***************************************************************************
* *
@@ -54,6 +54,8 @@ public class DeathmatchArea implements LoginListener {
"0_semos_mountain_n2_w"), 104, 123);
}
player.teleport(cowardSpot.getZone(), cowardSpot.getX(), cowardSpot.getY(), Direction.DOWN, player);
+ // update slot so player can start again
+ player.setQuest("deathmatch", 0, "cancel");
player.sendPrivateText("You wake up far away from the city in the mountains. But you don't know what happened.");
}
diff --git a/src/games/stendhal/server/maps/quests/KillEnemyArmy.java b/src/games/stendhal/server/maps/quests/KillEnemyArmy.java
index 77bee6a39d..be6b89400e 100644
--- a/src/games/stendhal/server/maps/quests/KillEnemyArmy.java
+++ b/src/games/stendhal/server/maps/quests/KillEnemyArmy.java
@@ -508,7 +508,7 @@ public class KillEnemyArmy extends AbstractQuest {
fillQuestInfo(
"Kill Enemy Army",
"Despot Halb Errvl has a vendetta against any army who opposes him.",
- true);
+ true, 3);
step_1();
}
@@ -596,16 +596,4 @@ public class KillEnemyArmy extends AbstractQuest {
public String getRegion() {
return Region.SEMOS_SURROUNDS;
}
-
- @Override
- public int getCompletedCount(final Player player) {
- int count = 0;
- if (player.hasQuest(QUEST_SLOT)) {
- final String[] state = player.getQuest(QUEST_SLOT).split(";");
- if (state.length > 0) {
- count = Integer.parseInt(state[state.length-1]);
- }
- }
- return count;
- }
}
diff --git a/src/games/stendhal/server/maps/quests/PizzaDelivery.java b/src/games/stendhal/server/maps/quests/PizzaDelivery.java
index 15ef5c555b..1ac0519ce4 100644
--- a/src/games/stendhal/server/maps/quests/PizzaDelivery.java
+++ b/src/games/stendhal/server/maps/quests/PizzaDelivery.java
@@ -11,6 +11,10 @@
***************************************************************************/
package games.stendhal.server.maps.quests;
+import java.util.List;
+
+import games.stendhal.common.MathHelper;
+import games.stendhal.common.grammar.Grammar;
import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.core.engine.StendhalRPZone;
import games.stendhal.server.core.rp.StendhalQuestSystem;
@@ -18,7 +22,9 @@ import games.stendhal.server.entity.Outfit;
import games.stendhal.server.entity.npc.NPCList;
import games.stendhal.server.entity.npc.SpeakerNPC;
import games.stendhal.server.entity.npc.quest.DeliverItemQuestBuilder;
+import games.stendhal.server.entity.npc.quest.QuestHistoryResult;
import games.stendhal.server.entity.npc.quest.QuestManuscript;
+import games.stendhal.server.entity.player.Player;
import games.stendhal.server.maps.Region;
import games.stendhal.server.maps.quests.houses.HouseBuyingMain;
import games.stendhal.server.maps.semos.bakery.ChefNPC;
@@ -60,6 +66,9 @@ import games.stendhal.server.util.ResetSpeakerNPC;
*/
public class PizzaDelivery implements QuestManuscript {
+ private static final String questSlot = "pizza_delivery";
+
+
@Override
public DeliverItemQuestBuilder story() {
DeliverItemQuestBuilder quest = new DeliverItemQuestBuilder();
@@ -68,7 +77,7 @@ public class PizzaDelivery implements QuestManuscript {
quest.info()
.name("Pizza Delivery")
.description("Leander's pizza business is doing so well that he now recruits delivery boys and girls.")
- .internalName("pizza_delivery")
+ .internalName(questSlot)
.repeatableAfterMinutes(0)
.minLevel(0)
.region(Region.SEMOS_CITY)
@@ -84,7 +93,8 @@ public class PizzaDelivery implements QuestManuscript {
.whenInTime("If I hurry, I might still get there, with the pizza hot.")
.whenOutOfTime("The pizza has already gone cold.")
.whenQuestWasCompleted("I delivered the last pizza Leander gave to me.")
- .whenQuestCanBeRepeated("But I'd bet, Leander has more orders.");
+ .whenQuestCanBeRepeated("But I'd bet, Leander has more orders.")
+ .addResult(new HotDeliveryResult());
quest.offer()
@@ -354,4 +364,16 @@ public class PizzaDelivery implements QuestManuscript {
return res;
}
+ /**
+ * Adds number of hot deliveries to quest history.
+ */
+ private class HotDeliveryResult implements QuestHistoryResult {
+ @Override
+ public void apply(Player player, List res) {
+ final int count = MathHelper.parseIntDefault(player.getQuest(questSlot, 3), 0);
+ if (count > 0) {
+ res.add("I have delivered " + count + " hot " + Grammar.plnoun(count, "pizza") + ".");
+ }
+ }
+ }
}
diff --git a/src/js/stendhal/ui/component/ChatLogComponent.ts b/src/js/stendhal/ui/component/ChatLogComponent.ts
index 6f069570f4..d562354df6 100644
--- a/src/js/stendhal/ui/component/ChatLogComponent.ts
+++ b/src/js/stendhal/ui/component/ChatLogComponent.ts
@@ -503,9 +503,9 @@ class LogContextMenu extends Component {
super("contextmenu-template", true);
this.options = options;
- let content = "