/** * 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.server.model; import java.util.List; import java.util.Random; import java.util.Set; import java.util.logging.Logger; import net.sf.freecol.common.model.Ability; import net.sf.freecol.common.model.FreeColGameObject; import net.sf.freecol.common.model.Game; import net.sf.freecol.common.model.GoodsContainer; import net.sf.freecol.common.model.GoodsType; import net.sf.freecol.common.model.IndianSettlement; import net.sf.freecol.common.model.Player; import net.sf.freecol.common.model.Specification; import net.sf.freecol.common.model.Tile; import net.sf.freecol.common.model.Unit; import net.sf.freecol.common.model.UnitType; import net.sf.freecol.common.util.Utils; import net.sf.freecol.server.control.ChangeSet; import net.sf.freecol.server.control.ChangeSet.See; /** * The server version of an Indian Settlement. */ public class ServerIndianSettlement extends IndianSettlement implements ServerModelObject { private static final Logger logger = Logger.getLogger(ServerIndianSettlement.class.getName()); public static final int MAX_HORSES_PER_TURN = 2; /** * Trivial constructor for all ServerModelObjects. */ public ServerIndianSettlement(Game game, String id) { super(game, id); } /** * Creates a new ServerIndianSettlement. * * @param game The <code>Game</code> in which this object belong. * @param owner The <code>Player</code> owning this settlement. * @param name The name for this settlement. * @param tile The location of the <code>IndianSettlement</code>. * @param isCapital True if settlement is tribe's capital * @param learnableSkill The skill that can be learned by * Europeans at this settlement. * @param spokenTo Indicates if any European scout has asked to * speak with the chief. * @param missionary The missionary in this settlement (or null). * @exception IllegalArgumentException if an invalid tribe or kind is given */ public ServerIndianSettlement(Game game, Player owner, String name, Tile tile, boolean isCapital, UnitType learnableSkill, Set<Player> spokenTo, Unit missionary) { super(game, owner, name, tile); setGoodsContainer(new GoodsContainer(game, this)); this.learnableSkill = learnableSkill; setCapital(isCapital); this.spokenTo = spokenTo; this.missionary = missionary; convertProgress = 0; updateWantedGoods(); } /** * New turn for this native settlement. * * @param random A <code>Random</code> number source. * @param cs A <code>ChangeSet</code> to update. */ public void csNewTurn(Random random, ChangeSet cs) { logger.finest("ServerIndianSettlement.csNewTurn, for " + toString()); ServerPlayer owner = (ServerPlayer) getOwner(); Specification spec = getSpecification(); // Produce goods. List<GoodsType> goodsList = spec.getGoodsTypeList(); for (GoodsType g : goodsList) { addGoods(g.getStoredAs(), getProductionOf(g)); } // Consume goods. for (GoodsType g : goodsList) { consumeGoods(g, getConsumptionOf(g)); } // Now check the food situation int storedFood = getGoodsCount(spec.getPrimaryFoodType()); if (storedFood <= 0 && getUnitCount() > 0) { Unit victim = Utils.getRandomMember(logger, "Choose starver", getUnitList(), random); cs.addDispose(See.only(owner), this, victim); logger.finest("Famine in " + getName()); } if (getUnitCount() <= 0) { cs.addDispose(See.perhaps().always(owner), getTile(), this); logger.info(getName() + " collapsed."); return; } // Check for new resident. // Alcohol also contributes to create children. GoodsType foodType = spec.getPrimaryFoodType(); GoodsType rumType = spec.getGoodsType("model.goods.rum"); List<UnitType> unitTypes = spec.getUnitTypesWithAbility(Ability.BORN_IN_INDIAN_SETTLEMENT); if (!unitTypes.isEmpty() && (getGoodsCount(foodType) + 4 * getGoodsCount(rumType) > FOOD_PER_COLONIST + KEEP_RAW_MATERIAL) && ownedUnits.size() <= getType().getMaximumSize()) { // Allow one more brave than the initially generated number. // This is more than sufficient. Do not increase the amount // without discussing it on the developer's mailing list first. UnitType type = Utils.getRandomMember(logger, "Choose birth", unitTypes, random); Unit unit = new ServerUnit(getGame(), getTile(), owner, type); consumeGoods(foodType, FOOD_PER_COLONIST); consumeGoods(rumType, FOOD_PER_COLONIST/4); // New units quickly go out of their city and start annoying. addOwnedUnit(unit); unit.setIndianSettlement(this); logger.info("New native created in " + getName() + " with ID=" + unit.getId()); } // Try to breed horses // TODO: Make this generic. GoodsType horsesType = spec.getGoodsType("model.goods.horses"); // TODO: remove this GoodsType grainType = spec.getGoodsType("model.goods.grain"); int foodProdAvail = getProductionOf(grainType) - getFoodConsumption(); if (getGoodsCount(horsesType) >= horsesType.getBreedingNumber() && foodProdAvail > 0) { int nHorses = Math.min(MAX_HORSES_PER_TURN, foodProdAvail); addGoods(horsesType, nHorses); logger.finest("Settlement " + getName() + " bred " + nHorses); } getGoodsContainer().removeAbove(getWarehouseCapacity()); updateWantedGoods(); cs.add(See.only(owner), this); } /** * Convenience function to remove an amount of goods. * * @param type The <code>GoodsType</code> to remove. * @param amount The amount of goods to remove. */ private void consumeGoods(GoodsType type, int amount) { if (getGoodsCount(type) > 0) { amount = Math.min(amount, getGoodsCount(type)); removeGoods(type, amount); } } /** * Modifies the alarm level towards the given player due to an event * at this settlement, and propagate the alarm upwards through the * tribe. * * @param player The <code>Player</code>. * @param addToAlarm The amount to add to the current alarm level. * @return A list of settlements whose alarm level has changed. */ public List<FreeColGameObject> modifyAlarm(Player player, int addToAlarm) { boolean change = makeContactSettlement(player); change |= changeAlarm(player, addToAlarm); // Propagate alarm upwards. Capital has a greater impact. List<FreeColGameObject> modified = owner.modifyTension(player, ((isCapital()) ? addToAlarm : addToAlarm/2), this); if (change && getTile().isExploredBy(player)) { modified.add(this); } logger.finest("Alarm at " + getName() + " toward " + player.getName() + " modified by " + Integer.toString(addToAlarm) + " now = " + Integer.toString(getAlarm(player).getValue())); return modified; } /** * Returns the tag name of the root element representing this object. * * @return "serverIndianSettlement" */ public String getServerXMLElementTagName() { return "serverIndianSettlement"; } }