/**
* 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.networking;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.freecolandroid.xml.stream.XMLStreamException;
import net.sf.freecol.FreeCol;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.common.model.AbstractUnit;
import net.sf.freecol.common.model.BuildableType;
import net.sf.freecol.common.model.Colony;
import net.sf.freecol.common.model.DiplomaticTrade;
import net.sf.freecol.common.model.EquipmentType;
import net.sf.freecol.common.model.ExportData;
import net.sf.freecol.common.model.FreeColGameObject;
import net.sf.freecol.common.model.Game;
import net.sf.freecol.common.model.Goods;
import net.sf.freecol.common.model.GoodsType;
import net.sf.freecol.common.model.HighScore;
import net.sf.freecol.common.model.Location;
import net.sf.freecol.common.model.Map.Direction;
import net.sf.freecol.common.model.Monarch.MonarchAction;
import net.sf.freecol.common.model.NationSummary;
import net.sf.freecol.common.model.Player;
import net.sf.freecol.common.model.Region;
import net.sf.freecol.common.model.Settlement;
import net.sf.freecol.common.model.Tile;
import net.sf.freecol.common.model.TileImprovementType;
import net.sf.freecol.common.model.TradeRoute;
import net.sf.freecol.common.model.Unit;
import net.sf.freecol.common.model.Unit.UnitState;
import net.sf.freecol.common.model.UnitType;
import net.sf.freecol.common.model.WorkLocation;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* The API for client->server messaging.
*/
public class ServerAPI {
private static final Logger logger = Logger.getLogger(ServerAPI.class.getName());
private FreeColClient freeColClient; // cached client reference
/**
* Creates a new <code>ServerAPI</code>.
*
* @param freeColClient The <code>FreeColClient</code> that is
* communicating with a server.
*/
public ServerAPI(FreeColClient freeColClient) {
this.freeColClient = freeColClient;
}
/** Temporary trivial message wrapper. */
private class TrivialMessage extends DOMMessage {
private String tag;
private String[] attributes;
public TrivialMessage(String tag, String... attributes) {
this.tag = tag;
this.attributes = attributes;
}
public Element toXMLElement() {
Element e = createNewRootElement(tag);
for (int i = 0; i < attributes.length; i += 2) {
e.setAttribute(attributes[i], attributes[i+1]);
}
return e;
}
};
/**
* Helper to load a map.
*
* @param queries Query strings.
* @return A map with null mappings for the query strings.
*/
private HashMap<String, String> loadMap(String... queries) {
HashMap<String, String> result = new HashMap<String, String>();
for (String q : queries) result.put(q, null);
return result;
}
/**
* Sends a DOMMessage to the server.
*
* @param message The <code>DOMMessage</code> to send.
* @return True if the send succeeded.
*/
private boolean send(DOMMessage message) {
freeColClient.getClient().send(message.toXMLElement());
return true;
}
/**
* Sends the specified message to the server and returns the reply,
* if it has the specified tag.
* Handle "error" replies if they have a messageID or when in debug mode.
* This routine allows code simplification in much of the following
* client-server communication.
*
* In following routines we follow the convention that server I/O
* is confined to the ask<foo>() routine, which typically returns
* true if the server interaction succeeded, which does *not*
* necessarily imply that the actual substance of the request was
* allowed (e.g. a move may result in the death of a unit rather
* than actually moving).
*
* @param message A <code>DOMMessage</code> to send.
* @param tag The expected tag
* @param results A <code>Map</code> to store special attribute results in.
* @return The answer from the server if it has the specified tag,
* otherwise <code>null</code>.
*/
private Element askExpecting(DOMMessage message, String tag,
HashMap<String, String> results) {
Element request = message.toXMLElement();
Element reply;
try {
reply = freeColClient.getClient().getConnection()
.askDumping(request);
} catch (IOException e) {
logger.log(Level.WARNING, "Could not send \""
+ request.getTagName() + "\"-message.", e);
reply = null;
}
if (reply == null) return null;
if ("error".equals(reply.getTagName())) {
String messageId = reply.getAttribute("messageID");
String messageText = reply.getAttribute("message");
if (messageId != null && messageText != null
&& FreeCol.isInDebugMode()) {
// If debugging suppress the bland but i18n compliant
// failure message in favour of the higher detail
// non-i18n text.
reply.removeAttribute("messageID");
}
if (messageId == null && messageText == null) {
logger.warning("Received null error response");
} else {
logger.warning("Received error response: "
+ ((messageId != null) ? messageId : "")
+ "/" + ((messageText != null)
? messageText : ""));
handleReply(reply);
}
return null;
}
// Success!
if (tag == null || tag.equals(reply.getTagName())) {
// Do the standard processing.
String sound = reply.getAttribute("sound");
if (sound != null && !sound.isEmpty()) {
freeColClient.getGUI().playSound(sound);
}
// Look for special attributes
if (results != null) {
if (results.containsKey("*")) {
results.remove("*");
int len = reply.getAttributes().getLength();
for (int i = 0; i < len; i++) {
Node n = reply.getAttributes().item(i);
results.put(n.getNodeName(), n.getNodeValue());
}
} else {
for (String k : results.keySet()) {
if (reply.hasAttribute(k)) {
results.put(k, reply.getAttribute(k));
}
}
}
}
return reply;
}
// Unexpected reply. Whine and fail.
String complaint = "Received reply with tag " + reply.getTagName()
+ " which should have been " + tag
+ " to message " + message;
logger.warning(complaint);
if (FreeCol.isInDebugMode()) {
freeColClient.getGUI().errorMessage(null, complaint);
}
return null;
}
/**
* Handle a reply element using the client input handler.
*
* @param reply The reply <code>Element</code> to handle.
*/
private void handleReply(Element reply) {
if (reply != null) {
freeColClient.getInGameInputHandler()
.handle(freeColClient.getClient().getConnection(), reply);
}
}
/**
* Extends askExpecting to also handle returns from the server.
*
* @param message A <code>DOMMessage</code> to send.
* @param tag The expected tag
* @param results A <code>Map</code> to store special attribute results in.
* @return True if the server interaction succeeded, else false.
*/
private boolean askHandling(DOMMessage message, String tag,
HashMap<String, String> results) {
Element reply = askExpecting(message, tag, results);
if (reply == null) return false;
handleReply(reply);
return true;
}
// Public interface
/**
* Server query-response to abandon a colony.
*
* @param colony The <code>Colony</code> to abandon.
* @return True if the server interaction succeeded.
*/
public boolean abandonColony(Colony colony) {
return askHandling(new AbandonColonyMessage(colony),
null, null);
}
/**
* Server query-response to respond to a monarch offer.
*
* @param action The monarch action responded to.
* @param accept Accept or reject the offer.
* @return True if the server interaction succeeded.
*/
public boolean answerMonarch(MonarchAction action, boolean accept) {
return askHandling(new TrivialMessage("monarchAction",
"action", action.toString(),
"accepted", Boolean.toString(accept)),
null, null);
}
/**
* Server query-response for finding out the skill taught at a settlement.
*
* @param unit The <code>Unit</code> that is asking.
* @param direction The direction to a settlement to ask.
* @return True if the server interaction succeeded.
*/
public boolean askSkill(Unit unit, Direction direction) {
return askHandling(new AskSkillMessage(unit, direction),
null, null);
}
/**
* Server query-response for assigning a teacher.
*
* @param student The student <code>Unit</code>.
* @param teacher The teacher <code>Unit</code>.
* @return True if the server interaction succeeded.
*/
public boolean assignTeacher(Unit student, Unit teacher) {
return askHandling(new AssignTeacherMessage(student, teacher),
null, null);
}
/**
* Server query-response for assigning a trade route to a unit.
*
* @param unit The <code>Unit</code> to assign a trade route to.
* @param tradeRoute The <code>TradeRoute</code> to assign.
* @return True if the server interaction succeeded.
*/
public boolean assignTradeRoute(Unit unit, TradeRoute tradeRoute) {
return askHandling(new AssignTradeRouteMessage(unit, tradeRoute),
null, null);
}
/**
* Server query-response for attacking.
*
* @param unit The <code>Unit</code> to perform the attack.
* @param direction The direction in which to attack.
* @return True if the server interaction succeeded.
*/
public boolean attack(Unit unit, Direction direction) {
return askHandling(new AttackMessage(unit, direction),
null, null);
}
/**
* Server query-response for building a colony.
*
* @param name The name for the colony.
* @param unit The <code>Unit</code> that will build.
* @return True if the server interaction succeeded.
*/
public boolean buildColony(String name, Unit unit) {
return askHandling(new BuildColonyMessage(name, unit),
null, null);
}
/**
* Server query-response to buy the given goods from the natives.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @param goods The <code>Goods</code> to buy.
* @param gold The agreed price.
* @return True if the server interaction succeeded.
*/
public boolean buyFromSettlement(Unit unit, Settlement settlement,
Goods goods, int gold) {
return askHandling(new BuyMessage(unit, settlement, goods, gold),
null, null);
}
/**
* Server query-response for buying goods in Europe.
*
* @param carrier The <code>Unit</code> to load with the goods.
* @param type The type of goods to buy.
* @param amount The amount of goods to buy.
* @return True if the server interaction succeeded.
*/
public boolean buyGoods(Unit carrier, GoodsType type, int amount) {
return askHandling(new BuyGoodsMessage(carrier, type, amount),
null, null);
}
/**
* Server query-response to ask the natives if a purchase is acceptable.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @param goods The <code>Goods</code> to trade.
* @param gold The proposed price (including query on negative).
* @return The price of the goods.
*/
public int buyProposition(Unit unit, Settlement settlement,
Goods goods, int gold) {
HashMap<String, String> results = loadMap("gold");
if (askHandling(new BuyPropositionMessage(unit, settlement,
goods, gold), null, results)) {
try {
return Integer.parseInt(results.get("gold"));
} catch (NumberFormatException e) {}
}
return NetworkConstants.NO_TRADE;
}
/**
* Server query-response to cash in a treasure train.
*
* @param unit The treasure train <code>Unit</code> to cash in.
* @return True if the server interaction succeeded.
*/
public boolean cashInTreasureTrain(Unit unit) {
return askHandling(new CashInTreasureTrainMessage(unit),
null, null);
}
/**
* Server query-response for changing unit state.
*
* @param unit The <code>Unit</code> to change the state of.
* @param state The new <code>UnitState</code>.
* @return boolean <b>true</b> if the server interaction succeeded.
*/
public boolean changeState(Unit unit, UnitState state) {
return askHandling(new ChangeStateMessage(unit, state),
null, null);
}
/**
* Server query-response for changing work improvement type.
*
* @param unit The <code>Unit</code> to change the work type of.
* @param type The new <code>TileImprovementType</code> to work on.
* @return True if the server interaction succeeded.
*/
public boolean changeWorkImprovementType(Unit unit,
TileImprovementType type) {
return askHandling(new ChangeWorkImprovementTypeMessage(unit, type),
null, null);
}
/**
* Server query-response for changing work type.
*
* @param unit The <code>Unit</code> to change the work type of.
* @param workType The new <code>GoodsType</code> to produce.
* @return True if the server interaction succeeded.
*/
public boolean changeWorkType(Unit unit, GoodsType workType) {
return askHandling(new ChangeWorkTypeMessage(unit, workType),
null, null);
}
/**
* Server query-response for checking the high score.
*
* @return True if the player has achieved a new high score.
*/
public boolean checkHighScore() {
HashMap<String, String> results = loadMap("highScore");
return (askHandling(new TrivialMessage("checkHighScore"),
null, results)
&& results.get("highScore") != null)
? Boolean.parseBoolean(results.get("highScore"))
: false;
}
/**
* Server query-response to claim a piece of land.
*
* @param tile The land to claim.
* @param colony An optional <code>Colony</code> to own the land.
* @param price The amount to pay.
* @return True if the server interaction succeeded.
*/
public boolean claimLand(Tile tile, Colony colony, int price) {
return askHandling(new ClaimLandMessage(tile, colony, price),
null, null);
}
/**
* Server query-response for clearing a unit speciality.
*
* @param unit The <code>Unit</code> to operate on.
* @return True if the server interaction succeeded.
*/
public boolean clearSpeciality(Unit unit) {
return askHandling(new ClearSpecialityMessage(unit),
null, null);
}
/**
* Server query-response to close a transaction session for a trade.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @return True if the server interaction succeeded.
*/
public boolean closeTransactionSession(Unit unit, Settlement settlement) {
return askHandling(new CloseTransactionMessage(unit, settlement),
null, null);
}
/**
* Send a chat message.
*
* @param chat The text of the message.
* @return True if the send succeeded.
*/
public boolean chat(String chat) {
return send(new ChatMessage(freeColClient.getMyPlayer(), chat, false));
}
/**
* Server query-response for declaring independence.
*
* @param nation The name for the new nation.
* @param country The name for the new country.
* @return True if the server interaction succeeded.
*/
public boolean declareIndependence(String nation, String country) {
return askHandling(new DeclareIndependenceMessage(nation, country),
null, null);
}
/**
* Server query-response for the special case of deciding to
* explore a rumour but then declining not to investigate the
* strange mounds.
*
* @param unit The <code>Unit</code> that is exploring.
* @param direction The <code>Direction</code> to move.
* @return True if the server interaction succeeded.
*/
public boolean declineMounds(Unit unit, Direction direction) {
return askHandling(new DeclineMoundsMessage(unit, direction),
null, null);
}
/**
* Server query-response to give the given goods to the natives.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @param goods The <code>Goods</code> to give.
* @return True if the server interaction succeeded.
*/
public boolean deliverGiftToSettlement(Unit unit, Settlement settlement,
Goods goods) {
return askHandling(new DeliverGiftMessage(unit, settlement, goods),
null, null);
}
/**
* Server query-response for demanding a tribute from a native
* settlement.
*
* @param unit The <code>Unit</code> that demands.
* @param direction The direction to demand in.
* @return True if the server interaction succeeded.
*/
public boolean demandTribute(Unit unit, Direction direction) {
return askHandling(new DemandTributeMessage(unit, direction),
null, null);
}
/**
* Handler server query-response for diplomatic messages.
*
* @param unit The <code>Unit</code> conducting the diplomacy.
* @param settlement The <code>Settlement</code> to negotiate with.
* @param agreement The <code>DiplomaticTrade</code> agreement to propose.
* @return The resulting agreement or null if none present.
*/
public DiplomaticTrade diplomacy(Unit unit, Settlement settlement,
DiplomaticTrade agreement) {
Element reply = askExpecting(new DiplomacyMessage(unit, settlement,
agreement),
null, null);
if (reply == null) return null;
if (DiplomacyMessage.getXMLElementTagName().equals(reply.getTagName())) {
Game game = freeColClient.getGame();
return new DiplomacyMessage(game, reply).getAgreement();
}
handleReply(reply);
return null;
}
/**
* Server query-response for disbanding a unit.
*
* @param unit The <code>Unit</code> to operate on.
* @return True if the server interaction succeeded.
*/
public boolean disbandUnit(Unit unit) {
return askHandling(new DisbandUnitMessage(unit),
null, null);
}
/**
* Server query-response for disembarking from a carrier.
*
* @param unit The <code>Unit</code> that is disembarking.
* @return True if the server interaction succeeded.
*/
public boolean disembark(Unit unit) {
return askHandling(new DisembarkMessage(unit),
null, null);
}
/**
* Server query-response for boarding a carrier.
*
* @param unit The <code>Unit</code> that is boarding.
* @param carrier The carrier <code>Unit</code>.
* @param direction An optional direction if the unit is boarding from
* an adjacent tile, or null if from the same tile.
* @return True if the server interaction succeeded.
*/
public boolean embark(Unit unit, Unit carrier, Direction direction) {
return askHandling(new EmbarkMessage(unit, carrier, direction),
null, null);
}
/**
* Server query-response for emigration.
*
* @param slot The slot from which the unit migrates, 1-3 selects
* a specific one, otherwise the server will choose one.
* @return True if the client-server interaction succeeded.
*/
public boolean emigrate(int slot) {
return askHandling(new EmigrateUnitMessage(slot),
null, null);
}
/**
* Server query-response for asking for the turn to end.
*
* @return True if the server interaction succeeded.
*/
public boolean endTurn() {
return askHandling(new TrivialMessage("endTurn"),
null, null);
}
/**
* Server query-response for asking to enter revenge mode.
*
* @return True if the server interaction succeeded.
*/
public boolean enterRevengeMode() {
return askHandling(new TrivialMessage("enterRevengeMode"),
null, null);
}
/**
* Server query-response for equipping a unit.
*
* @param unit The <code>Unit</code> to equip on.
* @param type The <code>EquipmentType</code> to equip with.
* @param amount The amount of equipment.
* @return True if the server interaction succeeded.
*/
public boolean equipUnit(Unit unit, EquipmentType type, int amount) {
return askHandling(new EquipUnitMessage(unit, type, amount),
null, null);
}
/**
* Server query-response for asking for the high scores list.
*
* @return The list of high scores.
*/
public List<HighScore> getHighScores() {
Element reply = askExpecting(new TrivialMessage("getHighScores"),
null, null);
if (reply == null) return Collections.emptyList();
List<HighScore> result = new ArrayList<HighScore>();
NodeList childElements = reply.getChildNodes();
for (int i = 0; i < childElements.getLength(); i++) {
try {
HighScore score = new HighScore((Element)childElements.item(i));
result.add(score);
} catch (XMLStreamException e) {
logger.warning("Unable to read score element: "
+ e.getMessage());
}
}
return result;
}
/**
* Server query-response for creating a new trade route.
*
* @return True if the server interaction succeeded.
*/
public boolean getNewTradeRoute() {
return askHandling(new TrivialMessage("getNewTradeRoute"),
null, null);
}
/**
* Server query-response for asking about a players REF.
*
* @return A list of REF units for the player.
*/
public List<AbstractUnit> getREFUnits() {
Element reply = askExpecting(new TrivialMessage("getREFUnits"),
null, null);
if (reply == null) return Collections.emptyList();
List<AbstractUnit> result = new ArrayList<AbstractUnit>();
NodeList childElements = reply.getChildNodes();
for (int index = 0; index < childElements.getLength(); index++) {
AbstractUnit unit = new AbstractUnit();
unit.readFromXMLElement((Element) childElements.item(index));
result.add(unit);
}
return result;
}
/**
* Server query-response to get a list of goods for sale from a settlement.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @return The goods for sale in the settlement,
* or null if the server interaction failed.
*/
public List<Goods> getGoodsForSaleInSettlement(Unit unit,
Settlement settlement) {
GoodsForSaleMessage message
= new GoodsForSaleMessage(unit, settlement, null);
Element reply = askExpecting(message,
GoodsForSaleMessage.getXMLElementTagName(), null);
if (reply == null) return null;
Game game = freeColClient.getGame();
List<Goods> goodsOffered = new ArrayList<Goods>();
NodeList childNodes = reply.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
goodsOffered.add(new Goods(game, (Element) childNodes.item(i)));
}
return goodsOffered;
}
/**
* Server query-response for asking for the server statistics.
*
* @return The server statistics.
*/
public java.util.Map<String, String> getStatistics() {
HashMap<String, String> results = loadMap("*");
return (askExpecting(new TrivialMessage("getStatistics"),
"statistics", results) == null) ? null
: results;
}
/**
* Server query-response for inciting the natives.
*
* @param unit The missionary <code>Unit</code>.
* @param direction The direction to a settlement to speak to.
* @param enemy An enemy <code>Player</code>.
* @param gold The amount of bribe, negative to enquire.
* @return The amount of gold to bribe with if this was an inquiry,
* zero for failure to incite and >0 for successful incitement,
* negative if the server interaction failed.
*/
public int incite(Unit unit, Direction direction, Player enemy, int gold) {
HashMap<String, String> results = loadMap("gold");
if (!askHandling(new InciteMessage(unit, direction, enemy, gold),
null, results)) return -1;
try {
return Integer.parseInt(results.get("gold"));
} catch (NumberFormatException e) {}
return -1;
}
/**
* Server query-response for joining a colony.
*
* @param unit The <code>Unit</code> that will join.
* @param colony The <code>Colony</code> to join.
* @return True if the server interaction succeeded.
*/
public boolean joinColony(Unit unit, Colony colony) {
return askHandling(new JoinColonyMessage(colony, unit),
null, null);
}
/**
* Server query-response for learning the skill taught at a settlement.
*
* @param unit The <code>Unit</code> that is asking.
* @param direction The direction to a settlement to ask.
* @return True if the server interaction succeeded.
*/
public boolean learnSkill(Unit unit, Direction direction) {
return askHandling(new LearnSkillMessage(unit, direction),
null, null);
}
/**
* Server query-response for loading cargo.
*
* @param goods The <code>Goods</code> to load.
* @param carrier The <code>Unit</code> to load onto.
* @return True if the query-response succeeds.
*/
public boolean loadCargo(Goods goods, Unit carrier) {
return askHandling(new LoadCargoMessage(goods, carrier),
null, null);
}
/**
* Server query-response for looting. Handles both an initial query and
* the actual looting.
*
* @param winner The <code>Unit</code> that is looting.
* @param defenderId The id of the defender unit (it may have sunk).
* @param goods A list of <code>Goods</code>, if empty this is a query
* as to what is to be looted which is filled into the list,
* if non-empty, then the list of goods to loot.
* @return True if the server interaction succeeded.
*/
public boolean loot(Unit winner, String defenderId, List<Goods> goods) {
return askHandling(new LootCargoMessage(winner, defenderId, goods),
null, null);
}
/**
* Server query-response for establishing/denouncing a mission.
*
* @param unit The missionary <code>Unit</code>.
* @param direction The direction to a settlement to establish with.
* @param denounce True if this is a denouncement.
* @return True if the server interaction succeeded.
*/
public boolean missionary(Unit unit, Direction direction,
boolean denounce) {
return askHandling(new MissionaryMessage(unit, direction, denounce),
null, null);
}
/**
* Server query-response for moving a unit.
*
* @param unit The <code>Unit</code> to move.
* @param direction The direction to move in.
* @return True if the server interaction succeeded.
*/
public boolean move(Unit unit, Direction direction) {
return askHandling(new MoveMessage(unit, direction),
null, null);
}
/**
* Server query-response for moving to across the high seas.
*
* @param unit The <code>Unit</code> to move.
* @param destination The <code>Location</code> to move to.
* @return True if the server interaction succeeded.
*/
public boolean moveTo(Unit unit, Location destination) {
return askHandling(new MoveToMessage(unit, destination),
null, null);
}
/**
* Server query-response for asking for the nation summary of a player.
*
* @param player The <code>Player</code> to summarize.
* @return A summary of that nation, or null on error.
*/
public NationSummary getNationSummary(Player player) {
GetNationSummaryMessage message = new GetNationSummaryMessage(player);
Element reply = askExpecting(message,
GetNationSummaryMessage.getXMLElementTagName(), null);
if (reply == null) return null;
return new GetNationSummaryMessage(reply).getNationSummary();
}
/**
* Server query-response for naming a new land.
*
* @param unit The <code>Unit</code> that has come ashore.
* @param name The new land name.
* @param welcomer A welcoming native player with whom to make a treaty.
* @param accept True if the treaty was accepted.
* @return True if the server interaction succeeded.
*/
public boolean newLandName(Unit unit, String name, Player welcomer,
boolean accept) {
return askHandling(new NewLandNameMessage(unit, name, welcomer, -1,
accept),
null, null);
}
/**
* Server query-response for naming a new region.
*
* @param region The <code>Region</code> that is being discovered.
* @param tile The <code>Tile</code> where the region is discovered.
* @param name The new region name.
* @return True if the server interaction succeeded.
*/
public boolean newRegionName(Region region, Tile tile, String name) {
return askHandling(new NewRegionNameMessage(region, tile, name),
null, null);
}
/**
* Server query-response to get the transaction session for a trade.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @return An array of booleans for the buy/sell/gift status,
* or null if the server interaction failed.
*/
public boolean[] openTransactionSession(Unit unit, Settlement settlement) {
HashMap<String, String> results
= loadMap("canBuy", "canSell", "canGift");
if (askExpecting(new GetTransactionMessage(unit, settlement),
null, results) == null
|| results.get("canBuy") == null
|| results.get("canSell") == null
|| results.get("canGift") == null) return null;
return new boolean[] {
Boolean.parseBoolean(results.get("canBuy")),
Boolean.parseBoolean(results.get("canSell")),
Boolean.parseBoolean(results.get("canGift"))
};
}
/**
* Server query-response for tax paying arrears.
*
* @param type The <code>GoodsType</code> to pay the arrears for.
* @return True if the server interaction succeeded.
*/
public boolean payArrears(GoodsType type) {
return askHandling(new PayArrearsMessage(type),
null, null);
}
/**
* Server query-response for paying for a building.
*
* @param colony The <code>Colony</code> that is building.
* @return True if the server interaction succeeded.
*/
public boolean payForBuilding(Colony colony) {
return askHandling(new PayForBuildingMessage(colony),
null, null);
}
/**
* Server query-response for renaming an object.
*
* @param object A <code>FreeColGameObject</code> to rename.
* @param name The name to apply.
* @return True if the renaming succeeded.
*/
public boolean rename(FreeColGameObject object, String name) {
return askHandling(new RenameMessage(object, name),
null, null);
}
/**
* Retires the player from the game.
*
* @return True if the player achieved a new high score.
*/
public boolean retire() {
return askHandling(new TrivialMessage("retire"),
null, null);
}
/**
* Server query-response for putting a unit outside a colony.
*
* @param unit The <code>Unit</code> to put out.
* @return True if the server interaction succeeded.
*/
public boolean putOutsideColony(Unit unit) {
return askHandling(new PutOutsideColonyMessage(unit),
null, null);
}
/**
* Server query-response for speaking with a native chief.
*
* @param unit The <code>Unit</code> that is speaking.
* @param direction The direction to a settlement to ask.
* @return A string describing the result,
* or null if the server interaction failed.
*/
public String scoutSpeak(Unit unit, Direction direction) {
HashMap<String, String> results = loadMap("result");
return (askHandling(new ScoutIndianSettlementMessage(unit, direction),
null, results)) ? results.get("result")
: null;
}
/**
* Server query-response for selling goods in Europe.
*
* @param goods The <code>Goods</code> to sell.
* @param carrier The <code>Unit</code> in Europe with the goods.
* @return True if the server interaction succeeded.
*/
public boolean sellGoods(Goods goods, Unit carrier) {
return askHandling(new SellGoodsMessage(goods, carrier),
null, null);
}
/**
* Server query-response to ask the natives if a sale is acceptable.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @param goods The <code>Goods</code> to trade.
* @param gold The proposed price (including query on negative).
* @return The selling price for the goods.
*/
public int sellProposition(Unit unit, Settlement settlement,
Goods goods, int gold) {
HashMap<String, String> results = loadMap("gold");
if (askHandling(new SellPropositionMessage(unit, settlement,
goods, gold), null, results)) {
try {
return Integer.parseInt(results.get("gold"));
} catch (NumberFormatException e) {}
}
return NetworkConstants.NO_TRADE;
}
/**
* Server query-response to sell the given goods to the natives.
*
* @param unit The <code>Unit</code> that is trading.
* @param settlement The <code>Settlement</code> that is trading.
* @param goods The <code>Goods</code> to sell.
* @param gold The agreed price.
* @return True if the server interaction succeeded.
*/
public boolean sellToSettlement(Unit unit, Settlement settlement,
Goods goods, int gold) {
return askHandling(new SellMessage(unit, settlement, goods, gold),
null, null);
}
/**
* Server query-response for changing a build queue.
*
* @param colony the Colony
* @param buildQueue the new values for the build queue
* @return True if the server interaction succeeded.
*/
public boolean setBuildQueue(Colony colony,
List<BuildableType> buildQueue) {
return askHandling(new SetBuildQueueMessage(colony, buildQueue),
null, null);
}
/**
* Server query-response to set the destination of the given unit.
*
* @param unit The <code>Unit</code> to direct.
* @param destination The destination <code>Location</code>.
* @return True if the server interaction succeeded.
* @see Unit#setDestination(Location)
*/
public boolean setDestination(Unit unit, Location destination) {
return askHandling(new SetDestinationMessage(unit, destination),
null, null);
}
/**
* Server query-response for setting goods levels.
*
* @param colony The <code>Colony</code> where the levels are set.
* @param data The <code>ExportData</code> setting.
* @return True if the server interaction succeeded.
*/
public boolean setGoodsLevels(Colony colony, ExportData data) {
return askHandling(new SetGoodsLevelsMessage(colony, data),
null, null);
}
/**
* Server query-response for setting the trade routes.
*
* @param routes A list of trade routes to update.
* @return True if the server interaction succeeded.
*/
public boolean setTradeRoutes(List<TradeRoute> routes) {
return askHandling(new SetTradeRoutesMessage(routes),
null, null);
}
/**
* Server query-response for spying on a colony.
*
* @param unit The <code>Unit</code> that is spying.
* @param direction The <code>Direction</code> of a colony to spy on.
* @return True if the client/server interaction succeeded.
*/
public boolean spy(Unit unit, Direction direction) {
return askHandling(new SpySettlementMessage(unit, direction),
null, null);
}
/**
* Server query-response for starting to skip turns.
*
* @return True if the server interaction succeeded.
*/
public boolean startSkipping() {
return send(new TrivialMessage("endTurn"));
}
/**
* Server query-response for training a unit in Europe.
*
* @param type The <code>UnitType</code> to train.
* @return True if the server interaction succeeded.
*/
public boolean trainUnitInEurope(UnitType type) {
return askHandling(new TrainUnitInEuropeMessage(type),
null, null);
}
/**
* Server query-response for unloading cargo.
*
* @param goods The <code>Goods</code> to unload.
* @return True if the query-response succeeds.
*/
public boolean unloadCargo(Goods goods) {
return askHandling(new UnloadCargoMessage(goods),
null, null);
}
/**
* Server query-response for updating the current stop.
*
* @param unit The <code>Unit</code> whose stop is to be updated.
* @return True if the query-response succeeds.
*/
public boolean updateCurrentStop(Unit unit) {
return askHandling(new UpdateCurrentStopMessage(unit),
null, null);
}
/**
* Server query-response for asking for updating the trade route.
*
* @param route The trade route to update.
* @return True if the server interaction succeeded.
*/
public boolean updateTradeRoute(TradeRoute route) {
return askHandling(new UpdateTradeRouteMessage(route),
null, null);
}
/**
* Server query-response for changing a work location.
*
* @param unit The <code>Unit</code> to change the workLocation of.
* @param workLocation The <code>WorkLocation</code> to change to.
* @return True if the server interaction succeeded.
*/
public boolean work(Unit unit, WorkLocation workLocation) {
return askHandling(new WorkMessage(unit, workLocation),
null, null);
}
}