Code Search for Developers
 
 
  

GameData.java from Magellan-Client at Krugle


Show GameData.java syntax highlighted

/*
 *  Copyright (C) 2000-2004 Roger Butenuth, Andreas Gampe,
 *                          Stefan Goetz, Sebastian Pappert,
 *                          Klaas Prause, Enno Rehling,
 *                          Sebastian Tusk, Ulrich Kuester,
 *                          Ilja Pavkovic
 *
 * This file is part of the Eressea Java Code Base, see the
 * file LICENSING for the licensing information applying to
 * this file.
 *
 */

package com.eressea;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

import com.eressea.cr.Loader;
import com.eressea.gamebinding.GameSpecificStuff;
import com.eressea.io.file.FileType;
import com.eressea.rules.Date;
import com.eressea.rules.EresseaDate;
import com.eressea.rules.MessageType;
import com.eressea.rules.RegionType;
import com.eressea.util.CollectionFactory;
import com.eressea.util.IDBaseConverter;
import com.eressea.util.Locales;
import com.eressea.util.Regions;
import com.eressea.util.Translations;
import com.eressea.util.logging.Logger;

/**
 * This is the central class for collecting all the data representing one computer report.
 * 
 * <p>
 * The maps units, regions and so on are declared as abstract methods and the getX and addX provide
 * access to them. This allows for subclasses that implicitely represent only a certain part of
 * the game data by declaring certain maps as <tt>null</tt> and returning <tt>null</tt> on the
 * corresponding getX() methods. This concept has so far not been applied and you usually operate
 * on the <tt>CompleteData</tt> subclass.
 * </p>
 */
public abstract class GameData implements Cloneable {
	private static final Logger log = Logger.getInstance(GameData.class);

	/** Game specific and usually fixed data (like races etc.). */
	public final Rules rules;

	/** The name of the game. */
	public final String name;
	
	/** encoding */
	public String encoding = FileType.DEFAULT_ENCODING;

	/**
	 * TODO: Comment for <code>ownerFaction</code>
	 */
	public EntityID ownerFaction;
	/**
	 * TODO: Comment for <code>recommendedOffset</code>
	 */
	public String recommendedOffset;
	
	/**
	 * The current TempUnit-ID. This means, if a new TempUnit is created, it's suggested ID is
	 * usually curTempID and if this suggestion is accepted by the user (which means, that a
	 * TempUnit with this id was created) curTempID is increased. A value of -1 indicates, that
	 * the variable is uninitialized and a value of 0 that the old system shall be used (which
	 * means, that the suggested temp id shall be calculated out of the id of the parent unit of
	 * the tempunit).
	 */
	protected int curTempID = -1;

	/**
	 * This method sets the current temp id with respect to the possible  max value of the current
	 * base. The value also has to be >= -1
	 *
	 * @param newTempID temp id
	 */
	public void setCurTempID(int newTempID) {
		curTempID = Math.max(-1, Math.min(newTempID, IDBaseConverter.getMaxId(this.base)));
	}

	/**
	 * TODO: DOCUMENT ME!
	 *
	 * @param s TODO: DOCUMENT ME!
	 */
	public void setCurTempID(String s) {
		setCurTempID("".equals(s) ? 0 : IDBaseConverter.parse(s,base));
	}

	/**
	 * This method sets the current temp id.
	 *
	 * @return TODO: DOCUMENT ME!
	 */
	public int getCurTempID() {
		return curTempID;
	}

	/**
	 * The current file attached to the game data. If it is null, the  save as dialog shall be
	 * opened.
	 */
	public FileType filetype = null;

	/**
	 * The 'round' this game data belongs to. Note that this imposes a restriction on how
	 * fine-grained date information can be applied to game data or certain parts of it. This will
	 * probably have to be changed the one or the other way.
	 */
	protected Date date = null;

	/** The 'mail' connection this game data belongs to. This may  be null */
	public String mailTo = null;

	/** The 'mail' subject for this game data. This may  be null */
	public String mailSubject = null;

	/**
	 * A collection of all units. The keys are <tt>Integer</tt> objects containg the unit's ids.
	 * The values consist of objects of class <tt>Unit</tt>. TEMP units are not included, they are
	 * only stored in the unit collection of their parents and their regions and in the tempUnits
	 * map.
	 *
	 * @return returns the units map
	 */
	public abstract Map units();

	/**
	 * A collection of tempUnits. The keys are <tt>Integer</tt> objects containg the unit's ids.
	 * The values consist of objects of class <tt>TempUnit</tt>.
	 *
	 * @return returns the tempunits map
	 */
	public abstract Map tempUnits();

	/**
	 * All regions in this game data. The keys are <tt>Coordinate</tt> objects containg the id of
	 * each region. The values consist of objects of class <tt>Region</tt>.
	 *
	 * @return returns the regions map
	 */
	public abstract Map regions();

	/**
	 * All factions in this game data. The keys are <tt>Integer</tt> objects containg the id of
	 * each faction. The values consist of objects of class <tt>Faction</tt>. One of these
	 * factions can be referenced by the ownerFaction attribute.
	 *
	 * @return returns the factions map
	 */
	public abstract Map factions();

	/**
	 * All buildings in this game data. The keys are <tt>Integer</tt> objects containg the id of
	 * each building. The values consist of objects of class <tt>Building</tt>.
	 *
	 * @return returns the buildings map
	 */
	public abstract Map buildings();

	/**
	 * All ships in this game data. The keys are <tt>Integer</tt> objects containg the id of each
	 * ship. The values consist of objects of class <tt>Ship</tt>.
	 *
	 * @return returns the ships map
	 */
	public abstract Map ships();

	/**
	 * All message types in this game data. The keys are <tt>Integer</tt> objects containg the id
	 * of each message type. The values consist of <tt>MessageType</tt> objects.
	 *
	 * @return returns the messageType map
	 */
	public abstract Map msgTypes();

	/**
	 * All magic spells in this game data. The keys are <tt>Integer</tt> objects containg the id of
	 * each spell. The values consist of objects of class <tt>Spell</tt>.
	 *
	 * @return returns the spells map
	 */
	public abstract Map spells();

	/**
	 * All potions in this game data. The keys are <tt>Integer</tt> objects containg the id of each
	 * potion. The values consist of objects of class <tt>Potion</tt>.
	 *
	 * @return returns the potions map
	 */
	public abstract Map potions();

	/**
	 * All islands in this game data. The keys are <tt>Integer</tt> objects containing the id of
	 * each island. The values consist of objects of class <tt>Island</tt>.
	 *
	 * @return returns the islands map
	 */
	public abstract Map islands();

	/**
	 * All HotSpots existing for this game data. Hot spots are used to quickly access regions of
	 * interest on the map. The keys are Integer representations of the hot spot id, the values
	 * are Coordinate objects.
	 *
	 * @return TODO: DOCUMENT ME!
	 */
	public abstract Map hotSpots();

