/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol 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.
*
* FreeCol 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 FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.common.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import net.sf.freecol.common.model.Unit.Role;
public class EquipmentType extends BuildableType {
public static final EquipmentType[] NO_EQUIPMENT = new EquipmentType[0];
/**
* The maximum number of equipment items that can be combined.
*/
private int maximumCount = 1;
/**
* Determines which type of Equipment will be lost first if the
* Unit carrying it is defeated. Horses should be lost before
* Muskets, for example.
*/
private int combatLossPriority;
/**
* What this equipment type becomes if it is captured by Indians
* (if captureEquipmentByIndians is true) or Europeans (otherwise).
*/
private String captureEquipmentId = null;
private boolean captureEquipmentByIndians = false;
/**
* The default Role of the Unit carrying this type of Equipment.
*/
private Role role;
/**
* Describe militaryEquipment here.
*/
private boolean militaryEquipment;
/**
* A List containing the IDs of equipment types compatible with this one.
*/
private List<String> compatibleEquipment = new ArrayList<String>();
public EquipmentType(String id, Specification specification) {
super(id, specification);
}
/**
* Get the <code>MaximumCount</code> value.
*
* @return an <code>int</code> value
*/
public final int getMaximumCount() {
return maximumCount;
}
/**
* Set the <code>MaximumCount</code> value.
*
* @param newMaximumCount The new MaximumCount value.
*/
public final void setMaximumCount(final int newMaximumCount) {
this.maximumCount = newMaximumCount;
}
/**
* Get the <code>Role</code> value.
*
* @return a <code>Role</code> value
*/
public final Role getRole() {
return role;
}
/**
* Set the <code>Role</code> value.
*
* @param newRole The new Role value.
*/
public final void setRole(final Role newRole) {
this.role = newRole;
}
/**
* Get the <code>CombatLossPriority</code> value.
*
* @return an <code>int</code> value
*/
public final int getCombatLossPriority() {
return combatLossPriority;
}
/**
* Set the <code>CombatLossPriority</code> value.
*
* @param newCombatLossPriority The new CombatLossPriority value.
*/
public final void setCombatLossPriority(final int newCombatLossPriority) {
this.combatLossPriority = newCombatLossPriority;
}
/**
* Returns true if this EquipmentType can be captured in combat.
*
* @return a <code>boolean</code> value
*/
public boolean canBeCaptured() {
return (combatLossPriority > 0);
}
/**
* Get the type of equipment to capture, handling the case where
* Europeans and Indians use different <code>EquipmentType</code>s
* for the same underlying goods.
*
* @param byIndians is the capture by the Indians?
*
* @return an <code>EquipmentType</code> value
*/
public EquipmentType getCaptureEquipment(boolean byIndians) {
return (captureEquipmentId != null
&& byIndians == captureEquipmentByIndians)
? getSpecification().getEquipmentType(captureEquipmentId)
: this;
}
/**
* Returns the abilities required by this Type.
*
* @return the abilities required by this Type.
*/
public Map<String, Boolean> getUnitAbilitiesRequired() {
return getAbilitiesRequired();
}
/**
* Returns true if this type of equipment is compatible with the
* given type of equipment.
*
* @param otherType an <code>EquipmentType</code> value
* @return a <code>boolean</code> value
*/
public boolean isCompatibleWith(EquipmentType otherType) {
if (this.getId().equals(otherType.getId())) {
// model.equipment.tools for example
return true;
}
return compatibleEquipment.contains(otherType.getId()) &&
otherType.compatibleEquipment.contains(getId());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((compatibleEquipment == null) ? 0 : compatibleEquipment
.hashCode());
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EquipmentType other = (EquipmentType) obj;
if (compatibleEquipment == null) {
if (other.compatibleEquipment != null)
return false;
} else if (!compatibleEquipment.equals(other.compatibleEquipment))
return false;
if (getId() == null) {
if (other.getId() != null)
return false;
} else if (!getId().equals(other.getId()))
return false;
return true;
}
/**
* Returns true if Equipment of this type grants an offence bonus
* or a defence bonus.
*
* @return a <code>boolean</code> value
*/
public final boolean isMilitaryEquipment() {
return militaryEquipment;
}
/**
* Set the <code>MilitaryEquipment</code> value.
*
* @param newMilitaryEquipment The new MilitaryEquipment value.
*/
public final void setMilitaryEquipment(final boolean newMilitaryEquipment) {
this.militaryEquipment = newMilitaryEquipment;
}
/**
* Makes an XML-representation of this object.
*
* @param out The output stream.
* @throws XMLStreamException if there are any problems writing to the
* stream.
*/
protected void toXMLImpl(XMLStreamWriter out) throws XMLStreamException {
super.toXML(out, getXMLElementTagName());
}
/**
* Write the attributes of this object to a stream.
*
* @param out The target stream.
* @throws XMLStreamException if there are any problems writing to
* the stream.
*/
@Override
protected void writeAttributes(XMLStreamWriter out)
throws XMLStreamException {
super.writeAttributes(out);
out.writeAttribute("maximum-count", Integer.toString(maximumCount));
out.writeAttribute("combat-loss-priority",
Integer.toString(combatLossPriority));
out.writeAttribute("role", role.toString().toLowerCase(Locale.US));
}
/**
* Write the children of this object to a stream.
*
* @param out The target stream.
* @throws XMLStreamException if there are any problems writing to
* the stream.
*/
@Override
protected void writeChildren(XMLStreamWriter out)
throws XMLStreamException {
super.writeChildren(out);
for (String compatible : compatibleEquipment) {
out.writeStartElement("compatible-equipment");
out.writeAttribute(ID_ATTRIBUTE_TAG, compatible);
out.writeEndElement();
}
if (captureEquipmentId != null) {
out.writeStartElement("capture-equipment");
out.writeAttribute(ID_ATTRIBUTE_TAG, captureEquipmentId);
out.writeAttribute("by-indians",
Boolean.toString(captureEquipmentByIndians));
out.writeEndElement();
}
}
/**
* Reads the attributes of this object from an XML stream.
*
* @param in The XML input stream.
* @throws XMLStreamException if a problem was encountered
* during parsing.
*/
@Override
protected void readAttributes(XMLStreamReader in)
throws XMLStreamException {
super.readAttributes(in);
maximumCount = getAttribute(in, "maximum-count", 1);
combatLossPriority = getAttribute(in, "combat-loss-priority", -1);
String roleString = getAttribute(in, "role", "default");
role = Enum.valueOf(Role.class, roleString.toUpperCase(Locale.US));
}
/**
* Reads the children of this object from an XML stream.
*
* @param in The XML input stream.
* @throws XMLStreamException if a problem was encountered
* during parsing.
*/
@Override
protected void readChildren(XMLStreamReader in) throws XMLStreamException {
super.readChildren(in);
for (Modifier modifier : getModifiers()) {
if (modifier.getId().equals(Modifier.OFFENCE) ||
modifier.getId().equals(Modifier.DEFENCE)) {
militaryEquipment = true;
for (AbstractGoods goods : getGoodsRequired()) {
goods.getType().setMilitaryGoods(true);
}
break;
}
}
}
/**
* Reads a child object.
*
* @param in The XML stream to read.
* @exception XMLStreamException if an error occurs
*/
@Override
protected void readChild(XMLStreamReader in) throws XMLStreamException {
String nodeName = in.getLocalName();
if ("required-location-ability".equals(nodeName)) {
// @compat 0.10.0
String abilityId = in.getAttributeValue(null, ID_ATTRIBUTE_TAG);
boolean value = getAttribute(in, VALUE_TAG, true);
getAbilitiesRequired().put(abilityId, value);
getSpecification().addAbility(abilityId);
in.nextTag(); // close this element
// end compatibility code
} else if ("compatible-equipment".equals(nodeName)) {
String equipmentId = in.getAttributeValue(null, ID_ATTRIBUTE_TAG);
compatibleEquipment.add(equipmentId);
in.nextTag(); // close this element
} else if ("capture-equipment".equals(nodeName)) {
captureEquipmentId = in.getAttributeValue(null, ID_ATTRIBUTE_TAG);
captureEquipmentByIndians = getAttribute(in, "by-indians", false);
in.nextTag();
} else {
super.readChild(in);
}
}
/**
* Returns the tag name of the root element representing this object.
*
* @return "equipment-type".
*/
public static String getXMLElementTagName() {
return "equipment-type";
}
}