public Range(Match match, Tile origin, Ability ability) 
	{
		this.match = match;
		this.origin = origin;
		this.ability = ability;
		
		validTargetPaths = new ConcurrentHashMap<Tile, ArrayList<Tile>>();
		invalidTargets = new ArrayList<Tile>();
		blockingTiles = new ArrayList<Tile>();
		
		//Movement ranges can "wrap" around obstacles (since units don't have to walk in a straight line)
		//but ability ranges must have a "line of fire" to be used.
		if (ability == null) {
			algorithmWrap(origin.getUnit().getCurrentMove(), 1);
		} else {
			algorithmLine(ability.getProperty(Ability.Property.RANGE), ability.getProperty(Ability.Property.MINIMUM_RANGE));
			//The range finding methods get passed ranges rather than being expected to infer them from ability,
			//so that whether the range is "wrappable" remains independent from whether it's an ability range.
			//This way, "wrappable" abilities are possible.
		}
	}