	/**
	 * Represents the table of translations from the report.
	 *
	 * @return TODO: DOCUMENT ME!
	 */
	public abstract Map translations();
	
	/**
	 * is set to true, if while proceeding some
	 * functions (e.g. CRParse) and we are running
	 * out of memory...
	 * data may be corrupted or empty then
	 */
	public boolean outOfMemory = false;

	/**
	 * Creates a new GameData object.
	 *
	 * @param _rules TODO: DOCUMENT ME!
	 */
	public GameData(Rules _rules) {
		this(_rules, "default");
	}

	/**
	 * Creates a new GameData object.
	 *
	 * @param _rules TODO: DOCUMENT ME!
	 * @param _name TODO: DOCUMENT ME!
	 *
	 * @throws NullPointerException TODO: DOCUMENT ME!
	 */
	public GameData(Rules _rules, String _name) {
		if(_rules == null) {
			throw new NullPointerException();
		}

		rules = _rules;
		name = _name;
	}

	/**
	 * Retrieve a building from buildings() by id.
	 *
	 * @param id the id of the building to be retrieved.
	 *
	 * @return an instance of class <tt>Building</tt> or <tt>null</tt> if there is no building with
	 * 		   the specified id or if buildings() is <tt>null</tt>.
	 */
	public Building getBuilding(ID id) {
		return (buildings() == null) ? null : (Building) buildings().get(id);
	}

	/**
	 * Retrieve a ship from ships() by id.
	 *
	 * @param id the id of the ship to be retrieved.
	 *
	 * @return an instance of class <tt>Ship</tt> or <tt>null</tt> if there is no ship with the
	 * 		   specified id or if ships() is <tt>null</tt>.
	 */
	public Ship getShip(ID id) {
		return (ships() == null) ? null : (Ship) ships().get(id);
	}

	/**
	 * Retrieve a faction from factions() by id.
	 *
	 * @param id the id of the faction to be retrieved.
	 *
	 * @return an instance of class <tt>Faction</tt> or <tt>null</tt> if there is no faction with
	 * 		   the specified id or if factions() is <tt>null</tt>.
	 */
	public Faction getFaction(ID id) {
		return (factions() == null) ? null : (Faction) factions().get(id);
	}

	/**
	 * Retrieve a unit from units() by id.
	 *
	 * @param id the id of the unit to be retrieved.
	 *
	 * @return an instance of class <tt>Unit</tt> or <tt>null</tt> if there is no unit with the
	 * 		   specified id or if units() is <tt>null</tt>.
	 */
	public Unit getUnit(ID id) {
		return (units() == null) ? null : (Unit) units().get(id);
	}

	/**
	 * Retrieve a region from regions() by id.
	 *
	 * @param c region coordinate
	 *
	 * @return an instance of class <tt>Region</tt> or <tt>null</tt> if there is no region with the
	 * 		   specified coordinates or if regions() is <tt>null</tt>.
	 */
	public Region getRegion(CoordinateID c) {
		CoordinateID id = new CoordinateID(c);
		return (regions() == null) ? null : (Region) regions().get(id);
	}

	/**
	 * Retrieve a message type from msgTypes() by id.
	 *
	 * @param id the id of the message type to be retrieved.
	 *
	 * @return an instance of class <tt>MessageType</tt> or <tt>null</tt> if there is no message
	 * 		   type with the specified id or if msgTypes() is <tt>null</tt>.
	 */
	public MessageType getMsgType(ID id) {
		return (msgTypes() == null) ? null : (MessageType) msgTypes().get(id);
	}

	/**
	 * Retrieve a spell from spells() by id.
	 *
	 * @param id the id of the spell to be retrieved.
	 *
	 * @return an instance of class <tt>Spell</tt> or <tt>null</tt> if there is no spell with the
	 * 		   specified id or if spells() is <tt>null</tt>.
	 */
	public Spell getSpell(ID id) {
		return (spells() == null) ? null : (Spell) spells().get(id);
	}
	
	/**
	 * Retrieve a spell from spells() by Name.
	 * used for orderReader / completer
	 * 
	 * @param id the name of the spell to be retrieved.
	 *
	 * @return an instance of class <tt>Spell</tt> or <tt>null</tt> if there is no spell with the
	 * 		   specified id or if spells() is <tt>null</tt>.
	 */
	public Spell getSpell(String spellName) {
		if (spells()==null || spells().size()==0){
			return null;
		}
		for (Iterator iter = spells().values().iterator();iter.hasNext();){
			Spell spell = (Spell)iter.next();
			if (spell.getName().equalsIgnoreCase(spellName)){
				return spell;
			}
		}
		return null;
	}
	

	/**
	 * Retrieve a potion from potions() by id.
	 *
	 * @param id the id of the potion to be retrieved.
	 *
	 * @return an instance of class <tt>Potion</tt> or <tt>null</tt> if there is no potion with the
	 * 		   specified id or if potions() is <tt>null</tt>.
	 */
	public Potion getPotion(ID id) {
		return (potions() == null) ? null : (Potion) potions().get(id);
	}

	/**
	 * Retrieve a island from islands() by id.
	 *
	 * @param id the id of the island to be retrieved.
	 *
	 * @return an instance of class <tt>Island</tt> or <tt>null</tt> if there is no island with the
	 * 		   specified id or if islands() is <tt>null</tt>.
	 */
	public Island getIsland(ID id) {
		return (islands() == null) ? null : (Island) islands().get(id);
	}

	/**
	 * Add a faction to the specified game data. If factions() is <tt>null</tt>, this method has no
	 * effect.
	 *
	 * @param f the faction to be added.
	 */
	public void addFaction(Faction f) {
		if(factions() != null) {
			factions().put(f.getID(), f);
		}
	}

	/**
	 * Add a unit to the specified game data. If units() is <tt>null</tt>, this method has no
	 * effect.
	 *
	 * @param u the unit to be added.
	 */
	public void addUnit(Unit u) {
		if(units() != null) {
			units().put(u.getID(), u);
		}
	}

	/**
	 * Add a region to the specified game data. If regions() is <tt>null</tt>, this method has no
	 * effect.
	 *
	 * @param r the region to be added.
	 */
	public void addRegion(Region r) {
		if(regions() != null) {
			regions().put(r.getID(), r);
		}
	}

	/**
	 * Add a ship to the specified game data. If ships() is <tt>null</tt>, this method has no
	 * effect.
	 *
	 * @param s the ship to be added.
	 */
	public void addShip(Ship s) {
		if(ships() != null) {
			ships().put(s.getID(), s);
		}
	}

