/** * Assign a carrier for this treasure. * * @param lb A <code>LogBuilder</code> to log to. * @return A suitable carrier <code>AIUnit</code>, to which this unit has been queued for * transport. */ private AIUnit assignCarrier(LogBuilder lb) { final AIUnit aiUnit = getAIUnit(); final Unit unit = getUnit(); final Player player = unit.getOwner(); final Europe europe = player.getEurope(); List<Unit> carriers = player.getCarriersForUnit(unit); if (carriers.isEmpty()) return null; // Pick the closest carrier and queue this unit. final Location here = unit.getLocation(); int turns = INFINITY; Unit closest = null; for (Unit c : carriers) { int t = c.getTurnsToReach(here); if (turns > t) { turns = t; closest = c; } } final AIMain aiMain = getAIMain(); TransportMission tm; AIUnit aiCarrier; if (closest != null && (aiCarrier = aiMain.getAIUnit(closest)) != null && (tm = aiCarrier.getMission(TransportMission.class)) != null) { setTarget(europe); aiUnit.changeTransport(aiCarrier); if (tm.forceCollection(aiUnit, lb)) { lb.add(" forced collection on ", aiCarrier.getUnit()); return aiCarrier; } } return null; }
/** * Why would an IndianDemandMission be invalid with the given unit and colony. * * @param aiUnit The <code>AIUnit</code> to test. * @param colony The <code>Colony</code> to test. * @return A reason why the mission would be invalid with the unit and colony or null if none * found. */ private static String invalidColonyReason(AIUnit aiUnit, Colony colony) { String reason = invalidTargetReason(colony); if (reason != null) return reason; final Unit unit = aiUnit.getUnit(); final Player owner = unit.getOwner(); Player targetPlayer = colony.getOwner(); switch (owner.getStance(targetPlayer)) { case UNCONTACTED: case PEACE: case ALLIANCE: return "bad-stance"; case WAR: case CEASE_FIRE: Tension tension = unit.getHomeIndianSettlement().getAlarm(targetPlayer); if (tension != null && tension.getLevel().compareTo(Tension.Level.CONTENT) <= 0) return "happy"; break; } return null; }
/** * Find a suitable cash in location for this unit. * * @param aiUnit The <code>AIUnit</code> to execute this mission. * @param range The maximum number of moves to search. * @param deferOK Enables deferring to a fallback colony. * @return A <code>PathNode</code> to the target, or null if not found which includes the case * when Europe should be preferred (because the unit can not get there by itself). */ private static PathNode findTargetPath(AIUnit aiUnit, int range, boolean deferOK) { if (invalidAIUnitReason(aiUnit) != null) return null; final Unit unit = aiUnit.getUnit(); final Location start = unit.getPathStartLocation(); final Player player = unit.getOwner(); final Europe europe = player.getEurope(); final Unit carrier = unit.getCarrier(); final CostDecider standardCd = CostDeciders.avoidSettlementsAndBlockingUnits(); PathNode path; if (player.getNumberOfSettlements() <= 0 || start == null) { // No settlements or not on the map, so go straight to // Europe. If Europe does not exist then this mission is // doomed. return (europe == null) ? null : unit.findPath(unit.getLocation(), europe, carrier, standardCd); } // Can the unit get to a cash in site? return unit.search(start, getGoalDecider(aiUnit, deferOK), standardCd, range, carrier); }
/** {@inheritDoc} */ @Override public Mission doMission(LogBuilder lb) { lb.add(tag); String reason = invalidReason(); if (reason != null) return lbFail(lb, false, reason); final AIUnit aiUnit = getAIUnit(); final Unit unit = getUnit(); final IndianSettlement is = unit.getHomeIndianSettlement(); Direction d; while (!this.demanded) { Unit.MoveType mt = travelToTarget(getTarget(), null, lb); switch (mt) { case MOVE_HIGH_SEAS: case MOVE_NO_MOVES: case MOVE_ILLEGAL: return lbWait(lb); case MOVE_NO_REPAIR: return lbFail(lb, false, AIUNITDIED); case MOVE_NO_TILE: return this; case ATTACK_SETTLEMENT: // Arrived? d = unit.getTile().getDirection(getTarget().getTile()); if (d != null) break; // Yes, arrived at target // Fall through case ATTACK_UNIT: // Something is blocking our path Location blocker = resolveBlockage(aiUnit, getTarget()); if (blocker == null) { moveRandomly(tag, null); continue; } d = unit.getTile().getDirection(blocker.getTile()); if (AIMessage.askAttack(aiUnit, d)) { return lbAttack(lb, blocker); } continue; default: return lbMove(lb, mt); } // Load the goods. lbAt(lb); Colony colony = (Colony) getTarget(); Player enemy = colony.getOwner(); Goods goods = selectGoods(colony); GoodsType type = (goods == null) ? null : goods.getType(); int amount = (goods == null) ? 0 : goods.getAmount(); if (goods == null) { if (!enemy.checkGold(1)) { return lbDone(lb, false, "empty handed"); } amount = enemy.getGold() / 20; if (amount == 0) amount = enemy.getGold(); } this.demanded = AIMessage.askIndianDemand(aiUnit, colony, type, amount); if (this.demanded && (goods == null || hasTribute())) { if (goods == null) { return lbDone(lb, false, "accepted tribute ", amount, " gold"); } lb.add(", accepted tribute ", goods); return lbRetarget(lb); } // Consider attacking if not content. int unitTension = (is == null) ? 0 : is.getAlarm(enemy).getValue(); int tension = Math.max(unitTension, unit.getOwner().getTension(enemy).getValue()); d = unit.getTile().getDirection(colony.getTile()); if (tension >= Tension.Level.CONTENT.getLimit() && d != null) { if (AIMessage.askAttack(aiUnit, d)) lbAttack(lb, colony); } return lbDone(lb, false, "refused at ", colony); } // Take the goods home for (; ; ) { Unit.MoveType mt = travelToTarget(getTarget(), CostDeciders.avoidSettlementsAndBlockingUnits(), lb); switch (mt) { case MOVE: // Arrived break; case MOVE_HIGH_SEAS: case MOVE_NO_MOVES: case MOVE_ILLEGAL: return lbWait(lb); case MOVE_NO_REPAIR: return lbFail(lb, false, AIUNITDIED); case MOVE_NO_TILE: return this; default: return lbMove(lb, mt); } // Unload the goods lbAt(lb); GoodsContainer container = unit.getGoodsContainer(); for (Goods goods : container.getCompactGoods()) { Goods tribute = container.removeGoods(goods.getType()); is.addGoods(tribute); } return lbDone(lb, false, "unloaded tribute"); } }