From c4fe94dd86283458fa87f0b0b5f2515bbd648a8d Mon Sep 17 00:00:00 2001 From: Hendrik Brummermann Date: Fri, 24 May 2024 06:13:17 +0200 Subject: [PATCH 01/19] updated version numbers --- app/android/client/build.gradle | 4 ++-- app/android/client/src/main/res/values/strings.xml | 2 +- app/neutralinojs/neutralino.config.json | 2 +- bin/runserver.bat | 2 +- bin/runserver.sh | 2 +- build.ant.properties | 4 ++-- buildtools/mkdocs/mkdocs.yml | 2 +- src/games/stendhal/common/Debug.java | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) mode change 100755 => 100644 bin/runserver.sh 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/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/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. From e77b9036480e815c7018b0c59cb41c4d353cb8e9 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Fri, 24 May 2024 20:55:52 -0700 Subject: [PATCH 02/19] Class for adding a customized result to BuiltQuest history --- .../server/entity/npc/quest/BuiltQuest.java | 1 + .../entity/npc/quest/QuestHistoryBuilder.java | 35 ++++++++++++++++++- .../entity/npc/quest/QuestHistoryResult.java | 33 +++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/games/stendhal/server/entity/npc/quest/QuestHistoryResult.java 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/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); +} From 14e29cf0c2542a0e16c1ea9c91d3fb8156017174 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Fri, 24 May 2024 20:58:12 -0700 Subject: [PATCH 03/19] Show number of hot deliveries in Pizza Delivery quest history --- .../server/maps/quests/PizzaDelivery.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) 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") + "."); + } + } + } } From bba21bd16678ebb80863c22c6691a9d1abc00fab Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sat, 25 May 2024 00:58:57 -0700 Subject: [PATCH 04/19] In case of logout in arena, update deathmatch slot after teleport to... ...allow player to start again Closes: https://github.com/arianne/stendhal/issues/724 --- doc/CHANGES.txt | 1 + src/games/stendhal/server/maps/deathmatch/DeathmatchArea.java | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/CHANGES.txt b/doc/CHANGES.txt index 51a39be1f5..664040b743 100644 --- a/doc/CHANGES.txt +++ b/doc/CHANGES.txt @@ -22,6 +22,7 @@ Changelog *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/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."); } From fc13470c9232b19bec452c7c9902011e30370d83 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sat, 25 May 2024 01:05:31 -0700 Subject: [PATCH 05/19] Disable Portuguese translation pending review --- .../pt/{full-description.txt => full-description.temp.txt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/android/client/src/main/play/listings/pt/{full-description.txt => full-description.temp.txt} (100%) 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 From a89d346d955c6a0720ea4e87fe65adab5f48823c Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sat, 25 May 2024 01:12:36 -0700 Subject: [PATCH 06/19] Reword changes --- doc/CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CHANGES.txt b/doc/CHANGES.txt index 664040b743..6e17ec5f4d 100644 --- a/doc/CHANGES.txt +++ b/doc/CHANGES.txt @@ -13,7 +13,7 @@ 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 From 1424391ec5985e8d767ab26d56a5b8b9d8636832 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sat, 25 May 2024 20:08:15 -0700 Subject: [PATCH 07/19] Update changes pertaining to Android release --- .../main/play/release-notes/en-US/default.txt | 76 ++++--------------- 1 file changed, 15 insertions(+), 61 deletions(-) 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..da90c3a19d 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,19 @@ - -1.46 - *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 - -*graphics* -- redrawn placeholder tiles in Oni Palace -- fixed some outfit errors -- disabled unfinished weapon-style attack sprites +- renamed chef Patrick to Preston +- new achievements: + - 30 Minutes or Less: Deliver 25 hot pizzas +- Balduin allows requesting different item for Ultimate Collector quest *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 +- fixed text extending past edge of notification bubbles +- added support for saving chat log to file +- 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 -*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 +*server fixes* +- fixed Seven Cherubs not showing up as completed +- fixed unable to start deathmatch after logout while in arena From 042b286c21fefe7d825495164e62ec880011d3e3 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 03:13:04 -0700 Subject: [PATCH 08/19] Clean up extra trailing semicolon --- .../src/main/java/org/stendhalgame/client/DownloadHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..3c259a43ff 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 @@ -27,7 +27,7 @@ import android.util.Base64; */ public class DownloadHandler { private boolean result = false; - private String message = null;; + private String message = null; public void download(final String url, final String mimetype) { From 2688cf8a187209a069415d8410a9e9befddcc4fd Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 04:20:11 -0700 Subject: [PATCH 09/19] Support plain text download in Android client Closes: https://github.com/arianne/stendhal/issues/727 --- .../stendhalgame/client/DownloadHandler.java | 145 +++++++++++++++--- 1 file changed, 121 insertions(+), 24 deletions(-) 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 3c259a43ff..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 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"; } } From 77c60c33de657b49fdda96eac223d3ecf5411b04 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 05:03:23 -0700 Subject: [PATCH 10/19] Fix button spacing of chat log context menu --- src/js/stendhal/ui/component/ChatLogComponent.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 = "
"; + let content = "
"; for (let i = 0; i < this.options.length; i++) { - content += "
"; + content += ""; } content += "
"; this.componentElement.innerHTML = content; From 518ad38b09b24ca1fb95ae1570a00ada0abec14e Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 11:59:55 -0700 Subject: [PATCH 11/19] Add sliders for remaining sound layers in settings dialog --- .../main/play/release-notes/en-US/default.txt | 1 + doc/CHANGES.txt | 1 + .../stendhal/ui/dialog/settings/SoundTab.ts | 24 ++++++++++++++----- 3 files changed, 20 insertions(+), 6 deletions(-) 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 da90c3a19d..6263c55ab8 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 @@ -13,6 +13,7 @@ - supports optional tab placement above panel contents - travel log tabs match theme - added basic lighting effects support +- added volume tab to settings dialog *server fixes* - fixed Seven Cherubs not showing up as completed diff --git a/doc/CHANGES.txt b/doc/CHANGES.txt index 6e17ec5f4d..3060dc0a77 100644 --- a/doc/CHANGES.txt +++ b/doc/CHANGES.txt @@ -19,6 +19,7 @@ Changelog - supports optional tab placement above panel contents - travel log tabs match theme - added basic lighting effects support +- added volume tab to settings dialog *server fixes* - fixed Seven Cherubs not showing up as completed diff --git a/src/js/stendhal/ui/dialog/settings/SoundTab.ts b/src/js/stendhal/ui/dialog/settings/SoundTab.ts index 1a98f80ef2..b4cd9a5edf 100644 --- a/src/js/stendhal/ui/dialog/settings/SoundTab.ts +++ b/src/js/stendhal/ui/dialog/settings/SoundTab.ts @@ -40,15 +40,27 @@ export class SoundTab extends AbstractSettingsTab { }; chkSound.addTo(col1); - const volMaster = new SliderComponent("setting-vol-master", "Master", 0, 100); - volMaster.setValue(sound.getVolume("master") * 100); - volMaster.onchange = function(evt: Event) { - sound.setVolume("master", volMaster.getValue() / 100); + const layers = [ + ["master", "Master"], + ["gui", "GUI"], + ["sfx", "Effects"], + ["creature", "Creatures"], + ["ambient", "Ambient"], + ["music", "Music"] + ]; + + for (const group of layers) { + const layer = group[0]; + const label = group[1]; + const slider = new SliderComponent("setting-vol-" + layer, label, 0, 100); + slider.setValue(sound.getVolume(layer) * 100); + slider.onchange = function(evt: Event) { + sound.setVolume(layer, slider.getValue() / 100); + } + slider.addTo(col1); } - volMaster.addTo(col1); // TODO: - // - add sliders for remaining sound channels // - disable sliders when sound is disabled // - show volume level value } From 5b15d1d35ddb9f19908f07af61c4eb14787333c1 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 12:40:11 -0700 Subject: [PATCH 12/19] Add SettingsComponent.getValue method --- .../stendhal/ui/dialog/settings/SoundTab.ts | 2 +- .../stendhal/ui/toolkit/SettingsComponent.ts | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/js/stendhal/ui/dialog/settings/SoundTab.ts b/src/js/stendhal/ui/dialog/settings/SoundTab.ts index b4cd9a5edf..2c7170f75f 100644 --- a/src/js/stendhal/ui/dialog/settings/SoundTab.ts +++ b/src/js/stendhal/ui/dialog/settings/SoundTab.ts @@ -35,7 +35,7 @@ export class SoundTab extends AbstractSettingsTab { const chkSound = new SettingsComponent("chk_sound", "Enable sound"); chkSound.setValue(config.getBoolean("sound")); chkSound.onchange = function(evt: Event) { - config.set("sound", (chkSound.componentElement as HTMLInputElement).checked); + config.set("sound", chkSound.getValue() as boolean); sound.onStateChanged(); }; chkSound.addTo(col1); diff --git a/src/js/stendhal/ui/toolkit/SettingsComponent.ts b/src/js/stendhal/ui/toolkit/SettingsComponent.ts index e766ae4caa..e94e1e67f9 100644 --- a/src/js/stendhal/ui/toolkit/SettingsComponent.ts +++ b/src/js/stendhal/ui/toolkit/SettingsComponent.ts @@ -164,6 +164,33 @@ export class SettingsComponent extends WidgetComponent { } } + /** + * Retrieves current value of component. + * + * Returns the following for each component type: + * - select: (`number`) selected index + * - check box: (`boolean`) checked state + * - default: (`string`) elements text value + * + * @returns {string|number|boolean} + * Component value. + */ + getValue(): string|number|boolean { + switch(this._type) { + case WidgetType.SELECT: + // selected number index + return (this.componentElement as HTMLSelectElement).selectedIndex; + break; + case WidgetType.CHECK: + // checked boolean state + return (this.componentElement as HTMLInputElement).checked; + break; + default: + // text value + return (this.componentElement as HTMLInputElement).value; + } + } + /** * Adds a selectable option. * From cfd976738e80e3a047d37cd8ea171e4560e03f1a Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 12:45:05 -0700 Subject: [PATCH 13/19] Add ComponentBase.setEnabled method --- src/js/stendhal/ui/toolkit/ComponentBase.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/js/stendhal/ui/toolkit/ComponentBase.ts b/src/js/stendhal/ui/toolkit/ComponentBase.ts index c90be74fd2..bbdfa28d28 100644 --- a/src/js/stendhal/ui/toolkit/ComponentBase.ts +++ b/src/js/stendhal/ui/toolkit/ComponentBase.ts @@ -57,4 +57,14 @@ export abstract class ComponentBase { hasFocus(): boolean { return document.activeElement == this.componentElement; } + + /** + * Enables or disables the HTML element. + * + * @param {boolean} enabled + * Enabled state to be set. + */ + setEnabled(enabled: boolean) { + (this.componentElement as any).disabled = !enabled; + } } From d6143973e589da0615cf5e32742d84354277b1e8 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 12:45:46 -0700 Subject: [PATCH 14/19] Disable sliders when sound not enabled --- .../stendhal/ui/dialog/settings/SoundTab.ts | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/js/stendhal/ui/dialog/settings/SoundTab.ts b/src/js/stendhal/ui/dialog/settings/SoundTab.ts index 2c7170f75f..7c91cf7399 100644 --- a/src/js/stendhal/ui/dialog/settings/SoundTab.ts +++ b/src/js/stendhal/ui/dialog/settings/SoundTab.ts @@ -24,19 +24,28 @@ import { ConfigManager } from "../../../util/ConfigManager"; export class SoundTab extends AbstractSettingsTab { + private readonly sliders: SliderComponent[]; + + constructor(parent: SettingsDialog, element: HTMLElement) { super(element); const config = ConfigManager.get(); const sound = SoundManager.get(); + this.sliders = []; const col1 = this.child("#col1")!; + // state of sound when dialog is created + let soundEnabled = config.getBoolean("sound"); + // TODO: add DOM element creation to `SettingsDialog.createCheckBox` const chkSound = new SettingsComponent("chk_sound", "Enable sound"); - chkSound.setValue(config.getBoolean("sound")); - chkSound.onchange = function(evt: Event) { - config.set("sound", chkSound.getValue() as boolean); + chkSound.setValue(soundEnabled); + chkSound.onchange = (evt: Event) => { + soundEnabled = chkSound.getValue() as boolean; + config.set("sound", soundEnabled); sound.onStateChanged(); + this.setSlidersEnabled(soundEnabled); }; chkSound.addTo(col1); @@ -58,10 +67,17 @@ export class SoundTab extends AbstractSettingsTab { sound.setVolume(layer, slider.getValue() / 100); } slider.addTo(col1); + this.sliders.push(slider); } + this.setSlidersEnabled(soundEnabled); // TODO: - // - disable sliders when sound is disabled // - show volume level value } + + private setSlidersEnabled(enabled: boolean) { + for (const slider of this.sliders) { + slider.setEnabled(enabled); + } + } } From 34b735f1ec0d52c1b89fe55f1f327904b83f2635 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Sun, 26 May 2024 12:51:42 -0700 Subject: [PATCH 15/19] Reword changes --- .../client/src/main/play/release-notes/en-US/default.txt | 2 +- doc/CHANGES.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 6263c55ab8..af7b5e5797 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 @@ -13,7 +13,7 @@ - supports optional tab placement above panel contents - travel log tabs match theme - added basic lighting effects support -- added volume tab to settings dialog +- added sound tab to settings dialog *server fixes* - fixed Seven Cherubs not showing up as completed diff --git a/doc/CHANGES.txt b/doc/CHANGES.txt index 3060dc0a77..d82a906879 100644 --- a/doc/CHANGES.txt +++ b/doc/CHANGES.txt @@ -19,7 +19,7 @@ Changelog - supports optional tab placement above panel contents - travel log tabs match theme - added basic lighting effects support -- added volume tab to settings dialog +- added sound tab to settings dialog *server fixes* - fixed Seven Cherubs not showing up as completed From 6c3d66277e1ec0bb1b14c1e0a2ce62c209619402 Mon Sep 17 00:00:00 2001 From: Hendrik Brummermann Date: Thu, 30 May 2024 23:23:26 +0200 Subject: [PATCH 16/19] updated Android release notes --- .../main/play/release-notes/en-US/default.txt | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) 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 af7b5e5797..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,20 +1,9 @@ -*world* -- renamed chef Patrick to Preston -- new achievements: - - 30 Minutes or Less: Deliver 25 hot pizzas -- Balduin allows requesting different item for Ultimate Collector quest +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. -*web client* -- fixed text extending past edge of notification bubbles -- added support for saving chat log to file -- 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 +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. -*server fixes* -- fixed Seven Cherubs not showing up as completed -- fixed unable to start deathmatch after logout while in arena +Speaking of weapons, some creatures have once again taken up arms. For example the angel and dark angel have new swords. + +Last but not least: We released an official Android App, which is available in the download section of our website or on F-Droid. + +Please see the complete change log for further details: http://localhost/game/stendhal.html#changes \ No newline at end of file From 5c957584f6492d11f4a8684a494a666b2ead0778 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Mon, 3 Jun 2024 14:31:06 -0700 Subject: [PATCH 17/19] Add failsafe to DeliverItemTask.isDeliveryTooLate --- .../entity/npc/quest/DeliverItemTask.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java b/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java index d8d45a3d49..c21059c406 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,22 @@ 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; + } } + } catch (final NumberFormatException | ArrayIndexOutOfBoundsException e) { + Logger.getLogger(DeliverItemTask.class).error(e); } return false; - } /** Takes away the player's uniform, if the he is wearing it. From 52dbfcbaa1b8b53c1acc5ee5f136d9d4ab0f6874 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Mon, 3 Jun 2024 14:11:43 -0700 Subject: [PATCH 18/19] Fix parsing completions count of Kill Enemy Army quest --- .../stendhal/server/maps/quests/KillEnemyArmy.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) 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; - } } From a41681759f35562d285bc7823c873f2087447354 Mon Sep 17 00:00:00 2001 From: Jordan Irwin Date: Wed, 5 Jun 2024 22:44:44 -0700 Subject: [PATCH 19/19] Don't assume on-time delivery when timestamp isn't available --- .../stendhal/server/entity/npc/quest/DeliverItemTask.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java b/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java index c21059c406..42803e309b 100644 --- a/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java +++ b/src/games/stendhal/server/entity/npc/quest/DeliverItemTask.java @@ -115,12 +115,14 @@ public class DeliverItemTask extends QuestTaskBuilder { + (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.