/** * 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.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import org.freecolandroid.xml.stream.XMLStreamConstants; import org.freecolandroid.xml.stream.XMLStreamException; import org.freecolandroid.xml.stream.XMLStreamReader; import org.freecolandroid.xml.stream.XMLStreamWriter; /** * Represents one FoundingFather to be contained in a Player object. * The FoundingFather is able to grant new abilities or bonuses to the * player, or to cause certain events. */ public class FoundingFather extends FreeColGameObjectType { /** * The probability of this FoundingFather being offered for selection. */ private int[] weight = new int[4]; /** * The type of this FoundingFather. One of the following constants. */ private FoundingFatherType type; /** * Players that want to elect this founding father must match all * scopes. */ private List<Scope> scopes = new ArrayList<Scope>(); /** * Describe events here. */ private List<Event> events = new ArrayList<Event>(); /** * Holds the upgrades of Units caused by this FoundingFather. */ private Map<UnitType, UnitType> upgrades; public static enum FoundingFatherType { TRADE, EXPLORATION, MILITARY, POLITICAL, RELIGIOUS } /** * A list of AbstractUnits generated by this FoundingFather. */ private List<AbstractUnit> units = null; public FoundingFather(String id, Specification specification) { super(id, specification); setModifierIndex(Modifier.FATHER_PRODUCTION_INDEX); } /** * Return the type of this FoundingFather. * * @return The type of this FoundingFather. */ public FoundingFatherType getType() { return type; } /** * Return the type of this FoundingFather. * * @param type A new <code>FoundingFatherType</code>. */ public void setType(FoundingFatherType type) { this.type = type; } /** * Return the localized type of this FoundingFather. * * @return a <code>String</code> value */ public String getTypeKey() { return getTypeKey(type); } /** * Return the localized type of the given FoundingFather. * * @param type an <code>int</code> value * @return a <code>String</code> value */ public static String getTypeKey(FoundingFatherType type) { return "model.foundingFather." + type.toString().toLowerCase(Locale.US); } /** * Get the weight of this FoundingFather. This is used to select a * random FoundingFather. * * @param age an <code>int</code> value * @return an <code>int</code> value */ public int getWeight(int age) { switch(age) { case 1: return weight[1]; case 2: return weight[2]; case 3: default: return weight[3]; } } /** * Get the <code>Units</code> value. * * @return a <code>List<AbstractUnit></code> value */ public final List<AbstractUnit> getUnits() { return units; } /** * Set the <code>Units</code> value. * * @param newUnits The new Units value. */ public final void setUnits(final List<AbstractUnit> newUnits) { this.units = newUnits; } /** * Get the <code>Events</code> value. * * @return a <code>List<Event></code> value */ public final List<Event> getEvents() { return events; } /** * Set the <code>Events</code> value. * * @param newEvents The new Events value. */ public final void setEvents(final List<Event> newEvents) { this.events = newEvents; } /** * Get the <code>Scopes</code> value. * * @return a <code>List<Scope></code> value */ public final List<Scope> getScopes() { return scopes; } /** * Returns true if this <code>FoundingFather</code> is available * to the Player given. * * @param player a <code>Player</code> value * @return a <code>boolean</code> value */ public boolean isAvailableTo(Player player) { if (player.isEuropean()) { if (scopes == null || scopes.isEmpty()) { return true; } else { for (Scope scope : scopes) { if (scope.appliesTo(player)) { return true; } } } } return false; } /** * Get the <code>Upgrades</code> value. * * @return a <code>Map<UnitType, UnitType></code> value */ public final Map<UnitType, UnitType> getUpgrades() { return upgrades; } /** * Set the <code>Upgrades</code> value. * * @param newUpgrades The new Upgrades value. */ public final void setUpgrades(final Map<UnitType, UnitType> newUpgrades) { this.upgrades = newUpgrades; } /** * 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("type", type.toString().toLowerCase(Locale.US)); for (int index = 1; index <= 3; index++) { out.writeAttribute("weight" + index, Integer.toString(weight[index])); } } /** * 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); if (events != null) { for (Event event : events) { event.toXMLImpl(out); } } if (scopes != null) { for (Scope scope : scopes) { scope.toXMLImpl(out); } } if (units != null) { for (AbstractUnit unit : units) { out.writeStartElement("unit"); out.writeAttribute(ID_ATTRIBUTE_TAG, unit.getId()); //out.writeAttribute("role", unit.getRole().toString().toLowerCase(Locale.US)); //out.writeAttribute("number", String.valueOf(unit.getNumber())); out.writeEndElement(); } } if (upgrades != null) { for (Map.Entry<UnitType, UnitType> entry : upgrades.entrySet()) { out.writeStartElement("upgrade"); out.writeAttribute("from-id", entry.getKey().getId()); out.writeAttribute("to-id", entry.getValue().getId()); 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); String typeString = in.getAttributeValue(null, "type").toUpperCase(Locale.US); type = Enum.valueOf(FoundingFatherType.class, typeString); weight[1] = Integer.parseInt(in.getAttributeValue(null, "weight1")); weight[2] = Integer.parseInt(in.getAttributeValue(null, "weight2")); weight[3] = Integer.parseInt(in.getAttributeValue(null, "weight3")); } /** * 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 { while (in.nextTag() != XMLStreamConstants.END_ELEMENT) { readChild(in); } } /** * 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 childName = in.getLocalName(); if (Event.getXMLElementTagName().equals(childName)) { Event event = new Event(null, getSpecification()); event.readFromXML(in); events.add(event); } else if ("scope".equals(childName)) { scopes.add(new Scope(in)); } else if ("unit".equals(childName)) { // AbstractUnit closes element AbstractUnit unit = new AbstractUnit(in); if (units == null) { units = new ArrayList<AbstractUnit>(); } units.add(unit); } else if ("upgrade".equals(childName)) { UnitType fromType = getSpecification() .getUnitType(in.getAttributeValue(null, "from-id")); UnitType toType = getSpecification() .getUnitType(in.getAttributeValue(null, "to-id")); if (fromType != null && toType != null) { if (upgrades == null) { upgrades = new HashMap<UnitType, UnitType>(); } upgrades.put(fromType, toType); } in.nextTag(); } else { super.readChild(in); } } /** * Compatibility hack, called from the specification when it is * finishing up. * @compat 0.9.x */ public void fixup09x() { try { // Cortes has changed if (!getModifierSet("model.modifier.nativeTreasureModifier").isEmpty()) { addAbility(new Ability("model.ability.plunderNatives")); } } catch (Exception e) { // we don't care } } /** * Returns the tag name of the root element representing this object. * * @return "founding-father". */ public static String getXMLElementTagName() { return "founding-father"; } }