	/**
	 * Add a building to the specified game data. If buildings() is <tt>null</tt>, this method has
	 * no effect.
	 *
	 * @param b the building to be added.
	 */
	public void addBuilding(Building b) {
		if(buildings() != null) {
			buildings().put(b.getID(), b);
		}
	}

	/**
	 * Add a message type to the specified game data. If msgTypes() is <tt>null</tt>, this method
	 * has no effect.
	 *
	 * @param type the message type to be added.
	 */
	public void addMsgType(MessageType type) {
		if(msgTypes() != null) {
			msgTypes().put(type.getID(), type);
		}
	}

	/**
	 * Add a spell to the specified game data. If spells() is <tt>null</tt>, this method has no
	 * effect.
	 *
	 * @param s the spells to be added.
	 */
	public void addSpell(Spell s) {
		if(spells() != null) {
			spells().put(s.getID(), s);
		}
	}

	/**
	 * Add a pption to the specified game data. If potions() is <tt>null</tt>, this method has no
	 * effect.
	 *
	 * @param p the potion to be added.
	 */
	public void addPotion(Potion p) {
		if(potions() != null) {
			potions().put(p.getID(), p);
		}
	}

	/**
	 * Add an island to the specified game data. If islands() is <tt>null</tt>, this method has no
	 * effect.
	 *
	 * @param i the island to be added.
	 */
	public void addIsland(Island i) {
		if(islands() != null) {
			islands().put(i.getID(), i);
		}
	}

	/**
	 * Returns a map selected regions.
	 *
	 */
	public abstract Map getSelectedRegionCoordinates();

	/**
	 * set a collection of selected regions.
	 *
	 * @param regions the Map of coordinates of selected regions
	 */
	public abstract void setSelectedRegionCoordinates(Map regions);

	/**
	 * Add or set a hot spot to the specified game data. If hotSpots() is <tt>null</tt>, this
	 * method has no effect.
	 *
	 * @param h the hot spot to be added.
	 */
	public void setHotSpot(HotSpot h) {
		if(hotSpots() != null) {
			hotSpots().put(h.getID(), h);
		}
	}

	/**
	 * Retrieve a hot spot from hotSpots() by its id.
	 *
	 * @param id the id of the hot spot to be retrieved.
	 *
	 * @return an instance of class <tt>HotSpot</tt> or <tt>null</tt> if there is no hot spot with
	 * 		   the specified id or if hotSpots() is <tt>null</tt>.
	 */
	public HotSpot getHotSpot(ID id) {
		return (hotSpots() == null) ? null : (HotSpot) hotSpots().get(id);
	}

	/**
	 * Remove a hot spot from hotSpots() by its id.
	 *
	 * @param id the id of the hot spot to be removed.
	 */
	public void removeHotSpot(ID id) {
		if(hotSpots() != null) {
			hotSpots().remove(id);
		}
	}

	/**
	 * Puts a translation into the translation table.
	 *
	 * @param from a language independent key.
	 * @param to the language dependent translation of key.
	 */
	public void addTranslation(String from, String to) {
		if(translations() != null) {
			translations().put(from, to);

			if(rules != null) {
				// dynamically add translation key to rules to access object by name
				rules.changeName(from, to);
			}
		}
	}

    /**
     * Retrieve a translation from translations().
     *
     * @param key the key of the translation to be retrieved.
     *
     * @return an instance of class <tt>String</tt>. If no translation could be found, the name of the object is returned.
     */    
    public String getTranslation(NamedObject key) {
        return key == null ? null : getTranslation(key.getName());
    }
    
	/**
	 * Retrieve a translation from translations().
	 *
     * @param key the key of the translation to be retrieved.
	 *
	 * @return an instance of class <tt>String</tt>. If no translation could be found, the key is
	 * 		   returned.
	 */
	public String getTranslation(String key) {
		String retVal = (key == null || translations() == null) ? null : (String) translations().get(key);

        return retVal != null ? retVal : key;
	}

	/**
	 * Set a date, or a 'round', for this game data.
	 *
	 * @param d the new date.
	 */
	public void setDate(Date d) {
		date = d;
	}

	/**
	 * Get the date associated with this game data.
	 *
	 * @return rules.Date object
	 */
	public Date getDate() {
		return date;
	}

	/**
	 * The base (radix) in which ids are interpreted. The default value is 10. Note that all
	 * internal and cr representation is always decimal.
	 */
	public int base = 10;

	/**
	 * Indicates whether in this report skill points are to be expected or whether they are
	 * meaningful, respecitively.
	 */
	public boolean noSkillPoints = false;

	// TODO: clean up
    //////	deleted by stm (2006-10-20) 
//	/**
//	 * Sets the region at origin as the map origin. (e.g. an origin of (1,0,0) moves all regions in
//	 * level 0 one step to the west using eressea coordinates)
//	 *
//	 * @param origin translation vector as coordinate object
//	 */
//	public abstract void placeOrigin(CoordinateID origin);
//
//		// It can be assumed safely that a region's coordinate and the
//		// key in the regions map are the same object.
//		for(Iterator iter = regions().keySet().iterator(); iter.hasNext();) {
//			Coordinate coord = (Coordinate) iter.next();
//
//			if(coord.z == origin.z) {
//				coord.x -= origin.x;
//				coord.y -= origin.y;
//			}
//		}
//
//		// since the coordinate is the hash key, the modified
//		// coordinates produce invalid hash codes in all maps
//		// so everything has to be rehashed. Unfortunately, the
//		// regions map has to be copied two times.
//		Map r = CollectionFactory.createOrderedHashtable(regions());
//		regions().clear();
//		regions().putAll(r);
//
//		for(Iterator iter = islands().values().iterator(); iter.hasNext();) {
//			Island i = (Island) iter.next();
//			i.invalidateRegions();
//		}
//
//		// now we must change the messages because they use string representations
//		// of coordinates
//		// all factions
//		for(Iterator iter = factions().values().iterator(); iter.hasNext();) {
//			Faction f = (Faction) iter.next();
//
//			// all messages
//			if(f.messages != null) {
//				for(Iterator msgIter = f.messages.iterator(); msgIter.hasNext();) {
//					Message msg = (Message) msgIter.next();
//
//					if(msg.attributes != null) {
//						for(Iterator attrIter = msg.attributes.keySet().iterator();
//								attrIter.hasNext();) {
//							Object key = attrIter.next();
//							String strCoord = (String) msg.attributes.get(key);
//							Coordinate coord = Coordinate.parse(strCoord, ",");
//
//							if((coord != null) && (coord.z == origin.z)) {
//								coord.x -= origin.x;
//								coord.y -= origin.y;
//								msg.attributes.put(key, coord.toString(","));
//							} else {
//								coord = Coordinate.parse(strCoord, " ");
//
//								if((coord != null) && (coord.z == origin.z)) {
//									coord.x -= origin.x;
//									coord.y -= origin.y;
//									msg.attributes.put(key, coord.toString(" ", true));
//								}
//							}
//						}
//					}
//				}
//			}
//
//			// change battle IDs
//			if(f.battles != null) {
//				for(Iterator battles = f.battles.iterator(); battles.hasNext();) {
//					Battle b = (Battle) battles.next();
//
//					// currently the coordinate can overwritten, it
//					// does not serve as key in any map
//					Coordinate newCoord = (Coordinate) b.getID();
//
//					// we dont need to copy the coordinate as they are mutable
//					newCoord.x -= origin.x;
//					newCoord.y -= origin.y;
//				}
//			}
//		}
//	}


