/**
   * Calculates how much of the given goods type this settlement wants and should retain.
   *
   * @param type The <code>GoodsType</code>.
   * @return The amount of goods wanted.
   */
  protected int getWantedGoodsAmount(GoodsType type) {
    if (getUnitCount() <= 0) return 0;

    final Specification spec = getSpecification();
    final UnitType unitType = getFirstUnit().getType();
    final Role militaryRole =
        Role.getAvailableRoles(getOwner(), unitType, spec.getMilitaryRoles()).get(0);

    if (type.isMilitaryGoods()) {
      // Retain enough goods to fully arm.
      int need = 0;
      for (Unit u : ownedUnits) {
        if (u.getRole() == militaryRole) continue;
        List<AbstractGoods> required = u.getGoodsDifference(militaryRole, 1);
        need += AbstractGoods.getCount(type, required);
      }
      return need;
    }

    int consumption = getConsumptionOf(type);
    if (type == spec.getPrimaryFoodType()) {
      // Food is perishable, do not try to retain that much
      return Math.max(40, consumption * 3);
    }
    if (type.isTradeGoods() || type.isNewWorldLuxuryType() || type.isRefined()) {
      // Aim for 10 years supply, resupply is doubtful
      return Math.max(80, consumption * 20);
    }
    // Just keep some around
    return 2 * getUnitCount();
  }
  /**
   * Gets the goods this settlement is willing to sell.
   *
   * @param limit The maximum number of goods required.
   * @param unit The <code>Unit</code> that is trading.
   * @return A list of goods to sell.
   */
  public List<Goods> getSellGoods(int limit, Unit unit) {
    List<Goods> result = new ArrayList<>();
    List<Goods> settlementGoods = getCompactGoods();
    Collections.sort(settlementGoods, exportGoodsComparator);

    int count = 0;
    for (Goods goods : settlementGoods) {
      if (!willSell(goods.getType())) continue;
      int amount = goods.getAmount();
      int retain = getWantedGoodsAmount(goods.getType());
      if (retain >= amount) continue;
      amount -= retain;
      if (amount > GoodsContainer.CARGO_SIZE) {
        amount = GoodsContainer.CARGO_SIZE;
      }
      if (unit != null) {
        amount =
            Math.round(
                applyModifiers(
                    (float) amount,
                    getGame().getTurn(),
                    unit.getModifiers(Modifier.TRADE_VOLUME_PENALTY)));
      }
      if (amount < TRADE_MINIMUM_SIZE) continue;
      result.add(new Goods(getGame(), this, goods.getType(), amount));
      count++;
      if (count >= limit) break;
    }
    return result;
  }
 @Override
 public int compare(Goods goods1, Goods goods2) {
   int cmp;
   GoodsType t1 = goods1.getType();
   GoodsType t2 = goods2.getType();
   cmp = (((t2.isNewWorldGoodsType()) ? 1 : 0) - ((t1.isNewWorldGoodsType()) ? 1 : 0));
   if (cmp == 0) {
     int a1 = Math.min(goods2.getAmount(), GoodsContainer.CARGO_SIZE);
     int a2 = Math.min(goods1.getAmount(), GoodsContainer.CARGO_SIZE);
     cmp = getPriceToSell(t2, a2) - getPriceToSell(t1, a1);
     if (cmp == 0) {
       cmp = a2 - a1;
     }
   }
   return cmp;
 }
  /**
   * Gets the amount of gold this <code>IndianSettlment</code> is willing to sell the given <code>
   * Goods</code> for.
   *
   * <p>It is only meaningful to call this method from the server, since the settlement's {@link
   * GoodsContainer} is hidden from the clients.
   *
   * @param type The type of <code>Goods</code> to price.
   * @param amount The amount of <code>Goods</code> to price.
   * @return The price.
   */
  public int getPriceToSell(GoodsType type, int amount) {
    if (amount > GoodsContainer.CARGO_SIZE) {
      throw new IllegalArgumentException("Amount > " + GoodsContainer.CARGO_SIZE);
    }
    final int full = GOODS_BASE_PRICE + getType().getTradeBonus();

    // Base price is purchase price plus delta.
    // - military goods at double value
    // - trade goods at +50%
    int price = amount + Math.max(0, 11 * getPriceToBuy(type, amount) / 10);
    if (type.isMilitaryGoods()) {
      price = Math.max(price, amount * full * 2);
    } else if (type.isTradeGoods()) {
      price = Math.max(price, 150 * amount * full / 100);
    }
    return price;
  }
  /** {@inheritDoc} */
  @Override
  public int getImportAmount(GoodsType goodsType, int turns) {
    if (goodsType.limitIgnored()) return Integer.MAX_VALUE;

    int present = Math.max(0, getGoodsCount(goodsType) - turns * getTotalProductionOf(goodsType));
    int capacity = getWarehouseCapacity();
    return capacity - present;
  }
 /**
  * Add some initial goods to a newly generated settlement. After all, they have been here for some
  * time.
  *
  * @param random A pseudo-random number source.
  */
 public void addRandomGoods(Random random) {
   HashMap<GoodsType, Integer> goodsMap = new HashMap<>();
   for (Tile t : getOwnedTiles()) {
     for (AbstractGoods ag : t.getSortedPotential()) {
       GoodsType type = ag.getType().getStoredAs();
       Integer i = goodsMap.get(type);
       int value = (i == null) ? 0 : i;
       goodsMap.put(type, value + ag.getAmount());
     }
   }
   double d = randomInt(logger, "Goods at " + getName(), random, 10) * 0.1 + 1.0;
   for (Entry<GoodsType, Integer> e : goodsMap.entrySet()) {
     int i = e.getValue();
     if (!e.getKey().isFoodType()) i = (int) Math.round(d * e.getValue());
     i = Math.min(i, GoodsContainer.CARGO_SIZE);
     if (i > 0) addGoods(e.getKey(), i);
   }
 }
  /**
   * Price some goods according to the amount present in the settlement.
   *
   * @param type The type of goods for sale.
   * @param amount The amount of goods for sale.
   * @return A price for the goods.
   */
  private int getNormalGoodsPriceToBuy(GoodsType type, int amount) {
    final int tradeGoodsAdd = 20; // Fake additional trade goods present
    final int capacity = getGoodsCapacity();
    int current = getGoodsCount(type);

    // Increase effective stock if its raw material is produced here.
    GoodsType rawType = type.getInputType();
    if (rawType != null) {
      int rawProduction = getMaximumProduction(rawType);
      int add =
          (rawProduction < 5)
              ? 10 * rawProduction
              : (rawProduction < 10)
                  ? 5 * rawProduction + 25
                  : (rawProduction < 20) ? 2 * rawProduction + 55 : 100;
      // Decrease bonus in proportion to current stock, up to capacity.
      add = add * Math.max(0, capacity - current) / capacity;
      current += add;
    } else if (type.isTradeGoods()) {
      // Small artificial increase of the trade goods stored.
      current += tradeGoodsAdd;
    }

    // Only interested in the amount of goods that keeps the
    // total under the threshold.
    int retain = Math.min(getWantedGoodsAmount(type), capacity);
    int valued = (retain <= current) ? 0 : Math.min(amount, retain - current);

    // Unit price then is maximum price plus the bonus for the
    // settlement type, reduced by the proportion of goods present.
    int unitPrice =
        (GOODS_BASE_PRICE + getType().getTradeBonus()) * Math.max(0, capacity - current) / capacity;

    // But farmed goods are always less interesting.
    // and small settlements are not interested in building.
    if (type.isFarmed() || type.isRawBuildingMaterial()) unitPrice /= 2;

    // Only pay for the portion that is valued.
    return (unitPrice < 0) ? 0 : valued * unitPrice;
  }
 /**
  * Gets a random goods gift from this settlement.
  *
  * @param random A pseudo random number source.
  * @return A random goods gift, or null if none found.
  */
 public Goods getRandomGift(Random random) {
   List<Goods> goodsList = new ArrayList<>();
   for (GoodsType type : getSpecification().getNewWorldGoodsTypeList()) {
     int n = getGoodsCount(type) - KEEP_RAW_MATERIAL;
     if (n >= GIFT_THRESHOLD) {
       n -= GIFT_MINIMUM;
       Goods goods =
           new Goods(
               getGame(),
               this,
               type,
               Math.min(randomInt(logger, "Gift amount", random, n) + GIFT_MINIMUM, GIFT_MAXIMUM));
       goodsList.add(goods);
     }
   }
   return (goodsList.isEmpty()) ? null : getRandomMember(logger, "Gift type", goodsList, random);
 }
  /**
   * Price some goods that have military value to the settlement.
   *
   * @param type The type of goods for sale.
   * @param amount The amount of goods for sale.
   * @return A price for the goods.
   */
  private int getMilitaryGoodsPriceToBuy(GoodsType type, int amount) {
    final int full = GOODS_BASE_PRICE + getType().getTradeBonus();
    int required = getWantedGoodsAmount(type);
    if (required == 0) return 0; // Do not pay military price

    // If the settlement can use more than half of the goods on offer,
    // then pay top dollar for the lot.  Otherwise only pay the premium
    // price for the part they need and refer the remaining amount to
    // the normal goods pricing.
    int valued = Math.max(0, required - getGoodsCount(type));
    int price =
        (valued > amount / 2)
            ? full * amount
            : valued * full + getNormalGoodsPriceToBuy(type, amount - valued);
    logger.finest(
        "Military price(" + amount + " " + type + ")" + " valued=" + valued + " -> " + price);
    return price;
  }
