/** * 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 is this mission invalid with a given colony target, given that intermediate colonies are * excluded. * * @param aiUnit The <code>AIUnit</code> to check. * @param colony The potential target <code>Colony</code>. * @return A reason for mission invalidity, or null if none found. */ private static String invalidFullColonyReason(AIUnit aiUnit, Colony colony) { String reason = invalidTargetReason(colony, aiUnit.getUnit().getOwner()); return (reason != null) ? reason : (!aiUnit.getUnit().canCashInTreasureTrain(colony.getTile())) ? "cashin-impossible-at-location" : null; }
/** {@inheritDoc} */ @Override public Mission doMission(LogBuilder lb) { lb.add(tag); String reason = invalidReason(); if (isTargetReason(reason)) { return retargetMission(reason, lb); } else if (reason != null) { return lbFail(lb, false, reason); } for (; ; ) { // Go to the target. final Unit unit = getUnit(); Unit.MoveType mt = travelToTarget(getTarget(), CostDeciders.avoidSettlementsAndBlockingUnits(), lb); switch (mt) { case MOVE: // Arrived break; case MOVE_HIGH_SEAS: case MOVE_NO_MOVES: case MOVE_NO_REPAIR: case MOVE_ILLEGAL: return lbWait(lb); case MOVE_NO_ACCESS_EMBARK: case MOVE_NO_TILE: return this; default: return lbMove(lb, mt); } // Cash in now if: // - already in Europe // - or can never get there // - it is free to transport the treasure // - or there is no potential carrier to get the treasure to there // Otherwise, it is better to send to Europe. lbAt(lb); final AIUnit aiUnit = getAIUnit(); final Europe europe = getUnit().getOwner().getEurope(); if (unit.canCashInTreasureTrain()) { AIUnit aiCarrier = null; boolean cashin = unit.isInEurope() || europe == null || unit.getTransportFee() == 0; if (!cashin && aiUnit.getTransport() == null) { cashin = assignCarrier(lb) == null; } if (cashin) return (AIMessage.askCashInTreasureTrain(aiUnit)) ? lbDone(lb, false, "cashed in") : lbFail(lb, false, "cashin"); } return retargetMission("transport expected", lb); } }
/** * Why would this mission be invalid with the given unit? * * @param aiUnit The <code>AIUnit</code> to test. * @return A reason why the mission would be invalid with the unit, or null if none found. */ private static String invalidMissionReason(AIUnit aiUnit) { String reason = invalidAIUnitReason(aiUnit); if (reason != null) return reason; final Unit unit = aiUnit.getUnit(); return (!unit.canCarryTreasure()) ? "unit-cannot-carry-treasure" : (unit.getTreasureAmount() <= 0) ? "unit-treasure-nonpositive" : null; }
/** * Evaluate a potential cashin mission for a given unit and path. * * @param aiUnit The <code>AIUnit</code> to do the mission. * @param path A <code>PathNode</code> to take to the target. * @return A score for the proposed mission. */ public static int scorePath(AIUnit aiUnit, PathNode path) { Location loc; if (path == null || (loc = extractTarget(aiUnit, path)) == null || (loc instanceof Colony && invalidFullColonyReason(aiUnit, loc.getColony()) != null)) return Integer.MIN_VALUE; return aiUnit.getUnit().getTreasureAmount() / (path.getTotalTurns() + 1); }
/** * Why would this mission be invalid with the given AI unit and location? * * @param aiUnit The <code>AIUnit</code> to check. * @param loc The <code>Location</code> to check. * @return A reason for invalidity, or null if none found. */ public static String invalidReason(AIUnit aiUnit, Location loc) { String reason = invalidMissionReason(aiUnit); return (reason != null) ? reason : (loc instanceof Colony) ? invalidColonyReason(aiUnit, (Colony) loc) : (loc instanceof IndianSettlement) ? invalidTargetReason(loc, aiUnit.getUnit().getOwner()) : Mission.TARGETINVALID; }
/** * 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); }
private static IndianSettlement getHome(AIUnit aiUnit) { return aiUnit.getUnit().getHomeIndianSettlement(); }
/** * Checks if a unit is carrying a tribute. * * @param aiUnit The <code>AIUnit</code> to check. * @return True if the unit is carrying goods. */ private static boolean hasTribute(AIUnit aiUnit) { return aiUnit.getUnit().hasGoodsCargo(); }
/** * Why is this mission invalid with a given Europe target? * * @param aiUnit The <code>AIUnit</code> to check. * @param europe The potential target <code>Europe</code>. * @return A reason for mission invalidity, or null if none found. */ private static String invalidEuropeReason(AIUnit aiUnit, Europe europe) { return invalidTargetReason(europe, aiUnit.getUnit().getOwner()); }
/** * Why is this mission invalid with a given colony target, given that intermediate colonies are * included. * * @param aiUnit The <code>AIUnit</code> to check. * @param colony The potential target <code>Colony</code>. * @return A reason for mission invalidity, or null if none found. */ private static String invalidColonyReason(AIUnit aiUnit, Colony colony) { return invalidTargetReason(colony, aiUnit.getUnit().getOwner()); }