| Character.java |
1 /*
2 * CVS: $Id: Character.java,v 1.22 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 *
22 */
23
24package org.jzuul.engine;
25
26import java.text.MessageFormat;
27import java.util.Iterator;
28import java.util.List;
29import java.util.Random;
30
31import org.jdom.Element;
32import org.jzuul.engine.gui.GuiInterface;
33import org.jzuul.engine.rooms.*;
34
35/**
36 * Ein Character ist ein interaktives GameObject im Sinne eines Lebewesens
37 *
38 *
39 * @version $Revision: 1.22 $
40 */
41public class Character extends GameObject {
42
43 /**
44 * Enthält die Dialoge die ein Charakter führen kann
45 */
46 private List dialogs;
47
48 /**
49 * Die Nummer des aktuellen Dialogs
50 */
51 private int currentDialog = 0;
52
53 /**
54 * Das Inventar des Charakters
55 */
56 private Inventory inv;
57
58 /**
59 * enthält den aktuellen Room in dem sich der Character aufhält
60 */
61 protected Room currentRoom;
62
63 /**
64 * enthält das aktuell aktive Dialog Objekt
65 */
66 protected Dialog dialog;
67
68 /**
69 * für diverse Zwecke ein Random Object
70 */
71 private Random r;
72
73 /**
74 * Instanzieiert einen character
75 *
76 * @param name
77 * Der Name des Charakters
78 */
79 public Character(String name) {
80 super(name);
81 r = new Random();
82 inv = new Inventory(Inventory.UNLIMITED_INVENTORY);
83 this.takeable = false;
84 this.useable = false;
85 }
86
87 /**
88 * Führt eine Aktion aus (z.B moveRandom, leaveRoom) Die Namen für die
89 * Aktionen sind im gamefile.dtd definiert
90 *
91 * @param actionName
92 * der Name der Aktion
93 */
94 public void doAction(String actionName) {
95 Engine.debug(this.getName() + ": " + actionName, 2); //$NON-NLS-1$
96 if (actionName.equals("moveRandom")) { //$NON-NLS-1$
97 moveRandom();
98 }
99 if (actionName.equals("leaveRoom")) { //$NON-NLS-1$
00 this.leaveRoom();
01 }
02 }
03
04 /**
05 * Führt eine Bewegung eines Characters in eine mögliche Himmelsrichtung in
06 * Abhängigkeit von einer Zufallsvariable aus.
07 */
08 protected void moveRandom() {
09 if (r.nextBoolean()) { return; }
10 this.leaveRoom();
11 }
12
13 /**
14 * Sorgt dafür das der Character den Raum verlässt.
15 *
16 */
17 protected void leaveRoom() {
18 if (this.currentRoom == null) { return; }
19
20 List rooms = currentRoom.getWays();
21 Object[] formatArgs = { Helpers.firstToUpper(this.getName()) };
22 if (inRoomWithPlayer()) {
23 Engine.gui.printlnI(MessageFormat.format(Messages.getString("CHARACTER_LEAVES_ROOM"),formatArgs)); //$NON-NLS-1$
24 }
25 currentRoom.getContent().deleteGameObject(this.getName());
26 this.currentRoom = (Room) rooms.get(new Random().nextInt(rooms.size()));
27 currentRoom.getContent().addGameObject(this);
28 if (inRoomWithPlayer()) {
29 Engine.gui.printlnI(MessageFormat.format(Messages.getString("CHARACTER_ENTERS_ROOM"), formatArgs)); //$NON-NLS-1$
30 }
31 }
32
33 /**
34 * Sagt etwas im Namen des Characters wenn der Charakter sich im selben Raum
35 * wie der Spieler befindet.
36 *
37 * @param something
38 * Das was gesagt werden soll
39 */
40 public void say(String something) {
41 if ((inRoomWithPlayer() || (this.currentRoom == null)) && (something != null)& (!something.equals("")) ) { //$NON-NLS-1$
42 Engine.gui.println(Helpers.firstToUpper(this.getName()) + ": " + something, GuiInterface.BLUE); //$NON-NLS-1$
43 } else {
44 Engine.debug(this.getName() + " won't say something", 1); //$NON-NLS-1$
45 }
46 }
47
48 /**
49 * Stellt fest ob der Character sich im selben Room wie der Spieler befindet
50 *
51 * @return true wenn der Character im selben Room wie der Spieler ist, sonst
52 * false
53 */
54 public boolean inRoomWithPlayer() {
55 if (this.currentRoom == null) {
56 // I'm taken!
57 return false;
58 }
59 return this.currentRoom.getName().equals(Engine.player.getCurrentRoom().getName());
60 }
61
62 /**
63 * Setzt den aktiven Room für den Character
64 *
65 * @param newRoom
66 * der Room in dem sich der Player ist
67 */
68 public void setCurrentRoom(Room newRoom) {
69 this.currentRoom = newRoom;
70 }
71
72 /**
73 * Wird von dem Befehl "talk" aufgerufen uns sollte zu einem Dialog führen
74 *
75 * @return true bei erfolg des Dialoges, false otherwise
76 */
77 public boolean talkTo() {
78 if (this.dialog == null) {
79 if ((this.dialogs != null) && (this.dialogs.get(currentDialog) != null)
80 && checkPreconditions(currentDialog)) {
81 this.dialog = (Dialog) dialogs.get(currentDialog);
82 if (this.dialog.talk()) {
83 return true;
84 } else {
85 this.say(Messages.getString("CHARACTER_WONT_TALK")); //$NON-NLS-1$
86 return false;
87 }
88 } else {
89 this.say(Messages.getString("CHARACTER_WONT_TALK")); //$NON-NLS-1$
90 return false;
91 }
92 } else {
93 return this.dialog.talk();
94 }
95 }
96
97 /**
98 * Fordert den Character auf etwas zu nehmen. Die aufrufende Methode ist
99 * dafür zuständig den Gegenstand zu entfernen
00 *
01 * @param obj
02 * Das GameObject was genommen werden soll
03 * @return true falls der Gegenstand genommen wurde, false sonst
04 */
05 public boolean take(GameObject obj) {
06 if (isPrecondition(obj.getName())
07 || Engine.player.getTargetList().isGiveTarget(this.getName(), obj.getName())) {
08 this.say(Messages.getString("CHARACTER_THANKS")); //$NON-NLS-1$
09 inv.addGameObject(obj);
10 Engine.player.findAndDeleteGameObject(obj.getName());
11 return true;
12 } else {
13 return false;
14 }
15 }
16
17 /**
18 * Gibt das Objekt als JDOM Element XML zurück.
19 *
20 * @return den Character als JDOM XML Element
21 */
22 public Element toElement() {
23 Element characterElement = new Element("character"); //$NON-NLS-1$
24 characterElement.setAttribute("name", this.getName()); //$NON-NLS-1$
25 characterElement.setAttribute("dialog", String.valueOf(this.currentDialog + 1)); //$NON-NLS-1$
26 return characterElement;
27 }
28
29 /**
30 * Weist dem Charakter seine Dialoge zu
31 *
32 * @param dialogs
33 * eine Liste von Dialog Objekten
34 */
35 public void addDialogs(List dialogs) {
36 for (Iterator i = dialogs.iterator(); i.hasNext();) {
37 Dialog element = (Dialog) i.next();
38 element.setCharacter(this);
39 }
40 this.dialogs = dialogs;
41 }
42
43 /**
44 * Wird von dem AuswahlListener aufgerufen nachdem der Spieler eine
45 * DialogObject ausgewählt hat
46 *
47 * @param type
48 * Ein Event.DIALOG_ wert
49 */
50 public void pushAnswer(int type) {
51 this.doEvent(type);
52 Object[] formatArgs = { Helpers.firstToUpper(this.name) };
53 switch (type) {
54 case Event.DIALOG_CONTINUE:
55 talkTo();
56 break;
57 case Event.DIALOG_END_FAILURE:
58 Engine.gui.setDefaultActionListener();
59 Engine.gui.println(MessageFormat.format(Messages.getString("CHARACTER_ENDS_DIALOG"),formatArgs)); //$NON-NLS-1$
60 this.dialog.resetPhase();
61 break;
62 // das ist absicht:
63 case Event.DIALOG_END_SUCCESS:
64 case Event.DIALOG_CUSTOM_RESULT_1:
65 case Event.DIALOG_CUSTOM_RESULT_2:
66 case Event.DIALOG_CUSTOM_RESULT_3:
67 Engine.gui.setDefaultActionListener();
68 Engine.gui.println(MessageFormat.format(Messages.getString("CHARACTER_ENDS_DIALOG"),formatArgs)); //$NON-NLS-1$
69 this.dialog = null;
70 this.currentDialog++;
71 break;
72 default:
73 Engine.gui.setDefaultActionListener();
74 Engine.gui.println(MessageFormat.format(Messages.getString("CHARACTER_ENDS_DIALOG"),formatArgs)); //$NON-NLS-1$
75 }
76 }
77
78 /**
79 * Überprüft die Vorbedingungen für einen Dialog
80 *
81 * @param dialogNr
82 * die Dialognummer für den die Vorbedingungen überpüft werden
83 * sollen
84 * @return true wenn die Vorbedingungen erfüllt sind, false otherwise
85 */
86 protected boolean checkPreconditions(int dialogNr) {
87 if (dialogs.size() >= dialogNr) {
88 Dialog d = (Dialog) dialogs.get(dialogNr);
89 List precons = d.getPreconditions();
90 if (precons == null) { return true; }
91 for (Iterator iter = precons.iterator(); iter.hasNext();) {
92 String element = (String) iter.next();
93 if (!inv.containsGameObject(element)) { return false; }
94 }
95 }
96 return true;
97 }
98
99 /**
00 * Überprüft ob das GameObject mit dem Namen objName eine Dialogvorbedingung
01 * ist.
02 *
03 * @param objName
04 * der Name des Objekts das überpüft werden
05 * @return true wenn das spezifizierte Objekt eine Vorbedingung darstellt,
06 * false otherwise
07 */
08 protected boolean isPrecondition(String objName) {
09 if ((dialogs != null) && (dialogs.size() > currentDialog)) {
10 Dialog d = (Dialog) dialogs.get(currentDialog);
11 List precons = d.getPreconditions();
12 if (precons == null) { return true; }
13 return precons.contains(objName);
14 } else {
15 return false;
16 }
17
18 }
19
20 /**
21 * Setzt die aktuelle Dialognummer
22 *
23 * @param currentDialog
24 * die neue Dialognummer
25 */
26 public void setDialog(int currentDialog) {
27 this.currentDialog = currentDialog;
28 }
29
30 /**
31 * Führt das event mit der Id eventId aus. Spezifiziert folgende Defaults:
32 * Event.TAKEUP: setzt den aktullen Raum auf null Event.DROP: setzt den
33 * aktuellen Raum auf den aktuellen Raum des Spielers
34 *
35 * @param eventId
36 * eine Event Id
37 */
38 public void doEvent(int eventId) {
39 super.doEvent(eventId);
40 switch (eventId) {
41 case Event.TAKEUP:
42 this.setCurrentRoom(null);
43 break;
44 case Event.DROP:
45 this.setCurrentRoom(Engine.player.getCurrentRoom());
46 break;
47 }
48
49 }
50
51 /**
52 * Erstellt eine 1 zu 1 Kopie des Character Objektes
53 *
54 * @return eine Kopie des Character Objekt
55 */
56 public GameObject copy() {
57 Character newChar = new Character(this.getName());
58 super.cloneInto(newChar);
59 newChar.inv = this.inv.copy();
60 newChar.currentDialog = this.currentDialog;
61 // NOTE Again, not really save:
62 newChar.dialogs = this.dialogs;
63 newChar.currentRoom = this.currentRoom;
64 newChar.dialog = this.dialog;
65 return newChar;
66 }
67
68 public boolean isCharacter() {
69 return true;
70 }
71
72}