Exemple #10
0
  /** {@inheritDoc} */
  @Override
  public int getTotalProductionOf(GoodsType type) {
    if (type.isRefined()) {
      if (type != goodsToMake()) return 0;
      // Pretend 1/3 of the units present make the item with
      // basic production of 3.
      return getUnitCount();
    }

    int potential = 0;
    int tiles = 0;

    for (Tile workTile : getOwnedTiles()) {
      if (workTile != getTile() && !workTile.isOccupied()) {
        // FIXME: make unitType brave
        potential += workTile.getPotentialProduction(type, null);
        tiles++;
      }
    }

    // When a native settlement has more tiles than units, pretend
    // that they produce from their entire area at reduced
    // efficiency.
    if (tiles > getUnitCount()) {
      potential *= (float) getUnitCount() / tiles;
    }

    // Raw production is too generous, apply a fudge factor to reduce it
    // a bit for the non-food cases.
    if (!type.isFoodType()) {
      potential = (int) Math.round(potential * NATIVE_PRODUCTION_EFFICIENCY);
    }

    // But always add full potential of the center tile.
    potential += getTile().getPotentialProduction(type, null);
    return potential;
  }
Exemple #11
0
 /** {@inheritDoc} */
 @Override
 public int getExportAmount(GoodsType goodsType, int turns) {
   int present = Math.max(0, getGoodsCount(goodsType) + turns * getTotalProductionOf(goodsType));
   int wanted = getWantedGoodsAmount(goodsType);
   return present - wanted;
 }