1 /*
2  *  CVS: $Id: Room.java,v 1.17 2004/07/25 19:07:20 marcus Exp $
3  * 
4  *  This file is part of JZuul.
5  *
6  *  JZuul is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10 *
11 *  JZuul is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with Zuul; if not, write to the Free Software
18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 * 
20 *  Copyrigth 2004 by marcus, leh
21 *  Initially based on an example by Michael Kolling and David J. Barnes
22 * 
23 */
24
25package org.jzuul.engine.rooms;
26
27import java.io.InputStream;
28import java.util.Iterator;
29import java.util.List;
30import java.util.Vector;
31
32import org.jdom.Element;
33import org.jzuul.engine.Directions;
34import org.jzuul.engine.Engine;
35import org.jzuul.engine.Event;
36import org.jzuul.engine.EventHandler;
37import org.jzuul.engine.EventListener;
38import org.jzuul.engine.GameObject;
39import org.jzuul.engine.Helpers;
40import org.jzuul.engine.Inventory;
41import org.jzuul.engine.Messages;
42import org.jzuul.engine.exceptions.GuiNotInitializedException;
43import org.jzuul.engine.exceptions.NoSuchEventException;
44
45/**
46 * Ein normaler Raum
47 * 
48 * 
49 * @version $Revision: 1.17 $
50 **/
51public class Room implements EventListener {
52    /**
53     * enthält die Beschriebung des Raumes
54     */
55    protected String beschreibung;
56
57    /**
58     * die Beschreibungen für "look"
59     */
60    protected String[] blickrichtungen = new String[Directions.NUMBER_OF_DIRECTIONS];
61
62    /**
63     * Die Raum Objekte die an diesen Raum grenzen
64     */
65    protected Room[] wege = new Room[Directions.NUMBER_OF_DIRECTIONS];
66
67    /**
68     * Der Name des Raumes
69     */
70    protected String name;
71
72    /**
73     * Die EventHandler für diesen Raum
74     */
75    protected EventHandler[] eventHandlers = new EventHandler[Event.COUNT];
76
77    /**
78     * Der Inhalt des Raumes
79     */
80    protected Inventory contents;
81    
82    /**
83     * Enthällt den Stream auf das für den Raum definierte Bild
84     */
85    protected InputStream imageStream;
86
87    /**
88     * Konstruktor, erstellt einen Raum OHNE Beschreibung
89     * 
90     * @param name der Name des Raumes, ermöglicht den Zugriff innerhalb einer GameMap
91     */
92    public Room(String name) {
93        this(name, ""); //$NON-NLS-1$
94    }
95
96    /**
97     * Erzeuge eine Room Objekt mit einer Beschreibung. Ein Raum
98     * hat anfangs keine Ausgänge.
99     * @param name  der Name des Raumes, ermöglicht den Zugriff innerhalb einer GameMap
00     * @param beschreibung enthält eine Beschreibung in der Form
01     *        "in einer Küche" oder "auf einem Sportplatz".
02     */
03    public Room(String name, String beschreibung) {
04        this.name = name;
05        this.beschreibung = beschreibung;
06        contents = new Inventory(Inventory.UNLIMITED_INVENTORY);
07    }
08
09    /**
10     * Ermöglicht den Zugriff auf das "Inventar" des Raumes, ein Room Objekt kann unendlich viele Dinge enthalten
11     * 
12     * @return das Inventory Objekt des Raumes
13     */
14    public Inventory getContent() {
15        return this.contents;
16    }
17
18    /** 
19    * Zugriff auf das Room Objekt unter diesem Room Objekt
20     * 
21     * @return das Room Objekt unter dem aktuellen Raum
22     */
23    public Room getDownway() {
24        return getRoomByOrientation(Directions.BELOW);
25    }
26
27    /** 
28    * Zugriff auf das Room Objekt über diesem Room Objekt
29     * 
30     * @return das Room Objekt under dem aktuellen Room Objekt
31     */
32
33    public Room getUpway() {
34        return getRoomByOrientation(Directions.TOP);
35    }
36
37    /**
38     * Gibt ein Room Objekt in einer gegebenen Himmelsrichtung zurück
39     * 
40     * @param direction die Himmelsrichtung
41     * @return  den Raum in dieser Himmelsrichtung, null falls dort keiner ist
42     * @see org.jzuul.engine.Directions
43     */
44    public Room getRoomByOrientation(int direction) {
45        if (wege[direction] != null) {
46            return wege[direction];
47        } else {
48            return null;
49        }
50    }
51
52    /**
53     * Gibt due Beschreibung für eine Himmelrichtung zurück (für "look")
54     * 
55     * Für d Directions.TOP und Directions.BELOW wird ein default Wert zurückgegeben,
56     * 
57     * @param direction Eine mögliche Richtung wie north,east,south und west oder up and down
58     * @return die Beschreibung in dieser Richtung, null wenn es keine Beschreibung gibt.
59     * @see org.jzuul.engine.Directions
60     */
61    public String getWayDescriptionByDirection(int direction) {
62        // watch out, this is the INT version of this method
63        // which will be called by the STRING version of this method
64        Engine.debug("Called for direction " + direction, 1); //$NON-NLS-1$
65        if (Directions.getDirectionName(direction) == null) {
66            return null;
67        }
68        String desc = blickrichtungen[direction];
69        if ((desc != null) && (!desc.equals(""))) { //$NON-NLS-1$
70            return desc;
71        }
72        if (direction == Directions.TOP) {
73            return Messages.getString("ROOM_ROOF"); //$NON-NLS-1$
74        }
75        if (direction == Directions.BELOW) {
76            return Messages.getString("ROOM_BOTTOM"); //$NON-NLS-1$
77        }
78        return null;
79    }
80
81    /**
82     * Liefere die Beschreibung dieses Raums (die dem Konstruktor
83     * übergeben wurde).
84     * @return die Beschreibeung des Raumes
85     */
86    public String getDescription() {
87        if (beschreibung != null) {
88            return beschreibung;
89        } else {
90            return Messages.getString("ROOM_DEFAULT") + Helpers.firstToUpper(getName()); //$NON-NLS-1$
91        }
92    }
93
94    /**
95     * Führt ein Event aus und ruft den defaulHandler auf
96     * 
97     * @param id    die Event ID
98     * @see org.jzuul.engine.Event
99     */
00    public void doEvent(int id) {
01        if (id >= Event.COUNT || id < 0)
02            throw new IllegalArgumentException("Id is not valid: " + id); //$NON-NLS-1$
03        if (eventHandlers[id] != null) {
04            eventHandlers[id].execute(this);
05        }
06        defaultHandler(id);
07    }
08
09    /**
10     * Default EventHandler für die Fälle Event.PLAYERENTER und Event.PLAYERLEAVE.
11     * 
12     * Der Raum gibt diese Events an sein Inventory weiter. Bei einem PLAYERENTER
13     * wird zusätzlich die Beschreibung ausgegeben
14     * 
15     * @param eventId die EventId
16     * @see org.jzuul.engine.Event
17     * @see org.jzuul.engine.EventHandler
18     */
19    protected void defaultHandler(int eventId) {
20        //      these are the default event handlers: (do we want them overrideable?)
21        switch (eventId) {
22            case Event.PLAYERENTER :
23                this.printBeschreibung();
24                notifyContained(Event.PLAYERENTER);
25                break;
26            case Event.PLAYERLEAVE :
27                notifyContained(Event.PLAYERLEAVE);
28                break;
29        }
30    }
31
32    /**
33     * Gibt die Beschreibung aus
34     *
35     *  @throws GuiNotInitializedException wenn Engine.gui == null
36     */
37    public void printBeschreibung() throws GuiNotInitializedException {
38        if (Engine.gui == null) {
39            throw new GuiNotInitializedException("Engine.gui is undefined"); //$NON-NLS-1$
40        }
41
42        Engine.gui.showImage(this.imageStream);
43        Engine.gui.println();
44        Engine.gui.println(Messages.getString("ROOM_YOU_ARE") + this.getDescription()); //$NON-NLS-1$
45        Engine.gui.println();
46        String ausgaenge = getWegeAsString();
47
48        if (ausgaenge.length() > 0) {
49            Engine.gui.printU(Messages.getString("ROOM_WAYS")); //$NON-NLS-1$
50            Engine.gui.println(" " + ausgaenge); //$NON-NLS-1$
51        }
52
53        if (this.getUpway() != null) {
54            Engine.gui.println(Messages.getString("ROOM_STAIRS_UP")); //$NON-NLS-1$
55        }
56        if (this.getDownway() != null) {
57            Engine.gui.println(Messages.getString("ROOM_STAIRS_DOWN")); //$NON-NLS-1$
58        }
59
60        String inhalt = new String();
61        for (Iterator i = contents.gameObjectNamesIterator(); i.hasNext();) {
62            String objName = (String) i.next();
63            inhalt += Helpers.firstToUpper(objName) + " "; //$NON-NLS-1$
64            if (contents.getNumberOfObject(objName) > 1) {
65                inhalt += "(" + contents.getNumberOfObject(objName) + ") "; //$NON-NLS-1$ //$NON-NLS-2$
66            }
67        }
68        if (inhalt.length() > 0) {
69            Engine.gui.printU(Messages.getString("ROOM_INTERESTING_THINGS")); //$NON-NLS-1$
70            Engine.gui.println(" " + inhalt); //$NON-NLS-1$
71        }
72
73        Engine.gui.println();
74    }
75
76    /**
77     * Wandelt die möglichen Wege, also Himmelsrichtungen für die ein
78     * Room Objekt existiert in eine Beschreibung um
79     * 
80     * @return die Namen der Himmelsrichtungen für die Room Objekte existieren
81     */
82    public String getWegeAsString() {
83        String retval = new String();
84
85        if (getRoomByOrientation(Directions.NORTH) != null) {
86            retval = "north "; //$NON-NLS-1$
87        }
88        if (getRoomByOrientation(Directions.EAST) != null) {
89            retval += "east "; //$NON-NLS-1$
90        }
91        if (getRoomByOrientation(Directions.SOUTH) != null) {
92            retval += "south "; //$NON-NLS-1$
93        }
94        if (getRoomByOrientation(Directions.WEST) != null) {
95            retval += "west "; //$NON-NLS-1$
96        }
97        return retval;
98
99    }
00
01    /**
02     * Setzt die Beschreibungen für oben und unten
03     * 
04     * @param up    die neue Beschreibung für Oben
05     * @param down  die neue Beschreibung für Unten
06     */
07    public void setDescriptionsUpDown(String up, String down) {
08        blickrichtungen[Directions.TOP] = up;
09        blickrichtungen[Directions.BELOW] = down;
10    }
11
12    /**
13     * Zugriffe auf alle an ein Room Objekt grenzenden Räume
14     * 
15     * @return  eine Liste von Room Objekten die an den aktuellen Raum grenzen
16     */
17    public List getWays() {
18        Vector v = new Vector();
19        for (int i = 0; i < wege.length; i++) {
20            if (wege[i] != null) {
21                v.add(wege[i]);
22            }
23        }
24        return v;
25    }
26
27    /**
28     * Weist dem Room Objekt eine neues benachbartes Objekt zu 
29     * 
30     * @param direction die Himmelrichtung
31     * @param raum      das Room Objekt
32     * @see org.jzuul.engine.Directions
33     */
34    public void setExitByDirection(int direction, Room raum) {
35        if (wege[direction] == null) {
36            wege[direction] = raum;
37        } else {
38            /*throw new RoomOverwriteException(
39                "Der Room "
40                    + this.getName()
41                    + " hat schon einen Room in Richtung "
42                    + Directions.getDirectionName(direction));
43                    */
44        }
45    }
46
47    /**
48     * Setzt die Beschreibung für eine Himmelsrichtung die mit "look" 
49     * eingesehen werden kann.
50     * 
51     * @param direction die Richtung
52     * @param description   die neue Beschreibung
53     * @see org.jzuul.engine.Directions
54     */
55    public void setWayDescription(int direction, String description) {
56        blickrichtungen[direction] = description;
57    }
58
59    /**
60     * Gibt das Room Objekt in einer Himmelsrichtung zurück
61     * 
62     * @param orientation   der Name eine Himmelsrichtung
63     * @return  das Room Objekt in dieser Richtung, null falls keines existiert
64     * @see org.jzuul.engine.Directions
65     */
66    public Room getRoomByOrientation(String orientation) {
67        int dir = Directions.directionToInt(orientation);
68        if (dir > -1) {
69            return wege[dir];
70        } else {
71            return null;
72        }
73    }
74
75    /**
76     * Gibt die Beschreibung einer Himmelsrichtung zurück
77     * 
78     * @param direction der Name einer Himmelrichtung
79     * @return  die Beschreibung für diese Himmelsrichtung
80     * @see org.jzuul.engine.Directions
81     */
82    public String getWayDescriptionByDirection(String direction) {
83        int dir = Directions.directionToInt(direction);
84        if (dir != Directions.DIRECTION_ERROR) {
85            return getWayDescriptionByDirection(dir);
86        } else {
87            return null;
88        }
89    }
90
91    /**
92     * Zugriff auf den Namen eines Raumes
93     * 
94     * @return  der Name des Raumes
95     */
96    public String getName() {
97        return name;
98    }
99
00    /**
01     * Wandelt einen Raum und die enthaltenen Objekte in ein JDOM XML Element um
02     * 
03     * @return das JDOM XML Element das diesen Raum beschreibt
04     */
05    public Element toElement() {
06        Element roomE = new Element("room"); //$NON-NLS-1$
07
08        roomE.setAttribute("class", this.getClass().toString().substring(6)); //$NON-NLS-1$
09        roomE.setAttribute("name", getName()); //$NON-NLS-1$
10        roomE.addContent(new Element("description").setText(getDescription())); //$NON-NLS-1$
11
12        roomE.addContent(getContent().toElement());
13
14        Element w = waysToElement();
15        if (w.getChildren().size() > 0)
16            roomE.addContent(w);
17
18        Element v = viewsToElement();
19        if (v.getChildren().size() > 0)
20            roomE.addContent(v);
21
22        return roomE;
23    }
24
25    /**
26     * Wandelt die Wege (angrenzende Room Objekte) in ein JDOM XML Element um
27     * 
28     * @return  ein JDOM XML Element das die Namen der Räume beschreibt, die an diesen Raum grenzen
29     */
30    protected Element waysToElement() {
31        Element waysE = new Element("ways"); //$NON-NLS-1$
32        for (int i = 0; i < Directions.NUMBER_OF_DIRECTIONS; i++) {
33            if (wege[i] != null) {
34                Element wayE = new Element("way"); //$NON-NLS-1$
35                wayE.setAttribute("direction", Directions.getDirectionName(i)); //$NON-NLS-1$
36                wayE.setAttribute("room", wege[i].getName()); //$NON-NLS-1$
37                waysE.addContent(wayE);
38            }
39        }
40        return waysE;
41    }
42
43    /**
44     * Wandelt die Wege (Blickrichtungsbeschreibungen) in ein JDOM XML Element um
45     * 
46     * @return  ein JDOM XML Element das die Wegbeschreibungen enthällt
47     */
48    protected Element viewsToElement() {
49        Element viewsE = new Element("views"); //$NON-NLS-1$
50
51        int count = 0;
52        for (int i = 0; i < Directions.NUMBER_OF_DIRECTIONS; i++) {
53            if (blickrichtungen[i] != null) {
54                Element viewE = new Element("view"); //$NON-NLS-1$
55                viewE.setAttribute("direction", Directions.getDirectionName(i)); //$NON-NLS-1$
56                viewE.setText(blickrichtungen[i]);
57                viewsE.addContent(viewE);
58                count++;
59            }
60        }
61        return viewsE;
62    }
63
64    /**
65     * Weist dem Raum ein Inventar zu
66     * 
67     * @param newInv das neue Inventar
68     */
69    public void setInv(Inventory newInv) {
70        this.contents = newInv;
71    }
72
73    /**
74     * Weist den Raum an, ein GameObject aus dem globalen ObjectPool in sein Inventar zu übernehmen
75     * 
76     * @param objName   der Name des GameObjects das geholt werden soll 
77     */
78    public void getFromPool(String objName) {
79        Engine.debug(objName, 1);
80        GameObject obj = (GameObject) Engine.objectPool.get(objName);
81        this.contents.addGameObject(obj.copy());
82    }
83
84    /**
85     * Leitet ein Event an die enthaltenen GameObjects weiter
86     * 
87     * @param id die Id des Events
88     * @see org.jzuul.engine.Event
89     */
90    public void notifyContained(int id) {
91        Vector v = (Vector) this.getContent().getCharacterObjects();
92        for (Iterator i = v.iterator(); i.hasNext();) {
93            ((EventListener) i.next()).doEvent(id);
94        }
95    }
96
97    /**
98     * Setzt den EventHandler für eine Event.
99     * 
00     * @param name der Name des Events
01     * @param handler das EventHandler Objekt für dieses Event
02     * @see org.jzuul.engine.EventHandler
03     */
04    public void setHandler(String name, EventHandler handler) {
05        if (name == null || handler == null)
06            throw new IllegalArgumentException("You can not set a handler with a null value"); //$NON-NLS-1$
07        int id = Event.fromString(name);
08        if (id > -1) {
09            this.eventHandlers[id] = handler;
10        } else {
11            throw new NoSuchEventException("The event " + name + " is unknown"); //$NON-NLS-1$ //$NON-NLS-2$
12        }
13    }
14
15    /**
16     * Setzt dem Raum den auf das Bild verweisenden Stream
17     * 
18     * @param imageStream   ein InputStream der ein Bild enthällt
19     */
20    public void setImageStream(InputStream imageStream) {
21        this.imageStream = imageStream;
22    }
23
24}
25