	/**
	 * Sets the valid locale for this report. Currently, this is only used to remember this setting
	 * and write it back into the cr.
	 */
	public abstract void setLocale(Locale l);

	/**
	 * Returns the locale of this report. Currently, this is only used to remember this setting and
	 * write it back into the cr.
	 *
	 * @return TODO: DOCUMENT ME!
	 */
	public abstract Locale getLocale();

	/**
	 * Merges the specified dataset with this dataset.
	 *
	 * @param gd1 the first game data object for merging
	 * @param gd2 the second game data object for merging
	 *
	 * @return the new merged game data object
	 *
	 * @throws IllegalArgumentException if first and second game data object are from different
	 * 		   game types.
	 */
	public static GameData merge(GameData gd1, GameData gd2) {
		// make sure, the game types are the same.
		if(!gd1.name.equalsIgnoreCase(gd2.name)) {
			throw new IllegalArgumentException("GameData.merge(): Can't merge different game types. (" +
											   gd1.name + " via " + gd2.name + ")");
		}

		// make sure that a date object is available
		if(gd1.getDate() == null) {
			gd1.setDate(new EresseaDate(0));
		}

		if(gd2.getDate() == null) {
			gd2.setDate(new EresseaDate(0));
		}

		if(gd1.getDate().compareTo(gd2.getDate()) > 0) {
			return mergeIt(gd2, gd1);
		} else {
			return mergeIt(gd1, gd2);
		}
	}

