/*------------------------------------------------------------------------- svninfo: $Id$ Maarten's Mud, WWW-based MUD using MYSQL Copyright (C) 1998 Maarten van Leunen 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Maarten van Leunen Appelhof 27 5345 KA Oss Nederland Europe maarten_l@yahoo.com -------------------------------------------------------------------------*/ package mmud.items; import java.io.StringReader; import java.util.Hashtable; import java.util.TreeMap; import java.util.Vector; import java.util.logging.Logger; import mmud.Attribute; import mmud.AttributeContainer; import mmud.Constants; import mmud.MudException; import mmud.characters.Person; import mmud.common.MudInterpreter; import mmud.common.MudXMLExecutable; import mmud.database.AttributeDb; import mmud.database.Database; import mmud.database.ItemsDb; import mmud.database.MudDatabaseException; import simkin.Executable; import simkin.ExecutableContext; import simkin.ExecutableIterator; import simkin.FieldNotSupportedException; import simkin.Interpreter; import simkin.MethodNotSupportedException; import simkin.Null; import simkin.XMLExecutable; /** * An item in the mud. Basically consists of an ItemDefinition and a number of * Attributes specific to this item. */ public class Item implements Executable, AttributeContainer { private final int theItemDef; private final int theId; private final TreeMap<String, Attribute> theAttributes = new TreeMap<String, Attribute>(); /** * Default is null pointer, if it is not being worn/wielded. */ private PersonPositionEnum thePlaceOnBody; /** * Create this item object with a default Item Definition and id. This * method is usually only used by the database. * * @param anItemDef * definition of the item * @param anId * integer identification of the item * @param aPosBody * the place on the body that this item is worn on or wielded. */ Item(ItemDef anItemDef, int anId, PersonPositionEnum aPosBody) { this(anItemDef, anId); thePlaceOnBody = aPosBody; } /** * Create this item object with a default Item Definition and id. This * method is usually only used by the database. * * @param anItemDef * definition of the item * @param anId * integer identification of the item */ Item(ItemDef anItemDef, int anId) { theItemDef = anItemDef.getId(); theId = anId; } /** * Create this item object with a default Item Definition and id. This * method is usually only used by the database. * * @param anItemDef * integer definition identification of the item * @param anId * integer identification of the item */ Item(int anItemDef, int anId, PersonPositionEnum aPosBody) throws MudDatabaseException { this(ItemDefs.getItemDef(anItemDef), anId, aPosBody); } /** * Create this item object with a default Item Definition and id. This * method is usually only used by the database. * * @param anItemDef * integer definition identification of the item * @param anId * integer identification of the item */ Item(int anItemDef, int anId) throws MudDatabaseException { this(ItemDefs.getItemDef(anItemDef), anId); } /** * Returns the id of this Item. Every instance of an ItemDef has a unique * item id. * * @return integer identifying the Item. */ public int getId() { return theId; } /** * Returns the position on the body where this item is worn/wielded. Will * return a null pointer if the item is not worn/wielded at all. * * @return PersonPositionEnum identifying the position on the body. */ public PersonPositionEnum getWearing() { return thePlaceOnBody; } /** * Returns wether or not an item is being worn/wielded by a person. This * will always return false if the item is lying in a room. * * @return true if the item is being worn/wielded, otherwise false. */ public boolean isWearing() { return thePlaceOnBody != null; } /** * Return if the position entered is a member of the possible positions that * this item can be worn on. * * @return boolean, true if this item is wearable there. * @throws MudDatabaseException */ public boolean isWearable(PersonPositionEnum aPersonPosition) throws MudDatabaseException { return getItemDef().isWearable(aPersonPosition); } /** * Set the position on the body where this item is worn. Set the null * pointer if the item does not need to be worn. * * @param aPersonPosition * identifying the position on the body. * @throws RuntimeException * when unable to attach the item to this position on the body, * because the item won't fit. * @throws ItemDoesNotExistException * if the item could not be found. */ public void setWearing(PersonPositionEnum aPersonPosition) throws ItemDoesNotExistException, MudDatabaseException, ItemCannotBeWornException { if (!isWearable(aPersonPosition)) { throw new ItemCannotBeWornException( "unable to attach item to position," + " position illegal for this item."); } thePlaceOnBody = aPersonPosition; ItemsDb.changeWearing(this); } /** * get the verb of the item. * * @return String containing the verb. * @throws MudDatabaseException */ public String getVerb() throws MudDatabaseException { return getItemDef().getVerb(); } /** * get the first adjective of the item. * * @return String containing the first adjective. * @throws MudDatabaseException */ String getAdjective1() throws MudDatabaseException { return getItemDef().getAdjective1(); } /** * get the second adjective of the item. * * @return String containing the second adjective. * @throws MudDatabaseException */ String getAdjective2() throws MudDatabaseException { return getItemDef().getAdjective2(); } /** * get the third adjective of the item. * * @return String containing the third adjective. * @throws MudDatabaseException */ String getAdjective3() throws MudDatabaseException { return getItemDef().getAdjective3(); } /** * Returns the value of the item. * * @return String description of the amount of money. * @throws MudDatabaseException * @see Constants#getDescriptionOfMoney */ public String getDescriptionOfMoney() throws MudDatabaseException { String total = Constants.getDescriptionOfMoney(getMoney()); Logger.getLogger("mmud").finer("returns '" + total + "'"); return total; } /** * get the value of the item. * * @return integer containing the number of copper coins. * @throws MudDatabaseException */ public int getMoney() throws MudDatabaseException { return getItemDef().getMoney(); } /** * get the item definition belonging to this item. * * @return ItemDef object containing the item definition. * @throws MudDatabaseException * itemdef not found */ public ItemDef getItemDef() throws MudDatabaseException { return ItemDefs.getItemDef(theItemDef); } /** * get a description of the item. * * @return String containing the short description. * @throws MudDatabaseException * @see ItemDef#getDescription */ public String getDescription() throws MudDatabaseException { return getItemDef().getDescription(); } private String getStringForWearing(PersonPositionEnum aPos) throws MudDatabaseException { if (aPos == null) { return ""; } if (isWearable(aPos)) { return ("You can " + (aPos.isWielding() ? "wield" : "wear") + " it " + aPos + ".<BR>").replaceAll("%SHISHER", "your"); } return ""; } /** * get the description of the item (the long one). If the attribute * <I>description</I> exists, than this one is used instead. * * @return String containing the description. */ public String getLongDescription() throws MudException { StringBuffer myString = new StringBuffer( isAttribute("description") ? getAttribute("description") .getValue() : getItemDef().getLongDescription()); myString.append(getStringForWearing(PersonPositionEnum.WIELD_RIGHT)); myString.append(getStringForWearing(PersonPositionEnum.WIELD_LEFT)); myString.append(getStringForWearing(PersonPositionEnum.WIELD_BOTH)); myString.append(getStringForWearing(PersonPositionEnum.ON_HEAD)); myString.append(getStringForWearing(PersonPositionEnum.ON_NECK)); myString.append(getStringForWearing(PersonPositionEnum.ON_TORSO)); myString.append(getStringForWearing(PersonPositionEnum.ON_ARMS)); myString.append(getStringForWearing(PersonPositionEnum.ON_LEFT_WRIST)); myString.append(getStringForWearing(PersonPositionEnum.ON_RIGHT_WRIST)); myString.append(getStringForWearing(PersonPositionEnum.ON_LEFT_FINGER)); myString .append(getStringForWearing(PersonPositionEnum.ON_RIGHT_FINGER)); myString.append(getStringForWearing(PersonPositionEnum.ON_FEET)); myString.append(getStringForWearing(PersonPositionEnum.ON_HANDS)); myString.append(getStringForWearing(PersonPositionEnum.ON_WAIST)); myString.append(getStringForWearing(PersonPositionEnum.ON_LEGS)); myString.append(getStringForWearing(PersonPositionEnum.ON_EYES)); myString.append(getStringForWearing(PersonPositionEnum.ON_EARS)); myString.append(getStringForWearing(PersonPositionEnum.ABOUT_BODY)); return myString.toString(); } /** * standard tostring implementation. * * @return String containing the super.tostring + : + item def. */ @Override public String toString() { try { return super.toString() + ":" + getId() + ":" + getItemDef(); } catch (MudDatabaseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * Set or add an attribute of this item. * * @param anAttribute * the attribute to be added/set. */ public void setAttribute(Attribute anAttribute) throws MudException { theAttributes.put(anAttribute.getName(), anAttribute); AttributeDb.setAttribute(anAttribute, this); } /** * Set or add a number of attributes of this item. * * @param anAttributeVector * vector containing the attributes to be added/set. This does * not use the database, i.e. should be used <I>by</I> the * database, upon creation of items. */ public void setAttributes(Vector anAttributeVector) throws MudException { if (anAttributeVector == null) { return; } for (int i = 0; i < anAttributeVector.size(); i++) { Attribute attrib = (Attribute) anAttributeVector.elementAt(i); theAttributes.put(attrib.getName(), attrib); } } /** * returns the attribute found with name aName or null if it does not exist. * * @param aName * the name of the attribute to search for * @return Attribute object containing the attribute foudn or null. * @throws MudDatabaseException */ public Attribute getAttribute(String aName) throws MudDatabaseException { Attribute myAttrib = (Attribute) theAttributes.get(aName); if (myAttrib == null) { myAttrib = getItemDef().getAttribute(aName); } return myAttrib; } /** * Remove a specific attribute from the item. * * @param aName * the name of the attribute to be removed. */ public void removeAttribute(String aName) throws MudException { Attribute attrib = getAttribute(aName); theAttributes.remove(aName); if (attrib != null) { AttributeDb.removeAttribute(attrib, this); } } /** * returns true if the attribute with name aName exists. * * @param aName * the name of the attribute to check * @return boolean, true if the attribute exists for this item, otherwise * returns false. * @throws MudDatabaseException */ public boolean isAttribute(String aName) throws MudDatabaseException { return theAttributes.containsKey(aName) || getItemDef().isAttribute(aName); } // public boolean isWorn // public boolean isWielded // public PersonPositionEnum getWorn // public PersonPositionEnum getWielded // public void setWorn( // public void setWielded(PersonPositionEnum aNew public void setValue(String field_name, String attrib_name, Object value, ExecutableContext ctxt) throws FieldNotSupportedException { Logger.getLogger("mmud").finer( "field_name=" + field_name + ", atttrib_name=" + attrib_name + ", value=" + value + "[" + value.getClass() + "]"); if (field_name.equals("description")) { if (value instanceof Null) { throw new FieldNotSupportedException(field_name + " not set, cannot be null."); } if (value instanceof String) { // TODO: perhaps // setDescription((String) value); return; } throw new FieldNotSupportedException(field_name + " not set, not string."); } throw new FieldNotSupportedException(field_name + " not found."); } public void setValueAt(Object array_index, String attrib_name, Object value, ExecutableContext ctxt) { Logger.getLogger("mmud").finer( "array_index=" + array_index + ", atttrib_name=" + attrib_name + ", value=" + value); } public ExecutableIterator createIterator() { Logger.getLogger("mmud").finer(""); return null; } public ExecutableIterator createIterator(String qualifier) { Logger.getLogger("mmud").finer("qualifier=" + qualifier); return createIterator(); } public Hashtable getAttributes() { Logger.getLogger("mmud").finer(""); return null; } public Hashtable getInstanceVariables() { Logger.getLogger("mmud").finer(""); return null; } public String getSource(String location) { Logger.getLogger("mmud").finer("location=" + location); return null; } public Object getValue(String field_name, String attrib_name, ExecutableContext ctxt) throws FieldNotSupportedException { Logger.getLogger("mmud").finer( "field_name=" + field_name + ", atttrib_name=" + attrib_name); if (field_name.equals("description")) { try { return getDescription(); } catch (MudDatabaseException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (field_name.equals("itemdef")) { try { return new Integer(getItemDef().getId()); } catch (MudDatabaseException e) { Logger.getLogger("mmud").severe( "itemdefinition not found for item " + getId() + "!"); e.printStackTrace(); } } throw new FieldNotSupportedException(field_name + " not found."); } public Object getValueAt(Object array_index, String attrib_name, ExecutableContext ctxt) { Logger.getLogger("mmud").finer( "array_index=" + array_index + ", atttrib_name=" + attrib_name); return null; } public Object methodAttribute(String method_name, Object[] arguments, ExecutableContext ctxt) throws MethodNotSupportedException, MudDatabaseException { Logger.getLogger("mmud").finer( "method_name=" + method_name + ", arguments=" + arguments); if (method_name.equals("getAttribute")) { if (arguments.length == 1) { if (!(arguments[0] instanceof String)) { throw new MethodNotSupportedException(method_name + " does not contain a String as argument."); } Attribute mAttrib = getAttribute((String) arguments[0]); if (mAttrib == null) { return null; } if (mAttrib.getValueType().equals("string")) { return mAttrib.getValue(); } if (mAttrib.getValueType().equals("boolean")) { return new Boolean(mAttrib.getValue()); } if (mAttrib.getValueType().equals("integer")) { try { return new Integer(mAttrib.getValue()); } catch (NumberFormatException e) { throw new MethodNotSupportedException(method_name + " attribute " + mAttrib.getName() + " does not contain expected number."); } } throw new MethodNotSupportedException(method_name + " unknown value type in attribute " + mAttrib.getName() + ". (" + mAttrib.getValueType() + ")"); } } if (method_name.equals("removeAttribute")) { if (arguments.length == 1) { if (!(arguments[0] instanceof String)) { throw new MethodNotSupportedException(method_name + " does not contain a String as argument."); } try { removeAttribute((String) arguments[0]); } catch (MudException e) { throw new MethodNotSupportedException(method_name + " could not remove attribute."); } Database.writeLog("root", "removed attribute (" + arguments[0] + ") from item " + this); return null; } } if (method_name.equals("setAttribute")) { if (arguments.length == 2) { if (!(arguments[0] instanceof String)) { throw new MethodNotSupportedException(method_name + " does not contain a String as first argument."); } String mType = "object"; if (arguments[1] instanceof String) { mType = "string"; } if (arguments[1] instanceof Integer) { mType = "integer"; } if (arguments[1] instanceof Boolean) { mType = "boolean"; } Attribute mAttrib = null; try { mAttrib = new Attribute((String) arguments[0], arguments[1] + "", mType); } catch (MudException e) { throw new MethodNotSupportedException(method_name + " could not set attribute."); } try { setAttribute(mAttrib); } catch (MudException e) { throw new MethodNotSupportedException(method_name + " could not set attribute."); } Database.writeLog("root", "set attribute (" + arguments[0] + ") in item " + this); return null; } } if (method_name.equals("isAttribute")) { if (arguments.length == 1) { if (!(arguments[0] instanceof String)) { throw new MethodNotSupportedException(method_name + " does not contain a String as first argument."); } return new Boolean(isAttribute((String) arguments[0])); } } throw new MethodNotSupportedException(method_name + " not found."); } public Object method(String method_name, Object[] arguments, ExecutableContext ctxt) throws MethodNotSupportedException { Logger.getLogger("mmud").finer( "method_name=" + method_name + ", arguments=" + arguments); if (method_name.equals("addItem")) { if (arguments.length == 1) { if (!(arguments[0] instanceof Integer)) { throw new MethodNotSupportedException(method_name + " does not contain a Integer as argument."); } ItemDef myItemDef = null; try { myItemDef = ItemDefs.getItemDef(((Integer) arguments[0]) .intValue()); } catch (MudDatabaseException e) { throw new MethodNotSupportedException(e.getMessage()); } if (myItemDef == null) { throw new MethodNotSupportedException(method_name + " tried to use an unknown item definition."); } // TODO // if (myItemDef.getMoney() > 0) // { // throw new MethodNotSupportedException(method_name + // " tried to create an item that is worth money."); // } Item myItem = null; try { myItem = ItemsDb.addItem(myItemDef); } catch (MudException e2) { throw new MethodNotSupportedException(e2.getMessage()); } try { ItemsDb.addItemToContainer(myItem, this); } catch (ItemDoesNotExistException e) { throw new MethodNotSupportedException(e.getMessage()); } catch (MudDatabaseException e2) { throw new MethodNotSupportedException(e2.getMessage()); } Database.writeLog("root", "created item (" + myItem + ") in item " + this); return myItem; } } if (method_name.equals("isWielding")) { if (arguments.length == 0) { return new Boolean(getWearing().isWielding()); } } try { return methodAttribute(method_name, arguments, ctxt); } catch (MudDatabaseException e) { // TODO Auto-generated catch block e.printStackTrace(); } throw new MethodNotSupportedException(method_name + " not found."); } /** * Executes a script with this item as the focus point. * * @param aScript * a String containing the script to execute. * @param aXmlMethodName * the name of the method in the xml script that you wish to * execute. * @param aPerson * the person that is responsible for the mutation on the item, * causing the event. If it is a null value, the scripted method * will not be called with this array. This also means that the * method in the xml script needs to either have this parameter * set, or not set in the declaration. * @see <A HREF="http://www.simkin.co.uk">Simkin</A> * @throws MudException * if something goes wrong. */ public Object runScript(String aXmlMethodName, String aScript, Person aPerson) throws MudException { Logger.getLogger("mmud").finer(""); try { // Create an interpreter and a context Interpreter interp = new MudInterpreter(); ExecutableContext ctxt = new ExecutableContext(interp); // create an XMLExecutable object with the xml string XMLExecutable executable = new MudXMLExecutable(getId() + "", new StringReader(aScript)); // call the "main" method with the person as an argument // or with the person as well as the command (split into // different words in the array.) if (aPerson == null) { Object args[] = { this }; return executable.method(aXmlMethodName, args, ctxt); } Object args[] = { aPerson, this }; return executable.method(aXmlMethodName, args, ctxt); } catch (simkin.ParseException aParseException) { System.out.println("Unable to parse command."); aParseException.printStackTrace(); throw new MudException("Unable to parse command.", aParseException); } catch (Exception e) { e.printStackTrace(); throw new MudException("Unable to run script.", e); } } /** * Executes a script with this item as the focus point. * * @param aScript * a String containing the script to execute. * @param aXmlMethodName * the name of the method in the xml script that you wish to * execute. * @see <A HREF="http://www.simkin.co.uk">Simkin</A> * @see #runScript(String,String,String[]) * @throws MudException * if something goes wrong. */ public Object runScript(String aXmlMethodName, String aScript) throws MudException { Logger.getLogger("mmud").finer(""); return runScript(aXmlMethodName, aScript, null); } /** * determines whether an adjective is actually part of this items * description. * * @param anAdjective * String containing the adjective to look for. * @return boolean true if the adjective entered is part of the description * of this item. * @throws MudDatabaseException * @see ItemDef#isAdjective */ public boolean isAdjective(String anAdjective) throws MudDatabaseException { return getItemDef().isAdjective(anAdjective); } /** * Determines if this item can be sold. * * @return boolean, true if the item can be sold, false otherwise. */ public boolean isSellable() throws MudException { return (!isAttribute("notsellable")) && (getMoney() != 0) && (!isWearing()); } }