protected SailResult sail(final int direction)
	{
		final Room thisRoom=CMLib.map().roomLocation(this);
		if(thisRoom != null)
		{
			directionFacing = getDirectionFacing(direction);
			int[] tacticalCoords = null;
			if(amInTacticalMode())
			{
				int x=0;
				try
				{
					while((x>=0)&&(this.coordinates!=null)&&(tacticalCoords==null))
					{
						x=this.coordinates.indexOfFirst(this);
						Pair<Item,int[]> pair = (x>=0) ? this.coordinates.get(x) : null;
						if(pair == null)
							break;
						else
						if(pair.first != this)
							x=this.coordinates.indexOfFirst(this);
						else
							tacticalCoords = pair.second;
					}
				}
				catch(Exception e)
				{
				}
			}
			if(tacticalCoords != null)
			{
				final MOB mob = CMClass.getFactoryMOB(name(),phyStats().level(),thisRoom);
				try
				{
					mob.setRiding(this);
					mob.basePhyStats().setDisposition(mob.basePhyStats().disposition()|PhyStats.IS_SWIMMING);
					mob.phyStats().setDisposition(mob.phyStats().disposition()|PhyStats.IS_SWIMMING);
					if(directionFacing == direction)
					{
						final String directionName = CMLib.directions().getDirectionName(direction);
						final int[] newCoords = Directions.adjustXYByDirections(tacticalCoords[0], tacticalCoords[1], direction);
						final CMMsg maneuverMsg=CMClass.getMsg(mob,thisRoom,null,CMMsg.MSG_ADVANCE,newCoords[0]+","+newCoords[1],CMMsg.MSG_ADVANCE,directionName,
																CMMsg.MSG_ADVANCE,L("<S-NAME> maneuver(s) @x1.",directionName));
						if(thisRoom.okMessage(mob, maneuverMsg))
						{
							thisRoom.send(mob, maneuverMsg);
							final int oldDistance = this.getLowestTacticalDistanceFromThis();
							tacticalCoords[0] = newCoords[0];
							tacticalCoords[1] = newCoords[1];
							final int newDistance = this.getLowestTacticalDistanceFromThis();
							ticksSinceMove=0;
							if((newDistance <= oldDistance)||(newDistance < thisRoom.maxRange()))
								return SailResult.CONTINUE;
						}
						else
							return SailResult.REPEAT;
						// else we get to make a real Sailing move!
					}
					else
					{
						final int gradualDirection=Directions.getGradualDirectionCode(directionFacing, direction);
						final String directionName = CMLib.directions().getDirectionName(gradualDirection);
						final String finalDirectionName = CMLib.directions().getDirectionName(direction);
						final CMMsg maneuverMsg=CMClass.getMsg(mob,thisRoom,null,CMMsg.MSG_ADVANCE,directionName,CMMsg.MSG_ADVANCE,finalDirectionName,
								CMMsg.MSG_ADVANCE,L("<S-NAME> change(s) course, turning @x1.",directionName));
						if(thisRoom.okMessage(mob, maneuverMsg))
						{
							thisRoom.send(mob, maneuverMsg);
							directionFacing = CMLib.directions().getStrictDirectionCode(maneuverMsg.sourceMessage());
						}
						if(direction != directionFacing)
							return SailResult.REPEAT;
						else
							return SailResult.CONTINUE;
					}
				}
				finally
				{
					mob.destroy();
				}
			}
			else
			{
				directionFacing = direction;
			}
			this.clearTacticalMode();
			final Room destRoom=thisRoom.getRoomInDir(direction);
			final Exit exit=thisRoom.getExitInDir(direction);
			if((destRoom!=null)&&(exit!=null))
			{
				if((!CMLib.flags().isDeepWaterySurfaceRoom(destRoom))
				&&(destRoom.domainType()!=Room.DOMAIN_OUTDOORS_SEAPORT))
				{
					announceToShip(L("As there is no where to sail @x1, <S-NAME> meanders along the waves.",CMLib.directions().getInDirectionName(direction)));
					courseDirections.clear();
					return SailResult.CANCEL;
				}
				final int oppositeDirectionFacing=Directions.getOpDirectionCode(direction);
				final String directionName=CMLib.directions().getDirectionName(direction);
				final String otherDirectionName=CMLib.directions().getDirectionName(oppositeDirectionFacing);
				final Exit opExit=thisRoom.getExitInDir(oppositeDirectionFacing);
				final MOB mob = CMClass.getFactoryMOB(name(),phyStats().level(),CMLib.map().roomLocation(this));
				mob.setRiding(this);
				mob.basePhyStats().setDisposition(mob.basePhyStats().disposition()|PhyStats.IS_SWIMMING);
				mob.phyStats().setDisposition(mob.phyStats().disposition()|PhyStats.IS_SWIMMING);
				try
				{
					final boolean isSneaking = CMLib.flags().isSneaking(this);
					final String sailEnterStr = isSneaking ? null : L("<S-NAME> sail(s) in from @x1.",otherDirectionName);
					final String sailAwayStr = isSneaking ? null : L("<S-NAME> sail(s) @x1.",directionName);
					final CMMsg enterMsg=CMClass.getMsg(mob,destRoom,exit,CMMsg.MSG_ENTER,null,CMMsg.MSG_ENTER,null,CMMsg.MSG_ENTER,sailEnterStr);
					final CMMsg leaveMsg=CMClass.getMsg(mob,thisRoom,opExit,CMMsg.MSG_LEAVE,null,CMMsg.MSG_LEAVE,null,CMMsg.MSG_LEAVE,sailAwayStr);
					if((exit.okMessage(mob,enterMsg))
					&&(leaveMsg.target().okMessage(mob,leaveMsg))
					&&((opExit==null)||(opExit.okMessage(mob,leaveMsg)))
					&&(enterMsg.target().okMessage(mob,enterMsg)))
					{
						exit.executeMsg(mob,enterMsg);
						thisRoom.sendOthers(mob, leaveMsg);
						this.unDock(false);
						destRoom.moveItemTo(this);
						ticksSinceMove=0;
						this.dockHere(destRoom);
						//this.sendAreaMessage(leaveMsg, true);
						if(opExit!=null)
							opExit.executeMsg(mob,leaveMsg);
						destRoom.send(mob, enterMsg);
						haveEveryoneLookOverBow();
						return SailResult.CONTINUE;
					}
					else
					{
						announceToShip(L("<S-NAME> can not seem to travel @x1.",CMLib.directions().getInDirectionName(direction)));
						courseDirections.clear();
						return SailResult.CANCEL;
					}
				}
				finally
				{
					mob.destroy();
				}
			}
			else
			{
				announceToShip(L("As there is no where to sail @x1, <S-NAME> meanders along the waves.",CMLib.directions().getInDirectionName(direction)));
				courseDirections.clear();
				return SailResult.CANCEL;
			}
		}
		return SailResult.CANCEL;
	}