	/**
	 * Merges the two game data containers yielding a third one. By convention, olderGD must not be
	 * newer than newerGD. The resulting game data container inherits the rules and name from
	 * <b>newerGD</b>.
	 *
	 * @param olderGD A GaemData object, must be the newer one of the two
	 * @param newerGD The older GameData object.
	 *
	 * @return the merged GameData
	 */
	private static GameData mergeIt(GameData olderGD, GameData newerGD) {
		// 2002.02.20 pavkovic: the newer rules are in GameData gd2. So we take
		// them for the new GameData
		// FIXME(pavkovic) rules should be loaded instead of just used in this situation
		GameData resultGD = new CompleteData(newerGD.rules, newerGD.name);

		// DATE
		EresseaDate date = new EresseaDate(newerGD.getDate().getDate());
		date.setEpoch(((EresseaDate) newerGD.getDate()).getEpoch());
		resultGD.setDate(date);

	    String oldEncoding = olderGD.encoding;
	    String newEncoding = newerGD.encoding;
	    
	    log.info("Old Encoding: "+oldEncoding);
	    log.info("New Encoding: "+newEncoding);
	    
	    if (oldEncoding != null && newEncoding != null) {
	      if (oldEncoding.equalsIgnoreCase(newEncoding)) {
	        // do nothing
	        log.info("Do nothing");
	        resultGD.encoding = oldEncoding;
	      } else if (oldEncoding.equalsIgnoreCase(FileType.UTF_8) || newEncoding.equalsIgnoreCase(FileType.UTF_8)) {
	        // if one of the reports has UTF-8 Encoding, we use it always.
	        log.info("Set UTF-8 because one report match");
	        resultGD.encoding = FileType.UTF_8;
	      } else {
	        // okay, we have differnt encodings, but none of them is UTF-8 - what now?
	        log.info("Encoding does not match ("+oldEncoding+" vs. "+newEncoding+"), using new encoding");
	        resultGD.encoding = newEncoding;
	      }
	    } else {
	      // okay, this should never happen (no encoding in the reports)
	      // so, we set the default encoding
	      log.info("Set UTF-8 as default");
	      resultGD.encoding = FileType.UTF_8;
	    }
	    
	    log.info("Result: "+resultGD.encoding);
		
		boolean sameRound = olderGD.getDate().equals(newerGD.getDate());

		// MAIL TO, MAIL SUBJECT
		if(newerGD.mailTo != null) {
			resultGD.mailTo = newerGD.mailTo;
		} else {
			resultGD.mailTo = olderGD.mailTo;
		}

		if(newerGD.mailSubject != null) {
			resultGD.mailSubject = newerGD.mailSubject;
		} else {
			resultGD.mailSubject = olderGD.mailSubject;
		}

		// BASE
		if(newerGD.base != 0) {
			resultGD.base = newerGD.base;
		} else {
			resultGD.base = olderGD.base;
		}
		
		/**
		 * 
		 * Tracking an Bug
		 * warn, if we do not have 36 with eressea or vinyambar
		 * and set it to 36
		 */
		String actGameName = newerGD.name.toLowerCase();
		if ((actGameName.indexOf("eressea")>-1 || actGameName.indexOf("vinyambar")>-1) && (newerGD.base!=36)){
			// this should not happen
			log.warn("BASE ERROR !! merged report could have not base36 !! Changed to base36.");
			newerGD.base = 36;
		}
		
		// NOSKILLPOINTS: the newer report determines the skill point handling
		resultGD.noSkillPoints = newerGD.noSkillPoints;

		// curTempID
		// (it is assured, that at least on of the GameData-objects
		//  contains a default value for curTempID)
		if(newerGD.curTempID != -1) {
			resultGD.curTempID = newerGD.curTempID;
		} else {
			resultGD.curTempID = olderGD.curTempID;
		}

		// LOCALE
		if(newerGD.getLocale() != null) {
			resultGD.setLocale(newerGD.getLocale());
		} else {
			resultGD.setLocale(olderGD.getLocale());
		}

		// MESSAGETYPES
		// simple objects, created and merged in one step
		if(olderGD.msgTypes() != null) {
			for(Iterator iter = olderGD.msgTypes().values().iterator(); iter.hasNext();) {
				MessageType mt = (MessageType) iter.next();
				MessageType newMT = null;

				try {
					newMT = new MessageType((ID) mt.getID().clone());
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}

				MessageType.merge(olderGD, mt, resultGD, newMT);
				resultGD.addMsgType(newMT);
			}
		}

		if(newerGD.msgTypes() != null) {
			for(Iterator iter = newerGD.msgTypes().values().iterator(); iter.hasNext();) {
				MessageType mt = (MessageType) iter.next();
				MessageType newMT = resultGD.getMsgType(mt.getID());

				if(newMT == null) {
					try {
						newMT = new MessageType((ID) mt.getID().clone());
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}

				MessageType.merge(newerGD, mt, resultGD, newMT);
				resultGD.addMsgType(newMT);
			}
		}

		// SPELLS
		// simple objects, created and merged in one step
		if(olderGD.spells() != null) {
			for(Iterator iter = olderGD.spells().values().iterator(); iter.hasNext();) {
				Spell spell = (Spell) iter.next();
				Spell newSpell = null;

				try {
					newSpell = new Spell((ID) spell.getID().clone());
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}

				Spell.merge(olderGD, spell, resultGD, newSpell);
				resultGD.addSpell(newSpell);
			}
		}

		if(newerGD.spells() != null) {
			for(Iterator iter = newerGD.spells().values().iterator(); iter.hasNext();) {
				Spell spell = (Spell) iter.next();
				Spell newSpell = resultGD.getSpell(spell.getID());

				if(newSpell == null) {
					try {
						newSpell = new Spell((ID) spell.getID().clone());
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}

				Spell.merge(newerGD, spell, resultGD, newSpell);
				resultGD.addSpell(newSpell);
			}
		}

		// POTIONS
		// simple objects, created and merged in one step
		if(olderGD.potions() != null) {
			for(Iterator iter = olderGD.potions().values().iterator(); iter.hasNext();) {
				Potion potion = (Potion) iter.next();
				Potion newPotion = null;

				try {
					newPotion = new Potion((ID) potion.getID().clone());
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}

				Potion.merge(olderGD, potion, resultGD, newPotion);
				resultGD.addPotion(newPotion);
			}
		}

		if(newerGD.potions() != null) {
			for(Iterator iter = newerGD.potions().values().iterator(); iter.hasNext();) {
				Potion potion = (Potion) iter.next();
				Potion newPotion = resultGD.getPotion(potion.getID());

				if(newPotion == null) {
					try {
						newPotion = new Potion((ID) potion.getID().clone());
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}

				Potion.merge(newerGD, potion, resultGD, newPotion);
				resultGD.addPotion(newPotion);
			}
		}

		// TRANSLATIONS
		// simple objects, created and merged in one step
		if(resultGD.translations() != null) {
			if(olderGD.translations() != null) {
				resultGD.translations().putAll(olderGD.translations());
			}

			if((newerGD.translations() != null) && olderGD.getLocale().equals(newerGD.getLocale())) {
				resultGD.translations().putAll(newerGD.translations());
			}
		}

		// FIXME (stm): Allies do not get merged correctly. We have to either swap the order here or correct
		// something in the section "// MERGE FACTIONS" below
		// FACTIONS
		if(olderGD.factions() != null) {
			for(Iterator iter = olderGD.factions().values().iterator(); iter.hasNext();) {
				Faction f = (Faction) iter.next();

				try {
					resultGD.addFaction(new Faction((ID) f.getID().clone(), resultGD));
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}
			}
		}

		if(newerGD.factions() != null) {
			for(Iterator iter = newerGD.factions().values().iterator(); iter.hasNext();) {
				Faction f = (Faction) iter.next();

				if(resultGD.getFaction(f.getID()) == null) {
					try {
						resultGD.addFaction(new Faction((ID) f.getID().clone(), resultGD));
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}
			}
		}

		// REGIONS
		// this just adds all the regions to newGD. No content yet.
		if(olderGD.regions() != null) {
			for(Iterator iter = olderGD.regions().values().iterator(); iter.hasNext();) {
				Region r = (Region) iter.next();

				try {
					resultGD.addRegion(new Region((CoordinateID) r.getID().clone(), resultGD));
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}
			}
		}

		if(newerGD.regions() != null) {
			for(Iterator iter = newerGD.regions().values().iterator(); iter.hasNext();) {
				Region r = (Region) iter.next();

				if(resultGD.getRegion((CoordinateID) r.getID()) == null) {
					try {
						resultGD.addRegion(new Region((CoordinateID) r.getID().clone(), resultGD));
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}
			}
		}

		// ISLANDS
		if(olderGD.islands() != null) {
			for(Iterator iter = olderGD.islands().values().iterator(); iter.hasNext();) {
				Island i = (Island) iter.next();

				try {
					resultGD.addIsland(new Island((ID) i.getID().clone(), resultGD));
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}
			}
		}

		if(newerGD.islands() != null) {
			for(Iterator iter = newerGD.islands().values().iterator(); iter.hasNext();) {
				Island i = (Island) iter.next();

				if(olderGD.getIsland(i.getID()) == null) {
					try {
						resultGD.addIsland(new Island((ID) i.getID().clone(), resultGD));
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}
			}
		}

		// HOTSPOTS
		if(olderGD.hotSpots() != null) {
			for(Iterator iter = olderGD.hotSpots().values().iterator(); iter.hasNext();) {
				HotSpot h = (HotSpot) iter.next();

				try {
					resultGD.setHotSpot(new HotSpot((ID) h.getID().clone()));
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}
			}
		}

		if(newerGD.hotSpots() != null) {
			for(Iterator iter = newerGD.hotSpots().values().iterator(); iter.hasNext();) {
				HotSpot h = (HotSpot) iter.next();

				if(resultGD.getHotSpot(h.getID()) == null) {
					try {
						resultGD.setHotSpot(new HotSpot((ID) h.getID().clone()));
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}
			}
		}

		// BUILDINGS
		if(newerGD.buildings() != null) {
			for(Iterator iter = newerGD.buildings().values().iterator(); iter.hasNext();) {
				Building b = (Building) iter.next();

				try {
					resultGD.addBuilding(new Building((ID) b.getID().clone(), resultGD));
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}
			}
		}

		if(olderGD.buildings() != null) {
			// buildings are persistent.
			// Accept old buildings not occuring in the new report
			// only if there are no units in that region
			for(Iterator iter = olderGD.buildings().values().iterator(); iter.hasNext();) {
				Building b = (Building) iter.next();
				Building curBuilding = newerGD.getBuilding(b.getID());

				if(curBuilding == null) {
					// check if the building disappeared because we do
					// not know the region anymore or if it was
					// destroyed
					// FIXME(pavkovic): shouldn't it be Region curRegion = b.getRegion(); ?
					Region curRegion = newerGD.getRegion((CoordinateID) b.getRegion().getID());

					if((curRegion == null) || curRegion.units().isEmpty()) {
						try {
							resultGD.addBuilding(new Building((ID) b.getID().clone(), resultGD));
						} catch(CloneNotSupportedException e) {
							log.error(e);
						}
					} else {
						// we just don't see this region anymore so
						// keep the building
					}
				} else {
					// the building occurs in gd2 so we already
					// included its current version in newGD
				}
			}
		}

		// SHIPS
		if(sameRound && (olderGD.ships() != null)) {
			for(Iterator iter = olderGD.ships().values().iterator(); iter.hasNext();) {
				Ship s = (Ship) iter.next();

				try {
					resultGD.addShip(new Ship((ID) s.getID().clone(), resultGD));
				} catch(CloneNotSupportedException e) {
					log.error(e);
				}
			}
		}

		if(newerGD.ships() != null) {
			for(Iterator iter = newerGD.ships().values().iterator(); iter.hasNext();) {
				Ship s = (Ship) iter.next();

				if(resultGD.getShip(s.getID()) == null) {
					try {
						resultGD.addShip(new Ship((ID) s.getID().clone(), resultGD));
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}
			}
		}

		// UNITS

		/* Note: To gather the information needed for level changes, report one
		 *       is always treated. But in the case of unequal dates only units
		 *       that are also in the second report are added to the new one and
		 *       temp units are ignored. IDs are used for comparism.
		*/
		if(olderGD.units() != null) {
			for(Iterator iter = olderGD.units().values().iterator(); iter.hasNext();) {
				Unit u = (Unit) iter.next();

				if(sameRound || (newerGD.getUnit(u.getID()) != null)) {
					// TODO (stm): Isn't that nonsense? Doesn't it suffice to add the units of the new report
					// if they are not from the same round?
					try {
						resultGD.addUnit(new Unit((ID) u.getID().clone()));
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}
			}
		}

		if(newerGD.units() != null) {
			for(Iterator iter = newerGD.units().values().iterator(); iter.hasNext();) {
				Unit u = (Unit) iter.next();

				if(resultGD.getUnit(u.getID()) == null) {
					try {
						resultGD.addUnit(new Unit((ID) u.getID().clone()));
					} catch(CloneNotSupportedException e) {
						log.error(e);
					}
				}
			}
		}

		// MERGE FACTIONS
		if(olderGD.factions() != null) {
			for(Iterator iter = olderGD.factions().values().iterator(); iter.hasNext();) {
				Faction curFaction = (Faction) iter.next();
				Faction newFaction = resultGD.getFaction(curFaction.getID());

				// first pass
				Faction.merge(olderGD, curFaction, resultGD, newFaction);
			}
		}

		// MERGE REGIONS
		if(olderGD.regions() != null) {
			for(Iterator iter = olderGD.regions().values().iterator(); iter.hasNext();) {
				Region curRegion = (Region) iter.next();
				Region newRegion = resultGD.getRegion((CoordinateID) curRegion.getID());

				// first pass
				Region.merge(olderGD, curRegion, resultGD, newRegion, sameRound);
			}
		}

		// MERGE ISLANDS
		if(olderGD.islands() != null) {
			for(Iterator iter = olderGD.islands().values().iterator(); iter.hasNext();) {
				Island curIsland = (Island) iter.next();
				Island newIsland = resultGD.getIsland(curIsland.getID());

				// first pass
				Island.merge(olderGD, curIsland, resultGD, newIsland);
			}
		}

		// MERGE HOTSPOTS
		if(olderGD.hotSpots() != null) {
			for(Iterator iter = olderGD.hotSpots().values().iterator(); iter.hasNext();) {
				HotSpot curHotSpot = (HotSpot) iter.next();
				HotSpot newHotSpot = resultGD.getHotSpot(curHotSpot.getID());
				// first pass
				HotSpot.merge(olderGD, curHotSpot, resultGD, newHotSpot);
			}
		}

		// MERGE BUILDINGS
		if(olderGD.buildings() != null) {
			for(Iterator iter = olderGD.buildings().values().iterator(); iter.hasNext();) {
				Building curBuilding = (Building) iter.next();
				Building newBuilding = resultGD.getBuilding(curBuilding.getID());

				if(newBuilding != null) {
					// first pass
					Building.merge(olderGD, curBuilding, resultGD, newBuilding);
				}
			}
		}

		// MERGE SHIPS
		if((olderGD.ships() != null)) {
			for(Iterator iter = olderGD.ships().values().iterator(); iter.hasNext();) {
				Ship curShip = (Ship) iter.next();
				Ship newShip = resultGD.getShip(curShip.getID());

				// only merge ships from the "older" game data if they are from the same round
				if (sameRound)
					// first pass
					Ship.merge(olderGD, curShip, resultGD, newShip);
				else
					// TODO (stm 2007-02-19) this is a workaround, we need a nicer solution
					UnitContainer.mergeComments(curShip, newShip);
			}
		}

		// MERGE FACTIONS, SECOND PASS
		// must be done before merging units to keep group information
		if(newerGD.factions() != null) {
			for(Iterator iter = newerGD.factions().values().iterator(); iter.hasNext();) {
				Faction curFaction = (Faction) iter.next();
				Faction newFaction = resultGD.getFaction(curFaction.getID());
				
				// second pass
				Faction.merge(newerGD, curFaction, resultGD, newFaction);
			}
		}
		

		// MERGE UNITS

		/* Note: To gather level change informations all units are used.
		 *       If the dates are equal, a fully merge is done, if not, only the
		 *       skills are retrieved.
		 */
		for(Iterator it = resultGD.units().values().iterator(); it.hasNext(); ) {
			Unit newUnit = (Unit) it.next();

			// find the second first since we may need the temp id
			Unit curUnit2 = newerGD.findUnit(newUnit.getID(), null, null);

			// find a temp ID to gather information out of the temp unit
			ID tempID = null;
			Region newRegion = null;

			if((curUnit2 != null) && !sameRound) { // only use temp ID if reports have different date
				tempID = curUnit2.getTempID();

				if(tempID != null) {
					tempID = UnitID.createUnitID(-((UnitID) tempID).intValue(), newerGD.base);
				}

				newRegion = curUnit2.getRegion();
			}

			Unit curUnit1 = olderGD.findUnit(newUnit.getID(), tempID, newRegion); // now get the unit of the first report

			// first merge step
			if(curUnit1 != null) {
				if(sameRound) { // full merge
					Unit.merge(olderGD, curUnit1, resultGD, newUnit, sameRound);
				} else { // only copy the skills to get change-level base

					if((curUnit2.skills != null) || (curUnit1.getFaction().isPrivileged())) {
						Unit.copySkills(curUnit1, newUnit);
					}
				}
			}

			// second merge step
			if(curUnit2 != null) {
				Unit.merge(newerGD, curUnit2, resultGD, newUnit, sameRound);
			}
		}

		// MERGE REGIONS, SECOND PASS
		if(newerGD.regions() != null) {
			for(Iterator iter = newerGD.regions().values().iterator(); iter.hasNext();) {
				Region curRegion = (Region) iter.next();
				Region newRegion = resultGD.getRegion((CoordinateID) curRegion.getID());
				
				// second pass
				Region.merge(newerGD, curRegion, resultGD, newRegion, true);
			}
		}

		// MERGE ISLANDS, SECOND PASS
		if(newerGD.islands() != null) {
			for(Iterator iter = newerGD.islands().values().iterator(); iter.hasNext();) {
				Island curIsland = (Island) iter.next();
				Island newIsland = resultGD.getIsland(curIsland.getID());

				// second pass
				Island.merge(newerGD, curIsland, resultGD, newIsland);
			}
		}

		// MERGE HOTSPOTS, SECOND PASS
		if(newerGD.hotSpots() != null) {
			for(Iterator iter = newerGD.hotSpots().values().iterator(); iter.hasNext();) {
				HotSpot curHotSpot = (HotSpot) iter.next();
				HotSpot newHotSpot = resultGD.getHotSpot(curHotSpot.getID());
				// second pass
				HotSpot.merge(newerGD, curHotSpot, resultGD, newHotSpot);
			}
		}

		// MERGE BUILDINGS, SECOND PASS
		if(newerGD.buildings() != null) {
			for(Iterator iter = newerGD.buildings().values().iterator(); iter.hasNext();) {
				Building curBuilding = (Building) iter.next();
				Building newBuilding = resultGD.getBuilding(curBuilding.getID());

				if(newBuilding != null) {
					// second pass
					Building.merge(newerGD, curBuilding, resultGD, newBuilding);
				}
			}
		}

		// MERGE SHIPS, SECOND PASS
		if(newerGD.ships() != null) {
			for(Iterator iter = newerGD.ships().values().iterator(); iter.hasNext();) {
				Ship curShip = (Ship) iter.next();
				Ship newShip = resultGD.getShip(curShip.getID());

				// second pass
				Ship.merge(newerGD, curShip, resultGD, newShip);
			}
		}
		
		resultGD.postProcess();
		resultGD.resetToUnchanged();

		return resultGD;
	}

	protected Unit findUnit(ID id, ID tempID, Region newRegion) {
		// search for a temp unit
		if(tempID != null) {
			if(newRegion == null) {
				Iterator it = units().values().iterator();

				while(it.hasNext()) {
					Unit u = (Unit) it.next();
					Unit u2 = u.getTempUnit(tempID);

					if(u2 != null) {
						return u2;
					}
				}
			} else {
				Map m = Regions.getAllNeighbours(regions(), newRegion.getID(), 3, null);

				if(m != null) {
					Iterator it = m.values().iterator();

					while(it.hasNext()) {
						Region r = (Region) it.next();
						Unit u2 = r.getUnit(tempID);

						if(u2 != null) {
							return u2;
						}
					}
				}
			}
		}

		// standard search
		return getUnit(id);
	}

	/**
	 * This function checks if the game data have been manipulated somehow (merge will lead to a
	 * filetype null).
	 *
	 * @param g TODO: DOCUMENT ME!
	 *
	 * @return TODO: DOCUMENT ME!
	 */
	public boolean gameDataChanged(GameData g) {
		if(g.filetype == null) {
			return true;
		}

		for(Iterator iter = g.units().values().iterator(); iter.hasNext();) {
			Unit u = (Unit) iter.next();

			if(u.ordersHaveChanged()) {
				return true;
			}
		}

		return false;
	}

	/**
	 * reset change state of all units to false
	 */
	public void resetToUnchanged() {
		for(Iterator iter = units().values().iterator(); iter.hasNext();) {
			Unit u = (Unit) iter.next();
			u.setOrdersChanged(false);
		}
	}

	/**
	 * returns a clone of the game data (using CRWriter/CRParser  trick encapsulated in Loader)
	 *
	 * @return TODO: DOCUMENT ME!
	 *
	 * @throws CloneNotSupportedException TODO: DOCUMENT ME!
	 */
	public Object clone() throws CloneNotSupportedException {
		return new Loader().cloneGameData(this);
	}

	/**
	 * returns a clone of the game data (using CRWriter/CRParser  trick encapsulated in Loader)
	 * and at the same time translates the origin two <code>newOrigin</code>
	 *
	 * @return TODO: DOCUMENT ME!
	 *
	 * @throws CloneNotSupportedException TODO: DOCUMENT ME!
	 */
	public Object clone(CoordinateID newOrigin) throws CloneNotSupportedException {
		if (newOrigin.x == 0 && newOrigin.y == 0)
			return this.clone();
		else
			return new Loader().cloneGameData(this, newOrigin);
	}

	/**
	 * Provides the encapsulating of game specific stuff
	 *
	 * @return TODO: DOCUMENT ME!
	 */
	public GameSpecificStuff getGameSpecificStuff() {
		return rules.getGameSpecificStuff();
	}

	/** Post processes the game data (if necessary)  once */
	private boolean postProcessed = false;

	/**
	 * TODO: DOCUMENT ME!
	 */
	public void postProcess() {
		if(postProcessed) {
			return;
		}

		// enforce locale to be non-null
		postProcessLocale();

		// attach Regions to Islands
		Island.postProcess(this);

		// remove double messages
		postProcessMessages();

		// do game specific post processing 
		getGameSpecificStuff().postProcess(this);
		
		// TheVoid
		// make it optional
		// postProcessTheVoid();

		postProcessed = true;
	}
	
	/**
	 * scans the regions for missing regions, for regions with
	 * regionType "The Void" or "Leere"
	 * These Regions are not created in the world on the server, but we 
	 * are so near, that we should have some information about it.
	 * So we add these Regions with the special RegionType "Leere"
	 *
	 */
	public void postProcessTheVoid(){
		ArrayList newRegions = new ArrayList();
		for (Iterator iter = this.regions().keySet().iterator();iter.hasNext();){
			CoordinateID actRegionID = (CoordinateID)iter.next();
			Region actRegion = (Region) regions().get(actRegionID);
			boolean shouldHaveAllNeighbours = false;
			if (actRegion.getVisibility()!=null && (actRegion.getVisibility().equalsIgnoreCase("travel") 
					// || actRegion.getVisibility().equalsIgnoreCase("neighbour")
					)){
				shouldHaveAllNeighbours = true;
			} else {
				// if we have a unit in the region?
				if (actRegion.units()!=null && actRegion.units().size()>0){
						shouldHaveAllNeighbours = true;
				}
			}
			if (shouldHaveAllNeighbours){
				CoordinateID center = actRegion.getCoordinate();
				
				int radius = 1;
				for(int dx = -radius; dx <= radius; dx++) {
					for(int dy = (-radius + Math.abs(dx)) - ((dx > 0) ? dx : 0);
							dy <= ((radius - Math.abs(dx)) - ((dx < 0) ? dx : 0)); dy++) {
						CoordinateID c = new CoordinateID(0, 0, center.z);
						c.x = center.x + dx;
						c.y = center.y + dy;

						Region neighbour = (Region) regions().get(c);

						if(neighbour == null) {
							// Missing Neighbor
							Region r = new Region(c,this);
							RegionType type = this.rules.getRegionType(StringID.create("Leere"), true);
							r.setType(type);
							r.setName(Translations.getTranslation(this,"region.thevoid.name"));
							r.setDescription(Translations.getTranslation(this,"region.thevoid.beschr"));
							newRegions.add(r);
							this.addTranslation("Leere", Translations.getTranslation(this,"region.thevoid.name"));
						}
					}
				}
			}
		}
		if (newRegions.size()>0){
			for (Iterator iter = newRegions.iterator();iter.hasNext();){
				Region actRegion = (Region)iter.next();
				if (!this.regions().containsKey(actRegion.getID())){
					this.addRegion(actRegion);
				}
			}
		}
		int i = 1;
		i = 2;
	}
	
	
	/**
	 * Adds the order locale of Magellan if locale is null. This should prevent some NPE with the
	 * sideeffect to store a locale in a locale-less game data object.
	 */
	private void postProcessLocale() {
		if(getLocale() == null) {
			setLocale(Locales.getOrderLocale());
		}
	}

	/**
	 * This function post processes the message blocks to remove duplicate messages. In former
	 * times this has been done while loading the game data but  this had a negative time tradeoff
	 * (O(n^2)). This functions needs about O(n log n).
	 */
	private void postProcessMessages() {
		// faction.messages
		for(Iterator iter = factions().values().iterator(); iter.hasNext();) {
			Faction o = (Faction) iter.next();
			postProcessMessages(o.messages);
		}

		// region.messages
		for(Iterator iter = regions().values().iterator(); iter.hasNext();) {
			Region o = (Region) iter.next();
			postProcessMessages(o.messages);
		}
	}

	/**
	 * Postprocess a given list of messages. To remove duplicate messages  we put all messages in
	 * an ordered hashtable and put them back into the messages collection.
	 *
	 * @param messages TODO: DOCUMENT ME!
	 */
	private void postProcessMessages(Collection messages) {
		if(messages == null) {
			return;
		}

		Map ht = CollectionFactory.createOrderedHashtable();

		for(Iterator iter = messages.iterator(); iter.hasNext();) {
			Message msg = (Message) iter.next();

			if(ht.put(msg, msg) != null) {
				if(1==2) {
					log.warn("Duplicate message \"" + msg.getText() + "\" found, removing it.");
				}
			}
		}

		messages.clear();
		messages.addAll(ht.values());
	}

	/**
	 * TODO: DOCUMENT ME!
	 */
	public void postProcessAfterTrustlevelChange() {
		getGameSpecificStuff().postProcessAfterTrustlevelChange(this);
	}
	
//	 pavkovic 2003.01.28: this is a Map of the default Translations mapped to this class
	// it is called by reflection (we could force the implementation of an interface,
	// this way it is more flexible.)
	// Pls use this mechanism, so the translation files can be created automagically
	// by inspecting all classes.
	private static Map defaultTranslations;

	/**
	 * TODO: DOCUMENT ME!
	 *
	 * @return TODO: DOCUMENT ME!
	 */
	public static synchronized Map getDefaultTranslations() {
		if(defaultTranslations == null) {
			defaultTranslations = CollectionFactory.createHashtable();
			defaultTranslations.put("region.thevoid.name", "The Void");
			defaultTranslations.put("region.thevoid.beschr", "Added by magellan to indicate unexpected missing regions");
		}

		return defaultTranslations;
	}
	
	/**
	 * removes all "Leere" Regions
	 * needed for merging
	 */
	public void removeTheVoid(){
		ArrayList delRegionID = new ArrayList();
		for (Iterator iter = this.regions().keySet().iterator();iter.hasNext();){
			CoordinateID actRegionID = (CoordinateID)iter.next();
			Region actRegion = (Region) regions().get(actRegionID);
			if (actRegion.getRegionType().equals(this.rules.getRegionType("Leere"))){
				delRegionID.add(actRegionID);
			}
		}
		if (delRegionID.size()>0){
			for (Iterator iter = delRegionID.iterator();iter.hasNext();){
				CoordinateID actID = (CoordinateID)iter.next();
				this.regions().remove(actID);
			}
		}
	}
	
}




See more files for this project here

Magellan-Client

The Magellan Client is basicly a GUI for the pbem game eressea but can be used for other pbems based on \"atlantis\" too.

Project homepage: http://sourceforge.net/projects/magellan-client
Programming language(s): Java
License: other

  completion/
    AutoCompletion.java
    Completer.java
    CompleterSettingsProvider.java
    Completion.java
    OrderParser.java
  cr/
    Loader.java
  demo/
    actions/
      AbortAction.java
      AddCRAction.java
      AddSelectionAction.java
      ArmyStatsAction.java
      ChangeFactionConfirmationAction.java
      ConfirmAction.java
      ECheckAction.java
      EresseaOptionsAction.java
      ExpandSelectionAction.java
      ExportCRAction.java
      ExternalModuleAction.java
      FactionStatsAction.java
      FileHistoryAction.java
      FileSaveAction.java
      FileSaveAsAction.java
      FillSelectionAction.java
      FindAction.java
      FindPreviousUnconfirmedAction.java
      HelpAction.java
      InfoAction.java
      InvertSelectionAction.java
      IslandAction.java
      MapSaveAction.java
      MenuAction.java
      OpenCRAction.java
      OpenOrdersAction.java
      OpenSelectionAction.java
      OptionAction.java
      QuitAction.java
      RedoAction.java
    desktop/
    Client.java
    ClientPreferences.java
    EMapDetailsPanel.java
    EMapOverviewPanel.java
    FindDialog.java
    MagellanUndoManager.java
    SetOriginDialog.java
  event/
  extern/
  gamebinding/
  io/
  main/
  relation/
  resource/
  rules/
  skillchart/
  swing/
  tasks/
  util/
  Alliance.java
  Battle.java
  Border.java
  Building.java
  CombatSpell.java
  CompleteData.java
  CoordinateID.java
  Described.java
  DescribedObject.java
  EntityID.java
  Faction.java
  GameData.java
  Group.java
  HasRegion.java
  HotSpot.java
  ID.java
  Identifiable.java
  IntegerID.java
  Island.java
  Item.java
  LongID.java
  LuxuryPrice.java
  Message.java
  MissingData.java
  Named.java
  NamedObject.java
  Potion.java
  Region.java
  RegionResource.java
  Related.java
  RelatedObject.java
  Rules.java
  Scheme.java
  Ship.java
  Sign.java
  Skill.java
  Spell.java
  StringID.java
  TempUnit.java
  Unique.java
  Unit.java
  UnitContainer.java
  UnitID.java
  ZeroUnit.java