/* * Copyright (C) 2012 maartenl * * 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 3 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, see <http://www.gnu.org/licenses/>. */ package mmud.database.entities.game; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; import javax.persistence.Basic; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.Lob; import javax.persistence.ManyToOne; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import mmud.Attributes; import mmud.database.entities.Ownage; import mmud.database.entities.characters.Person; import mmud.database.entities.characters.User; import mmud.database.entities.items.Item; import mmud.database.entities.items.ItemWrangler; import mmud.exceptions.ItemException; import mmud.exceptions.MudException; import org.eclipse.persistence.annotations.Customizer; /** * A room. Bear in mind that this room has potential exits to the north, south, * east, west, up and down, which are also rooms. The structure forms a kind of * graph. * * @see <a href="http://www.eclipse.org/eclipselink/documentation/2.5/concepts/app_dev007.htm">About weaving</a> * @author maartenl */ @Entity @Table(name = "mm_rooms") @NamedQueries( { @NamedQuery(name = "Room.findAll", query = "SELECT r FROM Room r") , @NamedQuery(name = "Room.findById", query = "SELECT r FROM Room r WHERE r.id = :id") , @NamedQuery(name = "Room.findByCreation", query = "SELECT r FROM Room r WHERE r.creation = :creation") , @NamedQuery(name = "Room.findByTitle", query = "SELECT r FROM Room r WHERE r.title = :title") , @NamedQuery(name = "Room.findByPicture", query = "SELECT r FROM Room r WHERE r.picture = :picture") }) @Customizer(PersonsFilterForRoom.class) public class Room implements Serializable, DisplayInterface, ItemWrangler, AttributeWrangler, Ownage { private static final Logger itsLog = Logger.getLogger(Room.class.getName()); /** * The first room that new characters appear in. */ public static final Integer STARTERS_ROOM = 1; private static final long serialVersionUID = 1L; @Id @Basic(optional = false) @NotNull @Column(name = "id") private Integer id; @Basic(optional = false) @NotNull @Lob @Size(min = 1, max = 65535) @Column(name = "contents") private String contents; @Basic(optional = false) @NotNull @Column(name = "creation") @Temporal(TemporalType.TIMESTAMP) private Date creation; @Basic(optional = false) @NotNull @Size(min = 1, max = 120) @Column(name = "title") private String title; @Size(max = 120) @Column(name = "picture") private String picture; @JoinColumn(name = "owner", referencedColumnName = "name") @ManyToOne private Admin owner; @OneToMany(mappedBy = "down") private Collection<Room> roomCollection; @JoinColumn(name = "down", referencedColumnName = "id") @ManyToOne(fetch = FetchType.LAZY) private Room down; @OneToMany(mappedBy = "up") private Collection<Room> roomCollection1; @JoinColumn(name = "up", referencedColumnName = "id") @ManyToOne(fetch = FetchType.LAZY) private Room up; @OneToMany(mappedBy = "west") private Collection<Room> roomCollection2; @JoinColumn(name = "west", referencedColumnName = "id") @ManyToOne(fetch = FetchType.LAZY) private Room west; @OneToMany(mappedBy = "east") private Collection<Room> roomCollection3; @JoinColumn(name = "east", referencedColumnName = "id") @ManyToOne(fetch = FetchType.LAZY) private Room east; @OneToMany(mappedBy = "south") private Collection<Room> roomCollection4; @JoinColumn(name = "south", referencedColumnName = "id") @ManyToOne(fetch = FetchType.LAZY) private Room south; @OneToMany(mappedBy = "north") private Collection<Room> roomCollection5; @JoinColumn(name = "north", referencedColumnName = "id") @ManyToOne(fetch = FetchType.LAZY) private Room north; @JoinColumn(name = "area", referencedColumnName = "area") @ManyToOne(optional = false) private Area area; @OneToMany(cascade = CascadeType.ALL, mappedBy = "room", orphanRemoval = true) private Set<Roomattribute> attributes = new HashSet<>(); @OneToMany(cascade = CascadeType.ALL, mappedBy = "room") private Set<Item> items = new HashSet<>(); @OneToMany(cascade = CascadeType.ALL, mappedBy = "room") private Set<Person> persons = new HashSet<>(); @OneToMany(cascade = CascadeType.ALL, mappedBy = "room") private Set<Board> boards; public Room() { } public Room(Integer id) { this.id = id; } public Room(Integer id, String contents, Date creation, String title) { this.id = id; this.contents = contents; this.creation = creation; this.title = title; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } /** * A description of the room. * * @return */ public String getContents() { return contents; } /** * @see #getContents() * @param contents */ public void setContents(String contents) { this.contents = contents; } @Override public String getBody() { return contents; } public Date getCreation() { return creation; } public void setCreation(Date creation) { this.creation = creation; } public String getTitle() { return title; } @Override public String getMainTitle() { return getTitle(); } public void setTitle(String title) { this.title = title; } public String getPicture() { return picture; } @Override public String getImage() { return picture; } public void setPicture(String picture) { this.picture = picture; } @Override public Admin getOwner() { return owner; } @Override public void setOwner(Admin owner) { this.owner = owner; } public Collection<Room> getRoomCollection() { return roomCollection; } public void setRoomCollection(Collection<Room> roomCollection) { this.roomCollection = roomCollection; } public Room getDown() { return down; } public void setDown(Room down) { this.down = down; } public Collection<Room> getRoomCollection1() { return roomCollection1; } public void setRoomCollection1(Collection<Room> roomCollection1) { this.roomCollection1 = roomCollection1; } public Room getUp() { return up; } public void setUp(Room up) { this.up = up; } public Collection<Room> getRoomCollection2() { return roomCollection2; } public void setRoomCollection2(Collection<Room> roomCollection2) { this.roomCollection2 = roomCollection2; } public Room getWest() { return west; } public void setWest(Room west) { this.west = west; } public Collection<Room> getRoomCollection3() { return roomCollection3; } public void setRoomCollection3(Collection<Room> roomCollection3) { this.roomCollection3 = roomCollection3; } public Room getEast() { return east; } public void setEast(Room east) { this.east = east; } public Collection<Room> getRoomCollection4() { return roomCollection4; } public void setRoomCollection4(Collection<Room> roomCollection4) { this.roomCollection4 = roomCollection4; } public Room getSouth() { return south; } public void setSouth(Room south) { this.south = south; } public Collection<Room> getRoomCollection5() { return roomCollection5; } public void setRoomCollection5(Collection<Room> roomCollection5) { this.roomCollection5 = roomCollection5; } public Room getNorth() { return north; } public void setNorth(Room north) { this.north = north; } public Area getArea() { return area; } public void setArea(Area area) { this.area = area; } public Set<Roomattribute> getAttributes() { return attributes; } public void setAttributes(Set<Roomattribute> attributes) { this.attributes = attributes; } @Override public Set<Item> getItems() { return items; } public void setItems(Set<Item> items) { this.items = items; } /** * character communication method to everyone in the room. The message is * parsed, based on who is sending the message. * * @param aPerson the person who is the source of the message. * @param aMessage the message * * @see Person#writeMessage(mmud.database.entities.characters.Person, java.lang.String) */ public void sendMessage(Person aPerson, String aMessage) throws MudException { for (Person myChar : persons) { myChar.writeMessage(aPerson, aMessage); } } /** * character communication method to everyone in the room. The first person * is the source of the message. The second person is the target of the * message. The message is parsed based on the source and target. * Will also be sent to the person doing the communicatin' and * the target. * * @param aPerson the person doing the communicatin'. * @param aSecondPerson the person communicated to. * @param aMessage the message to be sent * @throws MudException if the room is not correct * @see Person#writeMessage(mmud.database.entities.characters.Person, * mmud.database.entities.characters.Person, java.lang.String) */ public void sendMessage(Person aPerson, Person aSecondPerson, String aMessage) throws MudException { for (Person myChar : persons) { myChar.writeMessage(aPerson, aSecondPerson, aMessage); } } /** * room communication method to everyone in the room. The message is not * parsed. Bear in mind that this method should only be used for * communication about environmental issues. If the communication originates * from a User/Person, you should use {@link #sendMessage(mmud.database.entities.characters.Person, java.lang.String) }. * Otherwise the Ignore functionality will be omitted. * * @param aMessage the message * @throws MudException if the room is not correct * @see Person#writeMessage(java.lang.String) */ public void sendMessage(String aMessage) throws MudException { for (Person myChar : persons) { myChar.writeMessage(aMessage); } } /** * character communication method to everyone in the room except to the two * persons mentioned in the header. The message is parsed based on the * source and target. * * @param aPerson the person doing the communicatin'. * @param aSecondPerson the person communicated to. * @param aMessage the message to be sent * @throws MudException if the room is not correct * @see Person#writeMessage(mmud.database.entities.characters.Person, * mmud.database.entities.characters.Person, java.lang.String) */ public void sendMessageExcl(Person aPerson, Person aSecondPerson, String aMessage) throws MudException { for (Person myChar : persons) { if (myChar != aPerson && myChar != aSecondPerson) { myChar.writeMessage(aPerson, aSecondPerson, aMessage); } } } /** * character communication method to everyone in the room excluded the * person mentioned in the parameters. The message is parsed, based on who * is sending the message. * * @param aPerson the person who is the source of the message. * @param aMessage the message * @throws MudException if the room is not correct * @see Person#writeMessage(mmud.database.entities.characters.Person, * java.lang.String) */ public void sendMessageExcl(Person aPerson, String aMessage) throws MudException { for (Person myChar : persons) { if (myChar != aPerson) { myChar.writeMessage(aPerson, aMessage); } } } @Override public int hashCode() { int hash = 0; hash += (id != null ? id.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof Room)) { return false; } Room other = (Room) object; if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) { return false; } return true; } @Override public String toString() { return "mmud.database.entities.game.Room[ id=" + id + " ]"; } /** * retrieve the character from the list of characters currently active in * the current room. * * @param aName name of the character to search for. Case matters not. * @return Character/Person in the room. Will return null pointer if * character not found. * @see #retrieveUser(java.lang.String) */ public Person retrievePerson(String aName) { for (Person person : persons) { if ((person.getName().equalsIgnoreCase(aName))) { return person; } } return null; } /** * retrieve the player from the list of characters currently active in * the current room. * * @param aName name of the player to search for. * @return Player in the room. Will return null pointer if * character not found or character is not a "real" player. * @see #retrievePerson(java.lang.String) */ public User retrieveUser(String aName) { Person person = retrievePerson(aName); if (person instanceof User) { return (User) person; } return null; } /** * retrieve the board in the room. May be null if there is no board. * * @param aName name of the board to search for. * @return Board in the room. Will return null pointer if * board not found. */ public Board getBoard(String aName) { for (Board board : boards) { if ((board.getName().equalsIgnoreCase(aName))) { return board; } } return null; } /** * Returns items if found, otherwise returns an empty list. * * @param parsed the parsed description of the item as given by the user, * for example {"light-green", "leather", "pants"}. * @return list of found items, empty if not found. */ public List<Item> findItems(List<String> parsed) { List<Item> result = new ArrayList<Item>(); for (Item item : getItems()) { if (item.isDescribedBy(parsed)) { result.add(item); } } return result; } @Override public boolean removeAttribute(String name) { Roomattribute attr = getRoomattribute(name); if (attr == null) { return false; } boolean result = attributes.remove(attr); return result; } @Override public Attribute getAttribute(String name) { return getRoomattribute(name); } @Override public void setAttribute(String name, String value) { Roomattribute attr = getRoomattribute(name); if (attr == null) { attr = new Roomattribute(name, getId()); attr.setRoom(this); } attr.setValue(value); attr.setValueType(Attributes.VALUETYPE_STRING); attributes.add(attr); } @Override public boolean verifyAttribute(String name, String value) { Roomattribute attr = getRoomattribute(name); if (attr == null) { itsLog.finer("verifyAttribute (name=" + name + ", value=" + value + ") not found on room " + getId() + "."); return false; } if (attr.getValue() == value) { itsLog.finer("verifyAttribute (name=" + name + ", value=" + value + ") same object on room " + getId() + "!"); return true; } if (attr.getValue().equals(value)) { itsLog.finer("verifyAttribute (name=" + name + ", value=" + value + ") matches on room " + getId() + "!"); return true; } itsLog.finer("verifyAttribute (name=" + name + ", value=" + value + ") with (name=" + attr.getName() + ", value=" + attr.getValue() + ") no match on room " + getId() + "."); return false; } private Roomattribute getRoomattribute(String name) { if (attributes == null) { itsLog.finer("getRoomattribute name=" + name + " collection is null"); return null; } for (Roomattribute attr : attributes) { itsLog.finer("getRoomattribute name=" + name + " attr=" + attr); if (attr.getName().equals(name)) { return attr; } } itsLog.finer("getRoomattribute name=" + name + " not found"); return null; } @Override public boolean destroyItem(Item item) { return items.remove(item); // note: as the collection is an orphan, the delete // on the set will take place automatically. } /** * A person, apparently, dropped this into the room. * * @param item the item he dropped. * @return boolean, true if it was added, false otherwise. */ public boolean drop(Item item) { return items.add(item); } public void get(Item item) { if (item == null || !items.contains(item)) { throw new ItemException("Item not found."); } if (!items.remove(item)) { throw new ItemException("Unable to remove item from room."); } } /** * Returns all persons in the room, can be bots or shopkeepers or normal * players. * * @param excluding this user is excluded. Can be null, in this case all * persons in the room are returned. * @return a list of persons in the room. */ public List<Person> getPersons(Person excluding) { List<Person> result = new ArrayList<>(); for (Person person : persons) { if (excluding == null || !person.getName().equals(excluding.getName())) { result.add(person); } } return result; } /** * Retrieves a specific person of the room, by (case-insensitive) name. * * @param name the name of the person to look for. * @return Person in the room, null if not found. */ public Person getPerson(String name) { for (Person person : persons) { if (person.getName().equalsIgnoreCase(name)) { return person; } } return null; } /** * Adds an {@link Item} to the room. * * @param item the new item. May not be null. * @return the new item, null if unable to add. */ @Override public Item addItem(Item item) { if (item.getBelongsTo() != null || item.getRoom() != null || item.getContainer() != null) { throw new MudException("Item already assigned."); } if (!items.add(item)) { return null; } item.assignTo(this); return item; } }