Compare commits

...
Sign in to create a new pull request.

18 commits

Author SHA1 Message Date
Hendrik Brummermann
c0d45674b5 fixed missing storage of signature for download from prefered location (fixes #3382547) 2011-07-29 23:53:50 +00:00
Hendrik Brummermann
f59d828108 remove broken .jar files from load-parameter in jar.properties 2011-07-14 13:19:51 +00:00
Hendrik Brummermann
bed8a38452 backported quest improvements by kymara 2011-07-14 13:19:01 +00:00
Hendrik Brummermann
a3610ac841 backported fix by kymara to re-word the world changes 2011-07-14 13:17:58 +00:00
Hendrik Brummermann
4b1f34ef40 fixed compiler warning, added license template 2011-07-13 19:50:06 +00:00
Hendrik Brummermann
e2436944c8 don't add entries to the start of the classpath if they are already there. 2011-07-13 18:35:23 +00:00
Hendrik Brummermann
d298b176c8 backported fix to ignore all files on invalid signature (fixes #3365690) 2011-07-13 18:10:26 +00:00
Hendrik Brummermann
7431a1e0ec fixed missing filename in signatures entries in jar.properties for known files 2011-07-12 21:19:30 +00:00
Hendrik Brummermann
5a9facaf69 added line break to inconsistent update state 2011-07-12 21:02:13 +00:00
Hendrik Brummermann
13fe9b87da treat ClassNotFoundException similar to LinkageError in the sense that it triggers the inconsistent update handling 2011-07-12 20:59:15 +00:00
Hendrik Brummermann
c7b76e0ad8 reverted last fix and implemented it different: Just overwrite the signature in jar.properties if the actual file matches the signature in update.properties 2011-07-12 20:51:09 +00:00
Hendrik Brummermann
b8dbda8db2 compare signature in jar.properties to signature in update.properties before deciding to skip a download 2011-07-12 20:49:18 +00:00
Hendrik Brummermann
422885d34b backported quests improvements by bluelads4 2011-07-12 20:25:24 +00:00
Hendrik Brummermann
52383dd85c SignatureVerifier can now handle hexadecimal strings with an uneven number of digits 2011-07-12 20:21:10 +00:00
Kimmo Rundelin
2ccfb5c7dd Added missing directory separator 2011-07-12 08:45:53 +00:00
Hendrik Brummermann
e90b090cc6 update changelog 2011-07-11 19:23:37 +00:00
Hendrik Brummermann
95b230f2e1 backported fix by kiheru for: Use ~/.config/stendhal as the data directory on unix like systems, unless the user already has saved account data in ~/stendhal 2011-07-11 19:20:20 +00:00
Hendrik Brummermann
622d70f28f updated version number 2011-07-10 21:38:17 +00:00
26 changed files with 320 additions and 125 deletions

View file

@ -73,7 +73,7 @@ version_server = http://arianne.sourceforge.net/stendhal.version
# current version of stendhal
version.old = 0.94
version = 0.94.5
version = 0.95
# javac options
javac.deprecation = true

View file

@ -9,6 +9,7 @@ read http://stendhalgame.org/wiki/Automatic_Software_Updater
******************
- rewrote the updater so that it will not break onces a year anymore because the certificate expires
- on Unix/Linux the home folder now defaults to $HOME/.config/stendhal for new installs
- improved the best player score for low level players: http://stendhalgame.org/wiki/Fixing_RP_Score_2011
* Marauroa*
@ -21,9 +22,10 @@ read http://stendhalgame.org/wiki/Automatic_Software_Updater
when the full client had twice the size of the soundless client.
*world*
- John and his wife Jane on Athor island need some help for saving their vacation
- Harold pays your earnings instantly on start of dialogue
- Andy who walks around on Ados cementary, could need some help by players
- John and Jane on Athor island have a disrupted holiday
- Andy, at Ados cemetery, seeks revenge
- Harold pays owed earnings instantly on start of dialogue
*fixes*

View file

@ -1,3 +1,3 @@
set STENDHAL_VERSION=0.94.5
set STENDHAL_VERSION=0.95
set LOCALCLASSPATH=.;data\script;data\conf;stendhal-server-%STENDHAL_VERSION%.jar;marauroa.jar;mysql-connector.jar;log4j.jar;commons-lang.jar;h2.jar
java -Xmx400m -cp "%LOCALCLASSPATH%" games.stendhal.server.StendhalServer -c server.ini -l

View file

@ -1,5 +1,5 @@
#!/bin/sh
STENDHAL_VERSION="0.94.5"
STENDHAL_VERSION="0.95"
LOCALCLASSPATH=.:data/script/:data/conf/:stendhal-server-$STENDHAL_VERSION.jar:marauroa.jar:mysql-connector.jar:log4j.jar:commons-lang.jar:h2.jar

View file

@ -25,6 +25,7 @@ import games.stendhal.common.Version;
import games.stendhal.common.resource.ResourceManager;
import java.awt.Dimension;
import java.io.File;
import java.security.AccessControlException;
import java.util.Locale;
@ -51,7 +52,7 @@ public class stendhal {
/**
* Directory for storing the persistent game data.
*/
private static final String gameFolder;
private static String gameFolder;
/**
* Just a try to get Webstart working without additional rights.
*/
@ -68,7 +69,7 @@ public class stendhal {
/** We set the main game folder to the game name */
GAME_NAME = ClientGameConfiguration.get("GAME_NAME");
STENDHAL_FOLDER = separator + GAME_NAME.toLowerCase(Locale.ENGLISH) + separator;
gameFolder = System.getProperty("user.home") + STENDHAL_FOLDER;
initGameFolder();
/** setup the search locations for the resource manager */
RESOURCE_MANAGER.addScheme("sound" , "data/sounds");
@ -88,6 +89,39 @@ public class stendhal {
public static final int FPS_LIMIT = 25;
/**
* Initialize the client game directory.
* <p>
* NOTE: IF YOU CHANGE THIS, CHANGE ALSO CORRESPONDING CODE IN
* Bootstrap.java
*/
private static void initGameFolder() {
String defaultFolder = System.getProperty("user.home") + STENDHAL_FOLDER;
/*
* Add any previously unrecognized unix like systems here. These will
* try to use ~/.config/stendhal if the user does not have saved data
* in ~/stendhal.
*
* OS X is counted in here too, but should it?
*
* List taken from:
* http://mindprod.com/jgloss/properties.html#OSNAME
*/
String unixLikes = "AIX|Digital Unix|FreeBSD|HP UX|Irix|Linux|Mac OS X|Solaris";
String system = System.getProperty("os.name");
if (system.matches(unixLikes)) {
// Check first if the user has important data in the default folder.
File f = new File(defaultFolder + "user.dat");
if (!f.exists()) {
gameFolder = System.getProperty("user.home") + separator
+ ".config" + separator + STENDHAL_FOLDER;
return;
}
}
// Everyone else should use the default top level directory in $HOME
gameFolder = defaultFolder;
}
public static void setDoLogin() {
doLogin = true;
}

View file

@ -1,5 +1,18 @@
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import static java.io.File.separator;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -24,8 +37,6 @@ import javax.swing.JOptionPane;
* @author hendrik
*/
public class Bootstrap {
private String pathSep;
private String jarFolder;
private Properties bootProp;
private Properties bootPropOrg;
@ -54,13 +65,23 @@ public class Bootstrap {
*/
void init() {
// discover folder for .jar-files
pathSep = System.getProperty("file.separator");
// Copied from stendhal.java; don't change this to anything different
// from than what's there
final String stendhal = ClientGameConfiguration.get("GAME_NAME").toLowerCase();
System.out.println("GAME: " + stendhal);
String topFolder = System.getProperty("user.home") + separator + stendhal + separator;
String unixLikes = "AIX|Digital Unix|FreeBSD|HP UX|Irix|Linux|Mac OS X|Solaris";
String system = System.getProperty("os.name");
if (system.matches(unixLikes)) {
// Check first if the user has important data in the default folder.
File f = new File(topFolder + "user.dat");
if (!f.exists()) {
topFolder = System.getProperty("user.home") + separator
+ ".config" + separator + stendhal + separator;
}
}
jarFolder = System.getProperty("user.home") + pathSep + stendhal
+ pathSep + "jar" + pathSep;
jarFolder = topFolder + "jar" + separator;
final File folder = new File(jarFolder);
if (!folder.exists()) {
folder.mkdirs();
@ -71,11 +92,13 @@ public class Bootstrap {
/**
* Sets a dynamic classpath up and returns a Class reference loaded from it.
*
* @param includeUpdates should updates from jar.properties be included
* @param firstPhase true, if this is the first phase before the updater is executed
* @return ClassLoader object
* @throws Exception
* if an unexpected error occurs
*/
ClassLoader createClassloader(boolean includeUpdates) throws Exception {
ClassLoader createClassloader(boolean includeUpdates, boolean firstPhase) throws Exception {
final List<URL> jarFiles = new LinkedList<URL>();
if (includeUpdates) {
// load jar.properties
@ -94,6 +117,13 @@ public class Bootstrap {
final String filename = st.nextToken();
if (SignatureVerifier.get().checkSignature(jarFolder + filename, bootProp.getProperty("file-signature." + filename))) {
jarFiles.add(new File(jarFolder + filename).toURI().toURL());
} else {
if (firstPhase) {
// if the signature of one file is not valid, ignore all files and do a fresh download
clearUpdateFiles();
ClassLoader loader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
return loader;
}
}
}
System.out.println("our classpath: " + jarNameString);
@ -151,7 +181,7 @@ public class Bootstrap {
private void handleUpdate() {
// invoke update handling first
try {
final ClassLoader classLoader = createClassloader(true);
final ClassLoader classLoader = createClassloader(true, true);
// is this the initial download (or do we already have the
// program downloaded)?
boolean initialDownload = false;
@ -173,8 +203,8 @@ public class Bootstrap {
// start update handling
final Class< ? > clazz = classLoader.loadClass("games.stendhal.client.update.UpdateManager");
final Method method = clazz.getMethod("process", String.class, Properties.class, Boolean.class);
method.invoke(clazz.newInstance(), jarFolder, bootProp, initialDownload);
final Method method = clazz.getMethod("process", String.class, Properties.class, Boolean.class, ClassLoader.class);
method.invoke(clazz.newInstance(), jarFolder, bootProp, initialDownload, classLoader);
} catch (final SecurityException e) {
throw e;
} catch (final Exception e) {
@ -203,7 +233,7 @@ public class Bootstrap {
// .jar-files may have been added
try {
final ClassLoader classLoader = createClassloader(true);
final ClassLoader classLoader = createClassloader(true, false);
final Class< ? > clazz = classLoader.loadClass(className);
final Method method = clazz.getMethod("main", args.getClass());
method.invoke(null, (Object) args);
@ -264,9 +294,9 @@ public class Bootstrap {
final int res = JOptionPane.showConfirmDialog(
null,
new SelectableLabel(" Sorry an error occurred because of inconsistent code signing.\r\n"
+ " Delete update files so that they are downloaded again after you restart " + ClientGameConfiguration.get("GAME_NAME") + "?\r\n"
+ " Note: This exception can occur if you include signed jars into a self build client."),
new SelectableLabel("Sorry an error occurred because of inconsistent code signing.\r\n"
+ "Delete update files so that they are downloaded again after you restart " + ClientGameConfiguration.get("GAME_NAME") + "?\r\n"
+ "Note: This exception can occur if you include signed jars into a self build client."),
ClientGameConfiguration.get("GAME_NAME"), JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (res == JOptionPane.YES_OPTION) {
@ -281,7 +311,7 @@ public class Bootstrap {
// self build client, do not try to update it
System.err.println("Self build client, starting without update .jar-files");
try {
final ClassLoader classLoader = createClassloader(false);
final ClassLoader classLoader = createClassloader(false, false);
final Class< ? > clazz = classLoader.loadClass(className);
final Method method = clazz.getMethod("main", args.getClass());
method.invoke(null, (Object) args);
@ -297,9 +327,8 @@ public class Bootstrap {
/**
* Handles exceptions during program invocation.
*
* @param message
* @param t
* exception
* @param message error message
* @param t exception
*/
void unexpectedErrorHandling(String message, final Throwable t) {
// unwrap chained exceptions
@ -313,11 +342,11 @@ public class Bootstrap {
if (e instanceof OutOfMemoryError) {
JOptionPane.showMessageDialog(null,
"Sorry, an OutOfMemoryError occurred. Please restart " + ClientGameConfiguration.get("GAME_NAME") + ".");
} else if (e instanceof LinkageError || e instanceof SecurityException) {
} else if (e instanceof LinkageError || e instanceof SecurityException || e instanceof ClassNotFoundException) {
final int res = JOptionPane.showConfirmDialog(
null,
new SelectableLabel(message
+ " Sorry an error occurred because of an inconsistent update state. Delete update files so that they are downloaded again after you restart " + ClientGameConfiguration.get("GAME_NAME") +"?"),
new SelectableLabel(message
+ " Sorry an error occurred because of an inconsistent update state.\r\nDelete update files so that they are downloaded again after you restart " + ClientGameConfiguration.get("GAME_NAME") +"?"),
ClientGameConfiguration.get("GAME_NAME"), JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (res == JOptionPane.YES_OPTION) {

View file

@ -1,3 +1,14 @@
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import java.io.FileNotFoundException;

View file

@ -1,15 +1,14 @@
//*****************************************************************************
//*****************************************************************************
//
// Important note
//
// Please note that this file is compiled using Java 1.2 in the build-script
// in order to display a dialogbox to the user in case an old version of java
// is used. As we compile it with Java 1.2 no new features may be used in this
// class.
//
//*****************************************************************************
//*****************************************************************************
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import java.lang.reflect.Method;

View file

@ -1,3 +1,14 @@
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import java.io.BufferedOutputStream;

View file

@ -1,3 +1,14 @@
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import javax.swing.JLabel;
@ -11,16 +22,19 @@ import javax.swing.JTextArea;
class SelectableLabel extends JTextArea {
private static final long serialVersionUID = -834949100383673798L;
/**
* creates a new SelectableLabel
*
* @param text text to display
*/
SelectableLabel(String text) {
super(text);
setEditable(false);
setBorder(null);
setOpaque(false);
/*
* Get the font directly from JLabel, in case the user is
* using a theme where it does not come from an UIManager
* property.
*/
// Get the font directly from JLabel, in case the user is
// using a theme where it does not come from an UIManager
// property.
JLabel tmp = new JLabel();
setFont(tmp.getFont());
}

View file

@ -1,4 +1,3 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2011 - Faiumoni e. V. *
***************************************************************************
@ -103,8 +102,17 @@ public class SignatureVerifier {
}
// http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java/140861#140861
private static byte[] hexStringToByteArray(String s) {
static byte[] hexStringToByteArray(String hexString) {
String s = hexString;
// handle uneven number of hex digits
int len = s.length();
if (len % 2 == 1) {
s = "0" + s;
len++;
}
// decode
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character

View file

@ -10,6 +10,18 @@
//
//*****************************************************************************
//*****************************************************************************
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import javax.swing.JOptionPane;

View file

@ -1,3 +1,14 @@
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import java.text.NumberFormat;

View file

@ -1,4 +1,3 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
@ -32,6 +31,7 @@ public class UpdateManager {
private Properties bootProp;
private String serverFolder;
private Properties updateProp;
private ClassLoader classLoader;
private UpdateProgressBar updateProgressBar;
private String fromVersion;
private String toVersion;
@ -60,14 +60,12 @@ public class UpdateManager {
/**
* Processes the update.
*
* @param jarFolder
* folder where the .jar files are stored
* @param bootProp
* boot properties
* @param initialDownload
* true, if only the small starter.jar is available
* @param jarFolder folder where the .jar files are stored
* @param bootProp boot properties
* @param initialDownload true, if only the small starter.jar is available
* @param classLoader with update files
*/
public void process(final String jarFolder, final Properties bootProp, final Boolean initialDownload) {
public void process(final String jarFolder, final Properties bootProp, final Boolean initialDownload, ClassLoader classLoader) {
if (!Boolean.parseBoolean(ClientGameConfiguration.get("UPDATE_ENABLE_AUTO_UPDATE"))) {
System.out.println("Automatic Update disabled");
@ -75,6 +73,7 @@ public class UpdateManager {
}
this.jarFolder = jarFolder;
this.bootProp = bootProp;
this.classLoader = classLoader;
init(initialDownload.booleanValue());
if (updateProp == null) {
if (initialDownload.booleanValue()) {
@ -99,6 +98,7 @@ public class UpdateManager {
versionState = VersionState.INITIAL_DOWNLOAD;
}
System.out.println("Update state: " + versionState + " initialDownload: " + initialDownload + " fromVersion: " + fromVersion);
switch (versionState) {
case CURRENT:
System.out.println("Current Version");
@ -158,7 +158,7 @@ public class UpdateManager {
*/
private String getVersion() {
try {
Class<?> clazz = Class.forName("games.stendhal.common.Version");
Class<?> clazz = classLoader.loadClass("games.stendhal.common.Version");
return (String) clazz.getField("VERSION").get(null);
} catch (ClassNotFoundException e) {
// ignore
@ -195,6 +195,7 @@ public class UpdateManager {
if (sizeShould == sizeIs) {
String signature = updateProp.getProperty("file-signature." + file);
if (SignatureVerifier.get().checkSignature(jarFolder + file, signature)) {
bootProp.put("file-signature." + file, signature);
itr.remove();
}
}
@ -313,11 +314,11 @@ public class UpdateManager {
final int shouldSize = Integer.parseInt(updateProp.getProperty("file-size." + file, ""));
String signature = updateProp.getProperty("file-signature." + file);
if ((fileObj.length() != shouldSize) || !SignatureVerifier.get().checkSignature(jarFolder + file, signature)) {
UpdateGUIDialogs.messageBox("Sorry, an error occurred while downloading the update.\r\nFile size of "
UpdateGUIDialogs.messageBox("Sorry, an error occurred while downloading the update.\r\nThe signature of "
+ file
+ "or signature does not match.\r\nWe got file size "
+ " does not match.\r\nWe got "
+ fileObj.length()
+ ". It should be "
+ " bytes of "
+ shouldSize);
updateProgressBar.dispose();
return false;
@ -371,6 +372,7 @@ public class UpdateManager {
System.out.println("signature verification failed");
return false;
}
bootProp.put("file-signature." + file, updateProp.getProperty("file-signature." + file));
} catch (final NumberFormatException e) {
e.printStackTrace(System.err);
return false;
@ -393,8 +395,9 @@ public class UpdateManager {
sb.append(file + ",");
}
sb.append(bootProp.getProperty("load-0.95", ""));
bootProp.put("load-0.95", sb.toString());
if (!bootProp.getProperty("load-0.95", "").startsWith(sb.toString())) {
sb.append(bootProp.getProperty("load-0.95", ""));
bootProp.put("load-0.95", sb.toString());
}
}
}

View file

@ -1,6 +1,5 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *

View file

@ -1,6 +1,5 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
@ -43,10 +42,10 @@ public class UpdateProgressBarHyperLinkListener implements HyperlinkListener {
}
}
static final String[] browsers = { "google-chrome", "chromium-browser", "firefox", "opera",
private static final String[] BROWSER = { "google-chrome", "chromium-browser", "firefox", "opera",
"konqueror", "epiphany", "seamonkey", "galeon", "kazehakase",
"mozilla" };
static final String errMsg = "Error attempting to launch web browser:\n ";
private static final String ERROR_MESSAGE = "Error attempting to launch web browser:\n ";
/**
* Opens the specified web page in the user's default browser
@ -76,7 +75,7 @@ public class UpdateProgressBarHyperLinkListener implements HyperlinkListener {
"rundll32 url.dll,FileProtocolHandler " + url);
else { // assume Unix or Linux
boolean found = false;
for (String browser : browsers)
for (String browser : BROWSER)
if (!found) {
found = Runtime.getRuntime().exec(
new String[] { "which", browser })
@ -87,7 +86,7 @@ public class UpdateProgressBarHyperLinkListener implements HyperlinkListener {
}
}
} catch (Exception e) {
System.err.println(errMsg + url);
System.err.println(ERROR_MESSAGE + url);
System.err.println(e);
}
}

View file

@ -1,6 +1,5 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *

View file

@ -1,15 +1,14 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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. *
* *
***************************************************************************/
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
import java.awt.event.WindowEvent;

View file

@ -1,3 +1,14 @@
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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.client.update;
/**

View file

@ -8,3 +8,14 @@
*/
package games.stendhal.client.update;
/***************************************************************************
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
* 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. *
* *
***************************************************************************/

View file

@ -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 = "0.94.5";
public static final String VERSION = "0.95";
public static final String PRE_RELEASE_VERSION = null;

View file

@ -271,7 +271,7 @@ public class GenerateINI {
out.println();
out.println("server_typeGame=" + gameName);
out.println("server_name=" + gameName + " Marauroa server");
out.println("server_version=0.94.5");
out.println("server_version=0.95");
out.println("server_contact=https://sourceforge.net/tracker/?atid=514826&group_id=66537&func=browse");
out.println();
out.println("# Extensions configured on the server. Enable at will.");

View file

@ -21,6 +21,7 @@ import games.stendhal.server.entity.npc.action.EquipItemAction;
import games.stendhal.server.entity.npc.action.IncreaseKarmaAction;
import games.stendhal.server.entity.npc.action.IncreaseXPAction;
import games.stendhal.server.entity.npc.action.MultipleActions;
import games.stendhal.server.entity.npc.action.SayTimeRemainingAction;
import games.stendhal.server.entity.npc.action.SetQuestAction;
import games.stendhal.server.entity.npc.action.SetQuestToTimeStampAction;
import games.stendhal.server.entity.npc.action.StartRecordingKillsAction;
@ -34,6 +35,7 @@ import games.stendhal.server.entity.npc.condition.TimePassedCondition;
import games.stendhal.server.entity.player.Player;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -86,24 +88,41 @@ public class CleanAthorsUnderground extends AbstractQuest {
ConversationPhrases.QUEST_MESSAGES,
new QuestNotStartedCondition(QUEST_SLOT),
ConversationStates.QUEST_OFFERED,
"My wife Jane and me are on vacation here on Athor island. Unfortunetly we can't explore the whole island cause some ugly creatures step in our way each time. Can you help us by killing some of them to turn our vacation into a good one?",
"My wife Jane and me are on vacation here on Athor island. #Unfortunately we can't explore the whole island because some ugly #creatures step in our way each time. Can you help us by killing some of them to turn our vacation into a good one?",
null);
npc.add(
ConversationStates.QUEST_OFFERED,
Arrays.asList("Unfortunately"),
null,
ConversationStates.QUEST_OFFERED,
"Yes, unfortunately. We wanted to have a great time here but all we did so far was sunbathe at the beach.",
null);
npc.add(
ConversationStates.QUEST_OFFERED,
Arrays.asList("creatures"),
null,
ConversationStates.QUEST_OFFERED,
"We just want to visit the first part of the dungeon, it seems to be very interesting. Some of these ugly things jump around there, even some mummies!",
null);
npc.add(ConversationStates.ATTENDING,
ConversationPhrases.QUEST_MESSAGES,
new AndCondition(new NotCondition(new TimePassedCondition(QUEST_SLOT, 1, WEEK_IN_MINUTES)), new QuestStateStartsWithCondition(QUEST_SLOT, "killed")),
ConversationStates.ATTENDING,
null,
new SayTimeRemainingAction(QUEST_SLOT, 1, WEEK_IN_MINUTES, "These #creatures didn't return so far and we could see some lovely places all over. Please return in"));
npc.add(ConversationStates.ATTENDING,
ConversationPhrases.QUEST_MESSAGES,
new AndCondition(new QuestStateStartsWithCondition(QUEST_SLOT,"killed"),
new TimePassedCondition(QUEST_SLOT, 1, WEEK_IN_MINUTES)),
ConversationStates.QUEST_OFFERED,
"Those creatures returned after the last time you helped us. May you help us again please?",
"Those #creatures returned after the last time you helped us. May you help us again please?",
null);
npc.add(ConversationStates.ATTENDING,
ConversationPhrases.QUEST_MESSAGES,
new AndCondition(new QuestStateStartsWithCondition(QUEST_SLOT,"killed"),
new NotCondition(new TimePassedCondition(QUEST_SLOT, 1, WEEK_IN_MINUTES))),
ConversationStates.ATTENDING,
"These creatures didn't return so far and we could see some lovely places all over.",
null);
final Map<String, Pair<Integer, Integer>> toKill = new TreeMap<String, Pair<Integer, Integer>>();
@ -135,7 +154,7 @@ public class CleanAthorsUnderground extends AbstractQuest {
ConversationPhrases.NO_MESSAGES,
null,
ConversationStates.ATTENDING,
"Oh nevermind. We'll go on sunbathing then. Not that we aren't tired of it...",
"Oh never mind. We'll go on sunbathing then. Not that we aren't tired of it...",
new SetQuestAction(QUEST_SLOT, "rejected"));
}
@ -165,7 +184,7 @@ public class CleanAthorsUnderground extends AbstractQuest {
new QuestInStateCondition(QUEST_SLOT, 0, "start"),
new KilledForQuestCondition(QUEST_SLOT, 1)),
ConversationStates.ATTENDING,
"Brilliant! You killed some of these ugly creatures as I see! Hopefully they'll not return that fast or we will still not have the chance to explore some places." + "Please take these greater potions as a reward for your help.",
"Brilliant! You killed some of these ugly creatures as I see! Hopefully they'll not return that fast or we will still not have the chance to explore some places." + " Please take these greater potions as a reward for your help.",
new MultipleActions(actions));
npc.add(ConversationStates.ATTENDING,
@ -174,7 +193,7 @@ public class CleanAthorsUnderground extends AbstractQuest {
new QuestInStateCondition(QUEST_SLOT, 0, "start"),
new NotCondition(new KilledForQuestCondition(QUEST_SLOT, 1))),
ConversationStates.ATTENDING,
"Please free these lovely places on Athor from ugly creatures!",
"Please free these lovely places on Athor from ugly #creatures!",
null);
}
@ -183,7 +202,7 @@ public class CleanAthorsUnderground extends AbstractQuest {
super.addToWorld();
fillQuestInfo(
"Clean Athors underground",
"John and his wife Jane want to explore Athor underground on their vacation but unfortunetely they can't.",
"John and his wife Jane want to explore Athor underground on their vacation but unfortunately they can't.",
false);
step_1();
step_2();
@ -197,11 +216,11 @@ public class CleanAthorsUnderground extends AbstractQuest {
return res;
}
if (!isCompleted(player)) {
res.add("I must kill one of each creature of Athor underground for helping John and Jane having a nice vacation!");
res.add("I must kill one of each creature of the Athor underground to help John and Jane have a nice vacation!");
} else if(isRepeatable(player)){
res.add("It's a long time ago that I visited John and asked if he was able to explore some places on Athor. Maybe he needs my help again.");
res.add("It's a long time ago that I visited John and Jane on Athor island. Maybe they need my help again now.");
} else {
res.add("I've killed some creatures and John and Jane can finally enjoy their vacation!");
res.add("I've killed some creatures and John and Jane can finally enjoy their vacation! They will not need my help again during the next days.");
}
return res;
}

View file

@ -13,13 +13,20 @@
package games.stendhal.server.maps.quests;
import games.stendhal.common.MathHelper;
import games.stendhal.common.Rand;
import games.stendhal.common.grammar.Grammar;
import games.stendhal.common.parser.Sentence;
import games.stendhal.server.core.engine.SingletonRepository;
import games.stendhal.server.entity.item.StackableItem;
import games.stendhal.server.entity.npc.ChatAction;
import games.stendhal.server.entity.npc.ConversationPhrases;
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.EquipItemAction;
import games.stendhal.server.entity.npc.action.IncreaseXPAction;
import games.stendhal.server.entity.npc.action.IncrementQuestAction;
import games.stendhal.server.entity.npc.action.MultipleActions;
import games.stendhal.server.entity.npc.action.SayTimeRemainingAction;
import games.stendhal.server.entity.npc.action.SetQuestAction;
import games.stendhal.server.entity.npc.action.SetQuestToTimeStampAction;
import games.stendhal.server.entity.npc.action.StartRecordingKillsAction;
@ -55,7 +62,7 @@ import marauroa.common.Pair;
*
* REWARD:<ul>
* <li> 15000 XP
* <li> 5 soup
* <li> 1-5 soup
* <li> some karma
* </ul>
*
@ -95,7 +102,7 @@ public class KillMonks extends AbstractQuest {
ConversationPhrases.QUEST_MESSAGES,
new QuestNotStartedCondition(QUEST_SLOT),
ConversationStates.QUEST_OFFERED,
"My lovely wife died when she went to Wofol for getting us some freshmade pizza by Kroip. Some monks stepped into her way and she had no chance. Now I want revenge! May you help me?",
"My lovely wife was killed when she went to Wo'fol to order some freshmade pizza by Kroip. Some monks stepped into her way and she had no chance. Now I want revenge! May you help me?",
null);
npc.add(ConversationStates.ATTENDING,
@ -107,16 +114,15 @@ public class KillMonks extends AbstractQuest {
null);
npc.add(ConversationStates.ATTENDING,
ConversationPhrases.QUEST_MESSAGES,
new AndCondition(new QuestStateStartsWithCondition(QUEST_SLOT,"killed"),
new NotCondition(new TimePassedCondition(QUEST_SLOT, 1, WEEK_IN_MINUTES*2))),
ConversationPhrases.QUEST_MESSAGES,
new AndCondition(new NotCondition(new TimePassedCondition(QUEST_SLOT, 1, WEEK_IN_MINUTES*2)), new QuestStateStartsWithCondition(QUEST_SLOT, "killed")),
ConversationStates.ATTENDING,
"These monks learned their lesson for now but I could need your help again in some days.",
null);
null,
new SayTimeRemainingAction(QUEST_SLOT, 1, WEEK_IN_MINUTES*2, "These monks learned their lesson for now but I could need your help again in"));
final List<ChatAction> actions = new LinkedList<ChatAction>();
actions.add(new SetQuestAction(QUEST_SLOT, "start"));
actions.add(new SetQuestAction(QUEST_SLOT, 0, "start"));
actions.add(new StartRecordingKillsAction(QUEST_SLOT, 1, creaturestokill));
@ -124,7 +130,7 @@ public class KillMonks extends AbstractQuest {
ConversationPhrases.YES_MESSAGES,
null,
ConversationStates.ATTENDING,
"Thank you! Also in the name of my beloved wife! Please kill 25 monks and 25 darkmonks.",
"Thank you! Please kill 25 monks and 25 darkmonks in the name of my beloved wife.",
new MultipleActions(actions));
npc.add(ConversationStates.QUEST_OFFERED,
@ -132,7 +138,7 @@ public class KillMonks extends AbstractQuest {
null,
ConversationStates.ATTENDING,
"That is a pity... Maybe you'll change your mind soon and help a sad man then.",
new SetQuestAction(QUEST_SLOT, "rejected"));
new SetQuestAction(QUEST_SLOT, 0, "rejected"));
}
private void step_2() {
@ -142,13 +148,26 @@ public class KillMonks extends AbstractQuest {
private void step_3() {
final SpeakerNPC npc = npcs.get("Andy");
ChatAction addRandomNumberOfItemsAction = new ChatAction() {
public void fire(final Player player, final Sentence sentence, final EventRaiser npc) {
//add random number of soups
final StackableItem soup = (StackableItem) SingletonRepository.getEntityManager()
.getItem("soup");
int amount;
// between 1 and 5 soup
amount = Rand.rand(4) + 1;
soup.setQuantity(amount);
player.equipOrPutOnGround(soup);
}
};
final List<ChatAction> actions = new LinkedList<ChatAction>();
actions.add(new EquipItemAction("soup", 5));
actions.add(addRandomNumberOfItemsAction);
actions.add(new IncreaseXPAction(15000));
actions.add(new SetQuestAction(QUEST_SLOT, "killed;1"));
actions.add(new SetQuestAction(QUEST_SLOT, 0, "killed"));
actions.add(new SetQuestToTimeStampAction(QUEST_SLOT, 1));
actions.add(new IncrementQuestAction(QUEST_SLOT,2,1));
LinkedList<String> triggers = new LinkedList<String>();
triggers.addAll(ConversationPhrases.FINISH_MESSAGES);
@ -159,7 +178,7 @@ public class KillMonks extends AbstractQuest {
new QuestInStateCondition(QUEST_SLOT, 0, "start"),
new KilledForQuestCondition(QUEST_SLOT, 1)),
ConversationStates.ATTENDING,
"Thank you so much! Now I can sleep a bit better.",
"Thank you so much! Now I can sleep a bit better. Please take some soup.",
new MultipleActions(actions));
npc.add(ConversationStates.ATTENDING,
@ -177,7 +196,7 @@ public class KillMonks extends AbstractQuest {
super.addToWorld();
fillQuestInfo(
"Kill Monks",
"Andy lost his wife by monks, now he wants revenge on them.",
"Andy's wife was killed by monks, now he wants revenge on them.",
false);
step_1();
step_2();
@ -191,12 +210,17 @@ public class KillMonks extends AbstractQuest {
return res;
}
if (!isCompleted(player)) {
res.add("I must kill 25 monks and 25 darkmonks to help Andy reaching his goal of taking revenge.");
res.add("I must kill 25 monks and 25 darkmonks to get revenge for Andy's wife.");
} else if(isRepeatable(player)){
res.add("Now, after more than two weeks, I should take a look after Andy again. Maybe he needs my help");
res.add("Now, after more than two weeks, I should check on Andy again. Maybe he needs my help!");
} else {
res.add("I've killed some monks and Andy finally can sleep a bit better!");
}
int repetitions = player.getNumberOfRepetitions(getSlotName(), 2);
if (repetitions > 0) {
res.add("I have taken revenge for Andy "
+ Grammar.quantityplnoun(repetitions, "time") + " now.");
}
return res;
}

View file

@ -22,7 +22,7 @@ Some of these people are NPC, they will give you tasks to accomplish and hints t
</security>
<resources>
<j2se href="http://java.sun.com/products/autodl/j2se" version="1.5+" /> <!-- max-heap-size="120" -->
<jar href="http://arianne.sourceforge.net/jws/stendhal-starter-0.94.5.jar" download="eager" main="true" />
<jar href="http://arianne.sourceforge.net/jws/stendhal-starter-0.95.jar" download="eager" main="true" />
</resources>
<application-desc/>
</jnlp>

View file

@ -1,6 +1,5 @@
/* $Id$ */
/***************************************************************************
* (C) Copyright 2003-2010 - Stendhal *
* (C) Copyright 2003-2011 - Stendhal *
***************************************************************************
***************************************************************************
* *
@ -71,7 +70,8 @@ public class HttpClientTest {
/**
* Tests for fetchFile
* @throws IOException
*
* @throws IOException in case of an input/output error
*/
@Test
public void testFetchFile() throws IOException {